Skip to content

Commit 30d28ad

Browse files
committed
[ElementAt] improve ElementAt
1 parent b03d0d0 commit 30d28ad

File tree

4 files changed

+68
-42
lines changed

4 files changed

+68
-42
lines changed

Documents/BenchmarksResults/ElementAtOnArray.md

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -7,16 +7,17 @@
77
``` ini
88

99
BenchmarkDotNet=v0.12.0, OS=Windows 10.0.19041
10-
Intel Core i7-7700 CPU 3.60GHz (Kaby Lake), 1 CPU, 8 logical and 4 physical cores
11-
.NET Core SDK=3.1.403
10+
Intel Core i7-8750H CPU 2.20GHz (Coffee Lake), 1 CPU, 12 logical and 6 physical cores
11+
.NET Core SDK=5.0.100-preview.7.20366.6
1212
[Host] : .NET Core 3.1.9 (CoreCLR 4.700.20.47201, CoreFX 4.700.20.47203), X64 RyuJIT
1313
DefaultJob : .NET Core 3.1.9 (CoreCLR 4.700.20.47201, CoreFX 4.700.20.47203), X64 RyuJIT
1414

1515

1616
```
17-
| Method | Mean | Error | StdDev | Ratio | Gen 0 | Gen 1 | Gen 2 | Allocated |
18-
|-------------------- |----------:|----------:|----------:|------:|-------:|------:|------:|----------:|
19-
| Linq | 26.625 ns | 0.2574 ns | 0.2408 ns | 1.00 | - | - | - | - |
20-
| EnumerableLinq | 26.390 ns | 0.4745 ns | 0.3962 ns | 0.99 | - | - | - | - |
21-
| StructLinq | 13.418 ns | 0.2688 ns | 0.2761 ns | 0.51 | 0.0076 | - | - | 32 B |
22-
| StructLinqZeroAlloc | 4.414 ns | 0.0438 ns | 0.0366 ns | 0.17 | - | - | - | - |
17+
| Method | Mean | Error | StdDev | Ratio | RatioSD | Gen 0 | Gen 1 | Gen 2 | Allocated |
18+
|---------------------------------- |-----------:|----------:|----------:|------:|--------:|-------:|------:|------:|----------:|
19+
| Linq | 24.122 ns | 0.3471 ns | 0.3077 ns | 1.00 | 0.00 | - | - | - | - |
20+
| EnumerableLinq | 24.105 ns | 0.2221 ns | 0.2077 ns | 1.00 | 0.01 | - | - | - | - |
21+
| StructLinq | 12.324 ns | 0.2485 ns | 0.2203 ns | 0.51 | 0.01 | 0.0068 | - | - | 32 B |
22+
| StructLinqZeroAlloc | 4.066 ns | 0.0562 ns | 0.0525 ns | 0.17 | 0.00 | - | - | - | - |
23+
| StructLinqZeroAllocWithEnumerator | 700.381 ns | 2.7479 ns | 2.5704 ns | 29.04 | 0.42 | - | - | - | - |

src/StructLinq.Benchmark/ElementAtOnArray.cs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
using System.Collections.Generic;
22
using System.Linq;
33
using BenchmarkDotNet.Attributes;
4+
using StructLinq.Array;
45

56
namespace StructLinq.Benchmark
67
{
@@ -29,5 +30,9 @@ public ElementAtOnArray()
2930
[Benchmark]
3031
public int StructLinqZeroAlloc() => array.ToStructEnumerable().ElementAt(Count / 2, x=>x);
3132

33+
[Benchmark]
34+
public int StructLinqZeroAllocWithEnumerator() => array.ToStructEnumerable().ElementAt(Count / 2, x => (IStructEnumerable<int, ArrayStructEnumerator<int>>)x);
35+
36+
3237
}
3338
}

src/StructLinq/ElementAt/RefStructEnumerable.ElementAt.cs

