Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 22 additions & 0 deletions Documents/BenchmarksResults/WhereOnArray.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
## WhereOnArray

### Source
[WhereOnArray.cs](../../src/StructLinq.Benchmark/WhereOnArray.cs)

### Results:
``` ini

BenchmarkDotNet=v0.12.1, OS=Windows 10.0.19042
Intel Core i7-7700 CPU 3.60GHz (Kaby Lake), 1 CPU, 8 logical and 4 physical cores
.NET Core SDK=5.0.101
[Host] : .NET Core 5.0.1 (CoreCLR 5.0.120.57516, CoreFX 5.0.120.57516), X64 RyuJIT
DefaultJob : .NET Core 5.0.1 (CoreCLR 5.0.120.57516, CoreFX 5.0.120.57516), X64 RyuJIT


```
| Method | Mean | Error | StdDev | Median | Ratio | RatioSD | Code Size | Gen 0 | Gen 1 | Gen 2 | Allocated |
|----------------------- |----------:|----------:|----------:|----------:|------:|--------:|----------:|------:|------:|------:|----------:|
| Handmaded | 8.131 μs | 0.0262 μs | 0.0218 μs | 8.137 μs | 1.00 | 0.00 | 58 B | - | - | - | - |
| LINQ | 46.088 μs | 0.8944 μs | 1.3388 μs | 45.395 μs | 5.82 | 0.15 | 896 B | - | - | - | 48 B |
| StructLINQ | 28.075 μs | 0.0999 μs | 0.0934 μs | 28.084 μs | 3.45 | 0.01 | 632 B | - | - | - | - |
| StructLINQWithFunction | 16.881 μs | 0.1049 μs | 0.0981 μs | 16.905 μs | 2.08 | 0.01 | 495 B | - | - | - | - |
22 changes: 22 additions & 0 deletions Documents/BenchmarksResults/WhereOnArrayOfClass.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
## WhereOnArrayOfClass

### Source
[WhereOnArrayOfClass.cs](../../src/StructLinq.Benchmark/WhereOnArrayOfClass.cs)

### Results:
``` ini

BenchmarkDotNet=v0.12.1, OS=Windows 10.0.19042
Intel Core i7-7700 CPU 3.60GHz (Kaby Lake), 1 CPU, 8 logical and 4 physical cores
.NET Core SDK=5.0.101
[Host] : .NET Core 5.0.1 (CoreCLR 5.0.120.57516, CoreFX 5.0.120.57516), X64 RyuJIT
DefaultJob : .NET Core 5.0.1 (CoreCLR 5.0.120.57516, CoreFX 5.0.120.57516), X64 RyuJIT


```
| Method | Mean | Error | StdDev | Ratio | RatioSD | Gen 0 | Gen 1 | Gen 2 | Allocated | Code Size |
|----------------------- |---------:|---------:|---------:|------:|--------:|------:|------:|------:|----------:|----------:|
| Handmaded | 12.79 μs | 0.025 μs | 0.021 μs | 1.00 | 0.00 | - | - | - | - | 62 B |
| LINQ | 66.50 μs | 1.298 μs | 1.903 μs | 5.24 | 0.15 | - | - | - | 48 B | 48 B |
| StructLINQ | 44.21 μs | 0.834 μs | 0.856 μs | 3.47 | 0.07 | - | - | - | - | 48 B |
| StructLINQWithFunction | 19.87 μs | 0.114 μs | 0.106 μs | 1.55 | 0.01 | - | - | - | - | 494 B |
77 changes: 77 additions & 0 deletions src/StructLinq.Benchmark/WhereOnArray.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
using System.Linq;
using System.Runtime.CompilerServices;
using BenchmarkDotNet.Attributes;

