Skip to content

Commit 0ab3c03

Browse files
committed
[Select] SelectEnumerable is now zero alloc.
1 parent b659a0d commit 0ab3c03

17 files changed

+98
-98
lines changed

src/StructLinq.Benchmark/ArrayClassSum.cs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -19,8 +19,8 @@ public ArrayClassSum()
1919
array = Enumerable.Range(0, Count).Select(x => new Container(x)).ToArray();
2020
var @select = new ContainerSelect();
2121
sysArray = array.Select(x => x.Element);
22-
convertArray = array.ToStructEnumerable().Select(x => x.Element);
23-
safeStructArray = array.ToStructEnumerable().Select(in select, Id<int>.Value);
22+
convertArray = array.ToStructEnumerable().Select(x => x.Element, x => x);
23+
safeStructArray = array.ToStructEnumerable().Select(ref select, x=>x, x => x);
2424
}
2525
[Benchmark]
2626
public int SysSum()
@@ -55,7 +55,7 @@ public Container(int element)
5555

5656
internal struct ContainerSelect : IFunction<Container, int>
5757
{
58-
public readonly int Eval(in Container element)
58+
public readonly int Eval(Container element)
5959
{
6060
return element.Element;
6161
}

src/StructLinq.Benchmark/ArrayReadonlyStructSum.cs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -19,8 +19,8 @@ public ArrayReadonlyStructSum()
1919
array = Enumerable.Range(0, Count).Select(x => ReadonlyStructContainer.Create(x)).ToArray();
2020
var @select = new ReadonlyStructContainerSelect();
2121
sysArray = array.Select(x => x.Element);
22-
convertArray = array.ToStructEnumerable().Select(x => x.Element);
23-
safeStructArray = array.ToStructEnumerable().Select(in select, Id<int>.Value);
22+
convertArray = array.ToStructEnumerable().Select(x => x.Element, x => x);
23+
safeStructArray = array.ToStructEnumerable().Select(ref select, x=>x, x => x);
2424
}
2525
[Benchmark]
2626
public int SysSum()
@@ -44,7 +44,7 @@ public int SysSum()
4444

4545
internal struct ReadonlyStructContainerSelect : IFunction<ReadonlyStructContainer, int>
4646
{
47-
public readonly int Eval(in ReadonlyStructContainer element)
47+
public readonly int Eval(ReadonlyStructContainer element)
4848
{
4949
return element.Element;
5050
}

src/StructLinq.Benchmark/ArraySealedClassSum.cs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -19,8 +19,8 @@ public ArraySealedClassSum()
1919
array = Enumerable.Range(0, Count).Select(x=> new SealedContainer(x)).ToArray();
2020
var @select = new SealedContainerSelect();
2121
sysArray = array.Select(x=> x.Element);
22-
convertArray = array.ToStructEnumerable().Select(x => x.Element);
23-
safeStructArray = array.ToStructEnumerable().Select(in select, Id<int>.Value);
22+
convertArray = array.ToStructEnumerable().Select(x => x.Element, x => x);
23+
safeStructArray = array.ToStructEnumerable().Select(ref select, x=>x, x => x);
2424
}
2525
[Benchmark]
2626
public int SysSum()
@@ -44,7 +44,7 @@ public int SysSum()
4444

4545
internal struct SealedContainerSelect : IFunction<SealedContainer, int>
4646
{
47-
public readonly int Eval(in SealedContainer element)
47+
public readonly int Eval(SealedContainer element)
4848
{
4949
return element.Element;
5050
}

src/StructLinq.Benchmark/ArrayStructSum.cs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -19,8 +19,8 @@ public ArrayStructSum()
1919
array = Enumerable.Range(0, Count).Select(x => StructContainer.Create(x)).ToArray();
2020
var @select = new StructContainerSelect();
2121
sysArray = array.Select(x => x.Element);
22-
convertArray = array.ToStructEnumerable().Select(x => x.Element);
23-
safeStructArray = array.ToStructEnumerable().Select(in select, Id<int>.Value);
22+
convertArray = array.ToStructEnumerable().Select(x => x.Element, x => x);
23+
safeStructArray = array.ToStructEnumerable().Select(ref select, x=>x, x => x);
2424
}
2525
[Benchmark]
2626
public int SysSum()
@@ -45,7 +45,7 @@ public int SysSum()
4545

