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
2 changes: 1 addition & 1 deletion Build/Common.Benchmark.props
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<Project>
<PropertyGroup Label="Framework">
<DefaultTargetFrameworks>netcoreapp3.1;net48;net50</DefaultTargetFrameworks>
<DefaultTargetFrameworks>net50;netcoreapp3.1;net48</DefaultTargetFrameworks>
</PropertyGroup>

<PropertyGroup>
Expand Down
22 changes: 22 additions & 0 deletions Documents/BenchmarksResults/SelectOnArray.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
## SelectOnArray

### Source
[SelectOnArray.cs](../../src/StructLinq.Benchmark/SelectOnArray.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 | Code Size | Gen 0 | Gen 1 | Gen 2 | Allocated |
|----------------------- |---------:|---------:|---------:|------:|--------:|----------:|------:|------:|------:|----------:|
| Handmaded | 11.27 μs | 0.011 μs | 0.009 μs | 1.00 | 0.00 | 53 B | - | - | - | - |
| LINQ | 61.02 μs | 0.356 μs | 0.298 μs | 5.41 | 0.03 | 1147 B | - | - | - | 48 B |
| StructLINQ | 20.85 μs | 0.098 μs | 0.087 μs | 1.85 | 0.01 | 627 B | - | - | - | - |
| StructLINQWithFunction | 17.78 μs | 0.076 μs | 0.063 μs | 1.58 | 0.01 | 593 B | - | - | - | - |
22 changes: 22 additions & 0 deletions Documents/BenchmarksResults/SelectOnArrayOfClass.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
## SelectOnArrayOfClass

### Source
[SelectOnArrayOfClass.cs](../../src/StructLinq.Benchmark/SelectOnArrayOfClass.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 | 6.726 μs | 0.1298 μs | 0.1494 μs | 1.00 | 0.00 | - | - | - | - | 48 B |
| LINQ | 76.179 μs | 1.4866 μs | 1.6523 μs | 11.32 | 0.33 | - | - | - | 48 B | 48 B |
| StructLINQ | 27.129 μs | 0.4152 μs | 0.3467 μs | 4.04 | 0.10 | - | - | - | - | 48 B |
| StructLINQWithFunction | 17.780 μs | 0.2278 μs | 0.2020 μs | 2.64 | 0.07 | - | - | - | - | 48 B |
2 changes: 2 additions & 0 deletions src/StructLinq.Benchmark/ArrayOfClassSum.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using System.Linq;
using System.Runtime.CompilerServices;
using BenchmarkDotNet.Attributes;

namespace StructLinq.Benchmark
Expand Down Expand Up @@ -49,6 +50,7 @@ public Container(int element)

internal struct ContainerSelect : IFunction<Container, int>
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public readonly int Eval(Container element)
{
return element.Element;
Expand Down
67 changes: 67 additions & 0 deletions src/StructLinq.Benchmark/SelectOnArray.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
using System.Linq;
using BenchmarkDotNet.Attributes;

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

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

[Benchmark(Baseline = true)]
public double Handmaded()
{
var sum = 0.0;
foreach (var i in array)
{
var x = i * 2.0;
sum += x;
}

return sum;
}

[Benchmark]
public double LINQ()
{
var sum = 0.0;
foreach (var i in array.Select(x=> x * 2.0))
{
sum += i;
}

return sum;
}

[Benchmark]
public double StructLINQ()
{
var sum = 0.0;
foreach (var i in array.ToStructEnumerable().Select(x=> x * 2.0, x=>x))
{
sum += i;
}

return sum;
}

[Benchmark]
public double StructLINQWithFunction()
{
var sum = 0.0;
var func = new MultFunction();
foreach (var i in array.ToStructEnumerable().Select(ref func, x=>x, x=> x))
{
sum += i;
}

return sum;
}
}
}
66 changes: 66 additions & 0 deletions src/StructLinq.Benchmark/SelectOnArrayOfClass.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
using System.Linq;
using BenchmarkDotNet.Attributes;

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

public SelectOnArrayOfClass()
{
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)
{
sum += i.Element;
}

return sum;
}

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

return sum;
}

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

return sum;
}

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

return sum;
}
}
}
37 changes: 37 additions & 0 deletions src/StructLinq.Tests/SelectFuncTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
using System;
using System.Linq;
using StructLinq.Range;
using StructLinq.Select;
using Xunit;