namespace StructLinq.Benchmark
{
[MemoryDiagnoser, DisassemblyDiagnoser(4)]
public class WhereOnArray
{
private int[] array;
private const int Count = 10000;

public WhereOnArray()
{
array = Enumerable.Range(0, Count).ToArray();
}

[Benchmark(Baseline = true)]
public int Handmaded()
{
var sum = 0;
foreach (var i in array)
{
if (i % 2 == 0)
sum += i;
}

return sum;
}

[Benchmark]
public int LINQ()
{
var sum = 0;
foreach (var i in array.Where(x=> x % 2 == 0))
{
sum += i;
}

return sum;
}

[Benchmark]
public int StructLINQ()
{
var sum = 0;
foreach (var i in array.ToStructEnumerable().Where(x=> x % 2 == 0, x=>x))
{
sum += i;
}

return sum;
}

[Benchmark]
public int StructLINQWithFunction()
{
var sum = 0;
var func = new WhereFunc();
foreach (var i in array.ToStructEnumerable().Where(ref func, x=>x))
{
sum += i;
}

return sum;
}

private readonly struct WhereFunc : IFunction<int, bool>
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public bool Eval(int element)
{
return element % 2 == 0;
}
}
}
}
77 changes: 77 additions & 0 deletions src/StructLinq.Benchmark/WhereOnArrayOfClass.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
using System.Linq;
using System.Runtime.CompilerServices;
using BenchmarkDotNet.Attributes;

