Skip to content

Commit 522c519

Browse files
committed
[SkipeWhile] add SkipeWhle extension.
1 parent 2768cb8 commit 522c519

File tree

13 files changed

+475
-0
lines changed

13 files changed

+475
-0
lines changed
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
## SkipWhileOnArray
2+
3+
### Source
4+
[SkipWhileOnArray.cs](../../src/StructLinq.Benchmark/SkipWhileOnArray.cs)
5+
6+
### Results:
7+
``` ini
8+
9+
BenchmarkDotNet=v0.12.1, OS=Windows 10.0.19042
10+
Intel Core i7-7700 CPU 3.60GHz (Kaby Lake), 1 CPU, 8 logical and 4 physical cores
11+
.NET Core SDK=5.0.202
12+
[Host] : .NET Core 5.0.5 (CoreCLR 5.0.521.16609, CoreFX 5.0.521.16609), X64 RyuJIT
13+
DefaultJob : .NET Core 5.0.5 (CoreCLR 5.0.521.16609, CoreFX 5.0.521.16609), X64 RyuJIT
14+
15+
16+
```
17+
| Method | Mean | Error | StdDev | Median | Ratio | RatioSD | Gen 0 | Gen 1 | Gen 2 | Allocated | Code Size |
18+
|---------------------------- |---------:|---------:|---------:|---------:|------:|--------:|------:|------:|------:|----------:|----------:|
19+
| Linq | 90.15 μs | 1.982 μs | 5.458 μs | 87.57 μs | 1.00 | 0.00 | - | - | - | 104 B | 561 B |
20+
| StructLinq | 23.56 μs | 0.216 μs | 0.192 μs | 23.59 μs | 0.25 | 0.02 | - | - | - | 32 B | 555 B |
21+
| StructLinqZeroAlloc | 24.11 μs | 0.202 μs | 0.179 μs | 24.08 μs | 0.26 | 0.02 | - | - | - | - | 714 B |
22+
| StructLinqFunctionZeroAlloc | 16.58 μs | 0.170 μs | 0.150 μs | 16.55 μs | 0.18 | 0.01 | - | - | - | - | 636 B |

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -158,6 +158,7 @@ Following extensions are available for :
158158
- `Reverse`([zero allocation](Documents/BenchmarksResults/Reverse.md))
159159
- `Select`
160160
- `Skip`
161+
- `SkipWhile`
161162
- `Sum`
162163
- `Take`
163164
- `Union`([zero allocation](Documents/BenchmarksResults/Union.md))