Lines changed: 27 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -15,35 +15,45 @@ private static bool RefTryInnerElementAt<T, TEnumerator>(ref TEnumerator enumera
1515
if (index < 0)
1616
return false;
1717

18-
int i = 0;
19-
while (enumerator.MoveNext()&& i<=index)
18+
while (true)
2019
{
21-
ref var current = ref enumerator.Current;
22-
elementAt = current;
23-
i++;
20+
if (!enumerator.MoveNext())
21+
{
22+
enumerator.Dispose();
23+
return false;
24+
}
25+
if (index == 0)
26+
{
27+
elementAt = ref enumerator.Current;
28+
enumerator.Dispose();
29+
return true;
30+
}
31+
index--;
2432
}
25-
enumerator.Dispose();
26-
return i == index + 1;
2733
}
2834

2935
[MethodImpl(MethodImplOptions.AggressiveInlining)]
3036
private static T RefInnerElementAt<T, TEnumerator>(ref TEnumerator enumerator, int index)
3137
where TEnumerator : struct, IRefStructEnumerator<T>
3238
{
39+
3340
if (index < 0)
3441
throw new ArgumentOutOfRangeException("index");
35-
int i = 0;
36-
T result = default;
37-
while (enumerator.MoveNext()&& i<=index)
42+
while (true)
3843
{
39-
ref var current = ref enumerator.Current;
40-
result = current;
41-
i++;
44+
if (!enumerator.MoveNext())
45+
{
46+
enumerator.Dispose();
47+
throw new ArgumentOutOfRangeException("index");
48+
}
49+
if (index == 0)
50+
{
51+
ref var innerElementAt = ref enumerator.Current;
52+
enumerator.Dispose();
53+
return innerElementAt;
54+
}
55+
index--;
4256
}
43-
enumerator.Dispose();
44-
if (i == index + 1)
45-
return result;
46-
throw new ArgumentOutOfRangeException("index");
4757
}
4858

4959
[MethodImpl(MethodImplOptions.AggressiveInlining)]

src/StructLinq/ElementAt/StructEnumerable.ElementAt.cs

Lines changed: 27 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -14,15 +14,22 @@ private static bool TryInnerElementAt<T, TEnumerator>(ref TEnumerator enumerator
1414
{
1515
if (index < 0)
1616
return false;
17-
int i = 0;
18-
while (enumerator.MoveNext()&& i<=index)
17+
18+
while (true)
1919
{
20-
var current = enumerator.Current;
21-
elementAt = current;
22-
i++;
20+
if (!enumerator.MoveNext())
21+
{
22+
enumerator.Dispose();
23+
return false;
24+
}
25+
if (index == 0)
26+
{
27+
elementAt = enumerator.Current;
28+
enumerator.Dispose();
29+
return true;
30+
}
31+
index--;
2332
}
24-
enumerator.Dispose();
25-
return i == index + 1;
2633
}
2734

2835
[MethodImpl(MethodImplOptions.AggressiveInlining)]
@@ -31,18 +38,21 @@ private static T InnerElementAt<T, TEnumerator>(ref TEnumerator enumerator, int
3138
{
3239
if (index < 0)
3340
throw new ArgumentOutOfRangeException("index");
34-
int i = 0;
35-
T result = default;
36-
while (enumerator.MoveNext()&& i<=index)
41+
while (true)
3742
{
38-
var current = enumerator.Current;
39-
result = current;
40-
i++;
43+
if (!enumerator.MoveNext())
44+
{
45+
enumerator.Dispose();
46+
throw new ArgumentOutOfRangeException("index");
47+
}
48+
if (index == 0)
49+
{
50+
var innerElementAt = enumerator.Current;
51+
enumerator.Dispose();
52+
return innerElementAt;
53+
}
54+
index--;
4155
}
42-
enumerator.Dispose();
43-
if (i == index+1)
44-
return result;
45-
throw new ArgumentOutOfRangeException("index");
4656
}
4757

4858
[MethodImpl(MethodImplOptions.AggressiveInlining)]

0 commit comments

Comments
 (0)