namespace StructLinq.Benchmark
{
[MemoryDiagnoser, DisassemblyDiagnoser(4)]
public class WhereOnArrayOfClass
{
private Container[] array;
private const int Count = 10000;

public WhereOnArrayOfClass()
{
array = Enumerable.Range(0, Count).Select(x=> new Container(x)).ToArray();
}

[Benchmark(Baseline = true)]
public int Handmaded()
{
var sum = 0;
foreach (var i in array)
{
if (i.Element % 2 == 0)
sum += i.Element;
}

return sum;
}

[Benchmark]
public int LINQ()
{
var sum = 0;
foreach (var i in array.Where(x=> x.Element % 2 == 0))
{
sum += i.Element;
}

return sum;
}

[Benchmark]
public int StructLINQ()
{
var sum = 0;
foreach (var i in array.ToStructEnumerable().Where(x=> x.Element % 2 == 0, x=>x))
{
sum += i.Element;
}

return sum;
}

[Benchmark]
public int StructLINQWithFunction()
{
var sum = 0;
var func = new WhereFunc();
foreach (var i in array.ToStructEnumerable().Where(ref func, x=>x))
{
sum += i.Element;
}

return sum;
}

private readonly struct WhereFunc : IFunction<Container, bool>
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public bool Eval(Container element)
{
return element.Element % 2 == 0;
}
}
}
}
4 changes: 2 additions & 2 deletions src/StructLinq.Tests/ReverseTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,12 @@ namespace StructLinq.Tests
{
public class ReverseTests : AbstractEnumerableTests<
int,
ReverseEnumerable<int, WhereEnumerable<int, IStructEnumerable<int, RangeEnumerator>, RangeEnumerator, StructFunction<int, bool>>, WhereEnumerator<int, RangeEnumerator, StructFunction<int, bool>>>,
ReverseEnumerable<int, WhereEnumerable<int, IStructEnumerable<int, RangeEnumerator>, RangeEnumerator>, WhereEnumerator<int, RangeEnumerator>>,
ReverseEnumerator<int>>
{

protected override
ReverseEnumerable<int, WhereEnumerable<int, IStructEnumerable<int, RangeEnumerator>, RangeEnumerator, StructFunction<int, bool>>, WhereEnumerator<int, RangeEnumerator, StructFunction<int, bool>>> Build(int size)
ReverseEnumerable<int, WhereEnumerable<int, IStructEnumerable<int, RangeEnumerator>, RangeEnumerator>, WhereEnumerator<int, RangeEnumerator>> Build(int size)
{
return StructEnumerable.Range(0, size).Where(x => true).Reverse(x => x);
}
Expand Down
6 changes: 3 additions & 3 deletions src/StructLinq.Tests/SkipTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,11 @@
namespace StructLinq.Tests
{
public class SkipTests : AbstractEnumerableTests<int,
SkipEnumerable<int, WhereEnumerable<int, RangeEnumerable, RangeEnumerator, StructFunction<int, bool>>, WhereEnumerator<int, RangeEnumerator, StructFunction<int, bool>>>,
SkipEnumerator<int, WhereEnumerator<int, RangeEnumerator, StructFunction<int, bool>>>>
SkipEnumerable<int, WhereEnumerable<int, RangeEnumerable, RangeEnumerator>, WhereEnumerator<int, RangeEnumerator>>,
SkipEnumerator<int, WhereEnumerator<int, RangeEnumerator>>>
{

protected override SkipEnumerable<int, WhereEnumerable<int, RangeEnumerable, RangeEnumerator, StructFunction<int, bool>>, WhereEnumerator<int, RangeEnumerator, StructFunction<int, bool>>> Build(int size)
protected override SkipEnumerable<int, WhereEnumerable<int, RangeEnumerable, RangeEnumerator>, WhereEnumerator<int, RangeEnumerator>> Build(int size)
{
var skipEnumerable = StructEnumerable.Range(-1, size + 5).Where(x=>true, x=>x).Skip(5, x=> x);
return skipEnumerable;
Expand Down
6 changes: 3 additions & 3 deletions src/StructLinq.Tests/TakeTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,10 @@
namespace StructLinq.Tests
{
public class TakeTests : AbstractEnumerableTests<int,
TakeEnumerable<int, WhereEnumerable<int, RangeEnumerable, RangeEnumerator, StructFunction<int, bool>>, WhereEnumerator<int, RangeEnumerator, StructFunction<int, bool>>>,
TakeEnumerator<int, WhereEnumerator<int, RangeEnumerator, StructFunction<int, bool>>>>
TakeEnumerable<int, WhereEnumerable<int, RangeEnumerable, RangeEnumerator>, WhereEnumerator<int, RangeEnumerator>>,
TakeEnumerator<int, WhereEnumerator<int, RangeEnumerator>>>
{
protected override TakeEnumerable<int, WhereEnumerable<int, RangeEnumerable, RangeEnumerator, StructFunction<int, bool>>, WhereEnumerator<int, RangeEnumerator, StructFunction<int, bool>>> Build(int size)
protected override TakeEnumerable<int, WhereEnumerable<int, RangeEnumerable, RangeEnumerator>, WhereEnumerator<int, RangeEnumerator>> Build(int size)
{
return StructEnumerable.Range(-1, size).Where(x=>true, x=>x).Take(size, x=> x);
}
Expand Down
6 changes: 3 additions & 3 deletions src/StructLinq.Tests/WhereTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,10 @@
namespace StructLinq.Tests
{
public class WhereTests : AbstractEnumerableTests<int,
WhereEnumerable<int, RangeEnumerable, RangeEnumerator, StructFunction<int, bool>>,
WhereEnumerator<int, RangeEnumerator, StructFunction<int, bool>>>
WhereEnumerable<int, RangeEnumerable, RangeEnumerator>,
WhereEnumerator<int, RangeEnumerator>>
{
protected override WhereEnumerable<int, RangeEnumerable, RangeEnumerator, StructFunction<int, bool>> Build(int size)
protected override WhereEnumerable<int, RangeEnumerable, RangeEnumerator> Build(int size)
{
var whereEnumerable = StructEnumerable.Range(-1, size).Where(x => x >= -1, x=>x);
return whereEnumerable;
Expand Down
10 changes: 4 additions & 6 deletions src/StructLinq/Where/StructEnumerable.Where.cs
Original file line number Diff line number Diff line change
Expand Up @@ -18,13 +18,12 @@ public static WhereEnumerable<T, TEnumerable, TEnumerator, TFunction> Where<T, T
}

[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static WhereEnumerable<T, TEnumerable, TEnumerator, StructFunction<T, bool>> Where<T, TEnumerable, TEnumerator>(this TEnumerable enumerable, Func<T, bool> predicate,
public static WhereEnumerable<T, TEnumerable, TEnumerator> Where<T, TEnumerable, TEnumerator>(this TEnumerable enumerable, Func<T, bool> predicate,
Func<TEnumerable, IStructEnumerable<T, TEnumerator>> _)
where TEnumerator : struct, IStructEnumerator<T>
where TEnumerable : struct, IStructEnumerable<T, TEnumerator>
{
var structPredicate = predicate.ToStruct();
return new WhereEnumerable<T, TEnumerable, TEnumerator, StructFunction<T, bool>>(ref structPredicate, ref enumerable);
return new WhereEnumerable<T, TEnumerable, TEnumerator>(predicate, ref enumerable);

}

Expand All @@ -50,11 +49,10 @@ public static RefWhereEnumerable<T, TEnumerable, TEnumerator, StructInFunction<T
}

[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static WhereEnumerable<T, IStructEnumerable<T, TEnumerator>, TEnumerator, StructFunction<T, bool>> Where<T, TEnumerator>(this IStructEnumerable<T, TEnumerator> enumerable, Func<T, bool> predicate)
public static WhereEnumerable<T, IStructEnumerable<T, TEnumerator>, TEnumerator> Where<T, TEnumerator>(this IStructEnumerable<T, TEnumerator> enumerable, Func<T, bool> predicate)
where TEnumerator : struct, IStructEnumerator<T>
{
var structPredicate = predicate.ToStruct();
return new WhereEnumerable<T, IStructEnumerable<T, TEnumerator>, TEnumerator, StructFunction<T, bool>>(ref structPredicate, ref enumerable);
return new WhereEnumerable<T, IStructEnumerable<T, TEnumerator>, TEnumerator>(predicate, ref enumerable);
}

[MethodImpl(MethodImplOptions.AggressiveInlining)]
Expand Down
23 changes: 22 additions & 1 deletion src/StructLinq/Where/WhereEnumerable.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using System.Runtime.CompilerServices;
using System;
using System.Runtime.CompilerServices;

namespace StructLinq.Where
{
Expand All @@ -22,4 +23,24 @@ public WhereEnumerator<TIn, TEnumerator, TFunction> GetEnumerator()
return new WhereEnumerator<TIn, TEnumerator, TFunction>(ref function, ref enumerator);
}
}

public struct WhereEnumerable<TIn, TEnumerable, TEnumerator> : IStructEnumerable<TIn, WhereEnumerator<TIn, TEnumerator>>
where TEnumerator : struct, IStructEnumerator<TIn>
where TEnumerable : IStructEnumerable<TIn, TEnumerator>
{
private Func<TIn, bool> function;
private TEnumerable inner;
public WhereEnumerable(Func<TIn, bool> function, ref TEnumerable inner)
{
this.function = function;
this.inner = inner;
}

[MethodImpl(MethodImplOptions.AggressiveInlining)]
public WhereEnumerator<TIn, TEnumerator> GetEnumerator()
{
var enumerator = inner.GetEnumerator();
return new WhereEnumerator<TIn, TEnumerator>(function, ref enumerator);
}
}
}
48 changes: 47 additions & 1 deletion src/StructLinq/Where/WhereEnumerator.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using System.Runtime.CompilerServices;
using System;
using System.Runtime.CompilerServices;

namespace StructLinq.Where
{
Expand Down Expand Up @@ -46,4 +47,49 @@ public void Dispose()
}

}

public struct WhereEnumerator<TIn, TEnumerator> : IStructEnumerator<TIn>
where TEnumerator : struct, IStructEnumerator<TIn>
{
#region private fields
private Func<TIn, bool> predicate;
private TEnumerator enumerator;
#endregion
public WhereEnumerator(Func<TIn, bool> predicate, ref TEnumerator enumerator)
{
this.predicate = predicate;
this.enumerator = enumerator;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public bool MoveNext()
{
while (enumerator.MoveNext())
{
var current = enumerator.Current;
if (!predicate(current))
continue;
return true;
}

return false;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void Reset()
{
enumerator.Reset();
}
public readonly TIn Current
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get => enumerator.Current;
}

[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void Dispose()
{
enumerator.Dispose();
}

}

}