StructLinq.sln

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,11 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "StructLinq.BCL.x64.Tests",
3838
EndProject
3939
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "StructLinq.BCL.x86.Tests", "src\StructLinq.BCL.Tests\StructLinq.BCL.x86.Tests.csproj", "{806CB7C5-190E-4160-B576-F9F6CF8316EC}"
4040
EndProject
41+
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{7AD83C4D-5F99-404D-82BA-E362C1E2C34A}"
42+
ProjectSection(SolutionItems) = preProject
43+
README.md = README.md
44+
EndProjectSection
45+
EndProject
4146
Global
4247
GlobalSection(SolutionConfigurationPlatforms) = preSolution
4348
Debug|Any CPU = Debug|Any CPU
Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
using System.Linq;
2+
using System.Runtime.CompilerServices;
3+
using BenchmarkDotNet.Attributes;
4+
5+
namespace StructLinq.Benchmark
6+
{
7+
[MemoryDiagnoser, DisassemblyDiagnoser(4)]
8+
public class SkipWhileOnArray
9+
{
10+
private const int Count = 10_000;
11+
public int[] array;
12+
13+
public SkipWhileOnArray()
14+
{
15+
array = Enumerable.Range(0, Count).ToArray();
16+
}
17+
18+
[Benchmark(Baseline = true)]
19+
public int Linq()
20+
{
21+
var sum = 0;
22+
foreach (var i in array.SkipWhile(x=> x < 5000))
23+
{
24+
sum += i;
25+
}
26+
27+
return sum;
28+
}
29+
30+
[Benchmark]
31+
public int StructLinq()
32+
{
33+
var sum = 0;
34+
foreach (var i in array.ToStructEnumerable().SkipWhile(x=> x < 5000))
35+
{
36+
sum += i;
37+
}
38+
39+
return sum;
40+
}
41+
42+
[Benchmark]
43+
public int StructLinqZeroAlloc()
44+
{
45+
var sum = 0;
46+
foreach (var i in array.ToStructEnumerable().SkipWhile(x=> x < 5000, x=>x))
47+
{
48+
sum += i;
49+
}
50+
51+
return sum;
52+
}
53+
54+
[Benchmark]
55+
public int StructLinqFunctionZeroAlloc()
56+
{
57+
var sum = 0;
58+
var predicate = new Predicate();
59+
foreach (var i in array.ToStructEnumerable().SkipWhile(predicate, x=>x))
60+
{
61+
sum += i;
62+
}
63+
64+
return sum;
65+
}
66+
67+
private struct Predicate : IFunction<int, bool>
68+
{
69+
[MethodImpl(MethodImplOptions.AggressiveInlining)]
70+
public bool Eval(int element)
71+
{
72+
return element < 5000;
73+
}
74+
}
75+
76+
}
77+
}
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
using System.Linq;
2+
using StructLinq.Array;
3+
using StructLinq.SkipWhile;
4+
using Xunit;
5+
6+
namespace StructLinq.Tests
7+
{
8+
public partial class SkipWhileTests
9+
{
10+
public class RefSkipWhileTests : AbstractRefEnumerableTests<int,
11+
RefSkipWhileEnumerable<int, StructInFunction<int, bool>, ArrayRefEnumerable<int>, ArrayRefStructEnumerator<int>>,
12+
RefSkipWhileEnumerator<int, StructInFunction<int, bool>, ArrayRefStructEnumerator<int>>>
13+
{
14+
15+
protected override RefSkipWhileEnumerable<int, StructInFunction<int, bool>, ArrayRefEnumerable<int>, ArrayRefStructEnumerator<int>> Build(int size)
16+
{
17+
var skipEnumerable = StructEnumerable.Range(-1, size).ToArray().ToRefStructEnumerable().SkipWhile((in int _) => false, x=>x);
18+
return skipEnumerable;
19+
}
20+
21+
[Theory]
22+
[InlineData(0, 10)]
23+
[InlineData(5, 3)]
24+
[InlineData(10, 5)]
25+
[InlineData(10, 15)]
26+
public void ShouldBeTheSameAsSystem(int max, int limit)
27+
{
28+
var expected = Enumerable.Range(0, max).ToArray().SkipWhile(x => x < limit).ToArray();
29+
var value = Enumerable.Range(0, max).ToArray().ToRefStructEnumerable().SkipWhile((in int x) => x < limit).ToArray();
30+
31+
Assert.Equal(expected, value);
32+
}
33+
34+
[Theory]
35+
[InlineData(0, 10)]
36+
[InlineData(5, 3)]
37+
[InlineData(10, 5)]
38+
[InlineData(10, 15)]
39+
public void ShouldBeTheSameAsSystemViaEnumerable(int max, int limit)
40+
{
41+
var expected = Enumerable.Range(0, max).ToArray().SkipWhile(x => x < limit).ToArray();
42+
var value = Enumerable.Range(0, max).ToArray().ToRefStructEnumerable().SkipWhile((in int x) => x < limit).ToEnumerable().ToArray();
43+
44+
Assert.Equal(expected, value);
45+
}
46+
47+
}
48+
}
49+
}
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
using System.Linq;
2+
using StructLinq.Range;
3+
using StructLinq.SkipWhile;
4+
using Xunit;
5+
6+
namespace StructLinq.Tests
7+
{
8+
public partial class SkipWhileTests : AbstractEnumerableTests<int,
9+
SkipWhileEnumerable<int, StructFunction<int, bool>, RangeEnumerable, RangeEnumerator>,
10+
SkipWhileEnumerator<int, StructFunction<int, bool>, RangeEnumerator>>
11+
{
12+
13+
protected override SkipWhileEnumerable<int, StructFunction<int, bool>, RangeEnumerable, RangeEnumerator> Build(int size)
14+
{
15+
var skipEnumerable = StructEnumerable.Range(-1, size).SkipWhile(x => false, x => x);
16+
return skipEnumerable;
17+
}
18+
19+
[Theory]
20+
[InlineData(0, 10)]
21+
[InlineData(10, 5)]
22+
[InlineData(10, 15)]
23+
public void ShouldBeTheSameAsSystem(int max, int limit)
24+
{
25+
var expected = Enumerable.Range(0, max).ToArray().SkipWhile(x => x < limit).ToArray();
26+
var value = Enumerable.Range(0, max).ToArray().ToStructEnumerable().SkipWhile(x => x < limit).ToArray();
27+
28+
Assert.Equal(expected, value);
29+
}
30+
31+
[Theory]
32+
[InlineData(0, 10)]
33+
[InlineData(10, 5)]
34+
[InlineData(10, 15)]
35+
public void ShouldBeTheSameAsSystemViaEnumerable(int max, int limit)
36+
{
37+
var expected = Enumerable.Range(0, max).ToArray().SkipWhile(x => x < limit).ToArray();
38+
var value = Enumerable.Range(0, max).ToArray().ToStructEnumerable().SkipWhile(x => x < limit).ToEnumerable().ToArray();
39+
40+
Assert.Equal(expected, value);
41+
}
42+
}
43+
}

src/StructLinq/Skip/StructEnumerable.Skip.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
using System.Runtime.CompilerServices;
33
using StructLinq.Skip;
44