4646
internal struct StructContainerSelect : IFunction<StructContainer, int>
4747
{
48-
public readonly int Eval(in StructContainer element)
48+
public readonly int Eval(StructContainer element)
4949
{
5050
return element.Element;
5151
}

src/StructLinq.Benchmark/ForEachOnArrayOfClassVsOfStruct.cs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -13,14 +13,14 @@ namespace StructLinq.Benchmark
1313
public class SumOnArrayOfClassVsOfStruct
1414
{
1515
private readonly ClassContainer[] sysRange;
16-
private readonly SelectEnumerable<StructContainer, int, ArrayStructEnumerator<StructContainer>, StructFunction<StructContainer, int>> arrayOfStructEnumerable;
17-
private readonly SelectEnumerable<ClassContainer, int, ArrayStructEnumerator<ClassContainer>, StructFunction<ClassContainer, int>> arrayOfClassEnumerable;
16+
private readonly SelectEnumerable<StructContainer, int, ArrayEnumerable<StructContainer>, ArrayStructEnumerator<StructContainer>, StructFunction<StructContainer, int>> arrayOfStructEnumerable;
17+
private readonly SelectEnumerable<ClassContainer, int, ArrayEnumerable<ClassContainer>, ArrayStructEnumerator<ClassContainer>, StructFunction<ClassContainer, int>> arrayOfClassEnumerable;
1818
private const int Count = 10000;
1919
public SumOnArrayOfClassVsOfStruct()
2020
{
2121
sysRange = Enumerable.Range(0, Count).Select(x=> new ClassContainer(x)).ToArray();
22-
arrayOfClassEnumerable = Enumerable.Range(0, Count).Select(x=> new ClassContainer(x)).ToArray().ToStructEnumerable().Select(x=> x.Index);
23-
arrayOfStructEnumerable = Enumerable.Range(0, Count).Select(x => new StructContainer(x)).ToArray().ToStructEnumerable().Select(x => x.Index);
22+
arrayOfClassEnumerable = Enumerable.Range(0, Count).Select(x=> new ClassContainer(x)).ToArray().ToStructEnumerable().Select(x=> x.Index, x => x);
23+
arrayOfStructEnumerable = Enumerable.Range(0, Count).Select(x => new StructContainer(x)).ToArray().ToStructEnumerable().Select(x => x.Index, x => x);
2424
}
2525

2626
[Benchmark(Baseline = true)]

src/StructLinq.Benchmark/RangeWhereSelectSum.cs

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -25,13 +25,13 @@ public RangeWhereSelectSum()
2525
var select = new SelectFunction();
2626
convertWithDelegate = Enumerable.Range(0, Count).ToStructEnumerable()
2727
.Where(x => (x & 1) == 0)
28-
.Select(x => x *2);
28+
.Select(x => x *2, x => x);
2929
convertWithStruct = Enumerable.Range(0, Count).ToStructEnumerable()
3030
.Where(in where)
31-
.Select(in select, Id<int>.Value);
31+
.Select(ref select, x=>x, x => x);
3232
structRange = StructEnumerable.Range(0, Count)
3333
.Where(in where)
34-
.Select(in select, Id<int>.Value);
34+
.Select(ref select, x=>x, x => x);
3535
}
3636
[Benchmark(Baseline = true)]
3737
public int SysSum()
@@ -62,15 +62,15 @@ public int SysSum()
6262

6363
struct WherePredicate : IFunction<int, bool>
6464
{
65-
public readonly bool Eval(in int element)
65+
public readonly bool Eval(int element)
6666
{
6767
return (element & 1) == 0;
6868
}
6969
}
7070

7171
struct SelectFunction : IFunction<int, int>
7272
{
73-
public readonly int Eval(in int element)
73+
public readonly int Eval(int element)
7474
{
7575
return element * 2;
7676
}

src/StructLinq.Benchmark/Select.cs

Lines changed: 41 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -1,71 +1,75 @@
1-
using System.Collections.Generic;
2-
using System.Linq;
1+
using System.Linq;
32
using BenchmarkDotNet.Attributes;
4-
using StructLinq.IEnumerable;
5-
using StructLinq.Range;
6-
using StructLinq.Select;
73

84
namespace StructLinq.Benchmark
95
{
10-
[MemoryDiagnoser]
6+
7+
//BenchmarkDotNet=v0.12.0, OS=Windows 10.0.18363
8+
//Intel Core i7-7700 CPU 3.60GHz (Kaby Lake), 1 CPU, 8 logical and 4 physical cores
9+
//.NET Core SDK=3.1.101
10+
//[Host] : .NET Core 3.1.1 (CoreCLR 4.700.19.60701, CoreFX 4.700.19.60801), X64 RyuJIT
11+
//DefaultJob : .NET Core 3.1.1 (CoreCLR 4.700.19.60701, CoreFX 4.700.19.60801), X64 RyuJIT
12+
13+
14+
//```
15+
//| Method | Mean | Error | StdDev | Ratio | RatioSD | Gen 0 | Gen 1 | Gen 2 | Allocated |
16+
//|--------------- |---------:|---------:|---------:|------:|--------:|------:|------:|------:|----------:|
17+
//| SysSelect | 66.87 us | 1.280 us | 1.524 us | 1.00 | 0.00 | - | - | - | 88 B |
18+
//| DelegateSelect | 30.33 us | 0.606 us | 0.744 us | 0.45 | 0.02 | - | - | - | - |
19+
//| StructSelect | 19.63 us | 0.213 us | 0.189 us | 0.30 | 0.01 | - | - | - | - |
20+
//| ConvertSelect | 69.85 us | 1.508 us | 1.411 us | 1.05 | 0.03 | - | - | - | 40 B |
21+
22+
[MemoryDiagnoser, DisassemblyDiagnoser(recursiveDepth: 4)]
1123
public class Select
1224
{
13-
private readonly IEnumerable<double> sysRange;
14-
private readonly IStructEnumerable<double, SelectEnumerator<int, double, RangeEnumerator, StructFunction<int, double>>> delegateRange;
15-
private readonly IStructEnumerable<double, SelectEnumerator<int, double, GenericEnumerator<int>, StructFunction<int, double>>> convertRange;
16-
private readonly CountAction<double>[] countActions = new CountAction<double>[1];
1725
private const int Count = 10000;
18-
private readonly IStructEnumerable<double, SelectEnumerator<int, double, RangeEnumerator, MultFunction>> structRange;
1926
public Select()
2027
{
21-
sysRange = Enumerable.Range(0, Count).Select(x=> x * 2.0);
22-
delegateRange = StructEnumerable.Range(0, Count).Select(x=> x * 2.0);
23-
convertRange = Enumerable.Range(0, Count).ToStructEnumerable().Select(x=> x * 2.0);
24-
var multFunction = new MultFunction();
25-
structRange = StructEnumerable.Range(0, Count).Select(in multFunction, Id<double>.Value);
2628
}
2729

2830
[Benchmark(Baseline = true)]
29-
public int SysSelect()
31+
public double SysSelect()
3032
{
31-
int count = 0;
32-
foreach (var i in sysRange)
33+
double sum = 0;
34+
var enumerable = Enumerable.Range(0, Count).Select(x=> x * 2.0);
35+
foreach (var i in enumerable)
3336
{
34-
count++;
37+
sum+= i;
3538
}
36-
return count;
39+
return sum;
3740
}
3841

3942
[Benchmark]
40-
public int DelegateSelect()
43+
public double DelegateSelect()
4144
{
42-
int count = 0;
43-
delegateRange.ForEach(i => count++);
44-
return count;
45+
return StructEnumerable
46+
.Range(0, Count)
47+
.Select(x => x * 2.0, x => x)
48+
.Sum(x=>x);
4549
}
4650

4751
[Benchmark]
48-
public int StructSelect()
52+
public double StructSelect()
4953
{
50-
ref CountAction<double> countAction = ref countActions[0];
51-
countAction.Count = 0;
52-
structRange.ForEach(ref countAction);
53-
return countAction.Count;
54+
var multFunction = new MultFunction();
55+
return StructEnumerable.Range(0, Count)
56+
.Select(ref multFunction, x=>x, x => x)
57+
.Sum(x=> x);
5458
}
5559

5660
[Benchmark]
57-
public int ConvertSelect()
61+
public double ConvertSelect()
5862
{
59-
ref CountAction<double> countAction = ref countActions[0];
60-
countAction.Count = 0;
61-
convertRange.ForEach(ref countAction);
62-
return countAction.Count;
63+
return Enumerable.Range(0, Count)
64+
.ToStructEnumerable()
65+
.Select(x=> x * 2.0, x => x)
66+
.Sum(x=>x);
6367
}
6468
}
6569

66-
struct MultFunction : IFunction<int, double>
70+
readonly struct MultFunction : IFunction<int, double>
6771
{
68-
public readonly double Eval(in int element)
72+
public double Eval(int element)
6973
{
7074
return element * 2.0;
7175
}

src/StructLinq.Benchmark/Where.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,7 @@ public int ConvertSelect()
6868

6969
struct WhereFunc : IFunction<int, bool>
7070
{
71-
public readonly bool Eval(in int element)
71+
public readonly bool Eval(int element)
7272
{
7373
return element > 0;
7474
}

src/StructLinq.Tests/SelectTests.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ public void StructTest()
3333
var fct = new MultFunction();
3434
var structEnum = StructEnumerable
3535
.Range(-50, 100)
36-
.Select(in fct, Id<double>.Value)
36+
.Select(ref fct, x=>x, x => x)
3737
.ToArray();
3838
Assert.Equal(sys, structEnum);
3939

@@ -46,7 +46,7 @@ protected override IEnumerable<int> Build(int size)
4646

4747
struct MultFunction : IFunction<int, double>
4848
{
49-
public double Eval(in int element)
49+
public double Eval(int element)
5050
{
5151
return element * 2.0;
5252
}

src/StructLinq.Tests/WhereTests.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ public void StructTest()
4646

4747
struct WhereFunc : IFunction<int, bool>
4848
{
49-
public bool Eval(in int element)
49+
public bool Eval(int element)
5050
{
5151
return element > 0;
5252
}

0 commit comments

Comments
 (0)