namespace StructLinq.Tests
{
public class SelectFuncTests : AbstractEnumerableTests<double,
SelectEnumerable<int, double, RangeEnumerable, RangeEnumerator>,
SelectEnumerator<int, double, RangeEnumerator>>
{
[Fact]
public void DelegateTest()
{
Func<int, double> selector = x => x * 2.0;
var sys = Enumerable
.Range(-50, 100)
.Select(selector)
.ToArray();
var structEnum = StructEnumerable
.Range(-50, 100)
.Select(selector)
.ToEnumerable()
.ToArray();
Assert.Equal(sys, structEnum);
}

protected override SelectEnumerable<int, double, RangeEnumerable, RangeEnumerator> Build(int size)
{
var selectEnumerable =
StructEnumerable.Range(-1, size).Select(x=> x * 2.0, x=> x);
return selectEnumerable;
}

}
}
26 changes: 15 additions & 11 deletions src/StructLinq.Tests/SelectTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,9 @@

namespace StructLinq.Tests
{
public class SelectTests : AbstractEnumerableTests<int,
SelectEnumerable<int, int, IStructCollection<int, RangeEnumerator>, RangeEnumerator, StructFunction<int, int>>,
SelectEnumerator<int, int, RangeEnumerator, StructFunction<int, int>>>
public class SelectTests : AbstractEnumerableTests<double,
SelectEnumerable<int, double, RangeEnumerable, RangeEnumerator, MultFunction>,
SelectEnumerator<int, double, RangeEnumerator, MultFunction>>
{
[Fact]
public void DelegateTest()
Expand All @@ -18,26 +18,30 @@ public void DelegateTest()
.Range(-50, 100)
.Select(selector)
.ToArray();
var func = new MultFunction();
var structEnum = StructEnumerable
.Range(-50, 100)
.Select(selector)
.Select(ref func, x=>x, x=> x)
.ToEnumerable()
.ToArray();
Assert.Equal(sys, structEnum);
}

protected override SelectEnumerable<int, int, IStructCollection<int, RangeEnumerator>, RangeEnumerator, StructFunction<int, int>> Build(int size)
protected override SelectEnumerable<int, double, RangeEnumerable, RangeEnumerator, MultFunction> Build(int size)
{
SelectEnumerable<int, int, IStructCollection<int, RangeEnumerator>, RangeEnumerator, StructFunction<int, int>> selectEnumerable = StructEnumerable.Range(-1, size).Select(x => x * 2);
var func = new MultFunction();
SelectEnumerable<int, double, RangeEnumerable, RangeEnumerator, MultFunction> selectEnumerable =
StructEnumerable.Range(-1, size).Select(ref func, x=>x, x => x);
return selectEnumerable;
}

struct MultFunction : IFunction<int, double>
}

public struct MultFunction : IFunction<int, double>
{
public double Eval(int element)
{
public double Eval(int element)
{
return element * 2.0;
}
return element * 2.0;
}
}
}
61 changes: 0 additions & 61 deletions src/StructLinq.Tests/ZeroAllocSelectTests.cs

This file was deleted.

33 changes: 32 additions & 1 deletion src/StructLinq/Select/SelectEnumerable.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.Select
{
Expand Down Expand Up @@ -31,6 +32,36 @@ internal TEnumerable Inner
get => inner;
}
}

public struct SelectEnumerable<TIn, TOut, TEnumerable, TEnumerator> : IStructEnumerable<TOut, SelectEnumerator<TIn, TOut, TEnumerator>>
where TEnumerator : struct, IStructEnumerator<TIn>
where TEnumerable : IStructEnumerable<TIn, TEnumerator>
{
#region private fields
private Func<TIn, TOut> function;
private TEnumerable inner;
#endregion

public SelectEnumerable(Func<TIn, TOut> function, ref TEnumerable inner)
{
this.function = function;
this.inner = inner;
}

[MethodImpl(MethodImplOptions.AggressiveInlining)]
public SelectEnumerator<TIn, TOut, TEnumerator> GetEnumerator()
{
var typedEnumerator = inner.GetEnumerator();
return new SelectEnumerator<TIn, TOut, TEnumerator>(function, ref typedEnumerator);
}

internal TEnumerable Inner
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get => inner;
}
}

}


Loading