5+
// ReSharper disable once CheckNamespace
56
namespace StructLinq
67
{
78
public static partial class StructEnumerable
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
using System.Runtime.CompilerServices;
2+
3+
namespace StructLinq.SkipWhile
4+
{
5+
public readonly struct RefSkipWhileEnumerable<T, TFunction, TEnumerable, TEnumerator> : IRefStructEnumerable<T, RefSkipWhileEnumerator<T, TFunction, TEnumerator>>
6+
where TFunction : struct, IInFunction<T, bool>
7+
where TEnumerator : struct, IRefStructEnumerator<T>
8+
where TEnumerable : IRefStructEnumerable<T, TEnumerator>
9+
{
10+
private readonly TEnumerable enumerable;
11+
private readonly TFunction predicate;
12+
13+
public RefSkipWhileEnumerable(TEnumerable enumerable, TFunction predicate)
14+
{
15+
this.enumerable = enumerable;
16+
this.predicate = predicate;
17+
}
18+
19+
[MethodImpl(MethodImplOptions.AggressiveInlining)]
20+
public RefSkipWhileEnumerator<T, TFunction, TEnumerator> GetEnumerator()
21+
{
22+
return new(predicate, enumerable.GetEnumerator());
23+
}
24+
}
25+
}
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
using System.Runtime.CompilerServices;
2+
3+
namespace StructLinq.SkipWhile
4+
{
5+
public struct RefSkipWhileEnumerator<T, TFunction, TEnumerator> : IRefStructEnumerator<T>
6+
where TFunction : struct, IInFunction<T, bool>
7+
where TEnumerator : struct, IRefStructEnumerator<T>
8+
9+
{
10+
private bool skipDone;
11+
private TFunction predicate;
12+
private TEnumerator enumerator;
13+
14+
public RefSkipWhileEnumerator(TFunction predicate, TEnumerator enumerator)
15+
{
16+
skipDone = false;
17+
this.predicate = predicate;
18+
this.enumerator = enumerator;
19+
}
20+
21+
[MethodImpl(MethodImplOptions.AggressiveInlining)]
22+
public void Dispose()
23+
{
24+
enumerator.Dispose();
25+
}
26+
27+
[MethodImpl(MethodImplOptions.AggressiveInlining)]
28+
public bool MoveNext()
29+
{
30+
if (skipDone)
31+
return enumerator.MoveNext();
32+
33+
while (enumerator.MoveNext())
34+
{
35+
ref var current = ref enumerator.Current;
36+
if (predicate.Eval(in current))
37+
continue;
38+
skipDone = true;
39+
return true;
40+
}
41+
return false;
42+
}
43+
44+
[MethodImpl(MethodImplOptions.AggressiveInlining)]
45+
public void Reset()
46+
{
47+
enumerator.Reset();
48+
}
49+
50+
public ref T Current
51+
{
52+
[MethodImpl(MethodImplOptions.AggressiveInlining)]
53+
get => ref enumerator.Current;
54+
}
55+
}
56+
}
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+

2+
using System;
3+
using System.Runtime.CompilerServices;
4+
using StructLinq.SkipWhile;
5+
6+
// ReSharper disable once CheckNamespace
7+
namespace StructLinq
8+
{
9+
public static partial class StructEnumerable
10+
{
11+
[MethodImpl(MethodImplOptions.AggressiveInlining)]
12+
public static RefSkipWhileEnumerable<T, TFunction, TEnumerable, TEnumerator> SkipWhile<T, TFunction, TEnumerable, TEnumerator>(this TEnumerable enumerable, TFunction predicate,
13+
Func<TEnumerable, IRefStructEnumerable<T, TEnumerator>> _)
14+
where TFunction : struct, IInFunction<T, bool>
15+
where TEnumerator : struct, IRefStructEnumerator<T>
16+
where TEnumerable : IRefStructEnumerable<T, TEnumerator>
17+
{
18+
return new(enumerable, predicate);
19+
}
20+
21+
[MethodImpl(MethodImplOptions.AggressiveInlining)]
22+
public static RefSkipWhileEnumerable<T, StructInFunction<T, bool>, TEnumerable, TEnumerator> SkipWhile<T, TEnumerable, TEnumerator>(this TEnumerable enumerable, InFunc<T, bool> predicate,
23+
Func<TEnumerable, IRefStructEnumerable<T, TEnumerator>> _)
24+
where TEnumerator : struct, IRefStructEnumerator<T>
25+
where TEnumerable : IRefStructEnumerable<T, TEnumerator>
26+
{
27+
return new(enumerable, predicate.ToStruct());
28+
}
29+
30+
[MethodImpl(MethodImplOptions.AggressiveInlining)]
31+
public static RefSkipWhileEnumerable<T, StructInFunction<T, bool>, IRefStructEnumerable<T, TEnumerator>, TEnumerator> SkipWhile<T, TEnumerator>(this IRefStructEnumerable<T, TEnumerator> enumerable, InFunc<T, bool> predicate)
32+
where TEnumerator : struct, IRefStructEnumerator<T>
33+
{
34+
return new(enumerable, predicate.ToStruct());
35+
}
36+
37+
}
38+
}

0 commit comments

Comments
 (0)