StructLinq
StructLinq copied to clipboard
Implementation in C# of LINQ concept with struct
StructLinq
Implementation in C# of LINQ concept with struct to reduce drastically memory allocation and improve performance.
Introduce IRefStructEnumerable
to improve performance when element are fat struct.
- Installation
- Usage
- Performances
-
Features
- BCL bindings
- Transformers
- Converters
- LINQ Extensions
- Other Extensions
- IRefStructEnumerable
Installation
This library is distributed via NuGet.
To install StructLinq
:
PM> Install-Package StructLinq
Usage
StructLinq
use massively generic concept and struct "specialization".
using StructLinq;
int[] array = new [] {1, 2, 3, 4, 5};
int result = array
.ToStructEnumerable()
.Where(x => (x & 1) == 0, x=>x)
.Select(x => x *2, x => x)
.Sum();
x=>x
is used to avoid boxing (and allocation) and to help generic type parameters inference.
You can also improve performance by using struct for Where predicate and select function.
Performances
All benchmark results are in here. For example following linq sequence:
list
.Where(x => (x & 1) == 0)
.Select(x => x * 2)
.Sum();
can be replace by:
list
.ToStructEnumerable()
.Where(x => (x & 1) == 0)
.Select(x => x * 2)
.Sum();
or if you want zero allocation by:
list
.ToStructEnumerable()
.Where(x => (x & 1) == 0, x=>x)
.Select(x => x * 2, x=>x)
.Sum(x=>x);
or if you want zero allocation and better performance by:
var where = new WherePredicate();
var select = new SelectFunction();
list
.ToStructEnumerable()
.Where(ref @where, x => x)
.Select(ref @select, x => x, x => x)
.Sum(x => x);
Benchmark results are:
BenchmarkDotNet=v0.12.1, OS=Windows 10.0.19042
Intel Core i7-8750H CPU 2.20GHz (Coffee Lake), 1 CPU, 12 logical and 6 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 | Gen 0 | Gen 1 | Gen 2 | Allocated |
---|---|---|---|---|---|---|---|---|
LINQ | 65.116 μs | 0.6153 μs | 0.5756 μs | 1.00 | - | - | - | 152 B |
StructLinqWithDelegate | 26.146 μs | 0.2402 μs | 0.2247 μs | 0.40 | - | - | - | 96 B |
StructLinqWithDelegateZeroAlloc | 27.854 μs | 0.0938 μs | 0.0783 μs | 0.43 | - | - | - | - |
StructLinqZeroAlloc | 6.872 μs | 0.0155 μs | 0.0137 μs | 0.11 | - | - | - | - |
StructLinq
is significatively faster than default LINQ
implementation.
Features
Duck typing with foreach
is available with zero allocation for IStructEnumerable
.
BCL
Following class have a StructLinq
extension method for IStructEnumerable
:
-
IEnumerable<T>
-
T[]
-
List<T>
(inStruct.Linq.BCL
) -
Dictionary<TKey, TValue>
(inStruct.Linq.BCL
) -
Hashset<T>
(inStruct.Linq.BCL
) -
ImmutableArray<T>
(inStruct.Linq.BCL
)
Converters
Following converters are available for :
-
ToArray
-
ToList
(inStruct.Linq.BCL
) -
ToEnumerable
LINQ Extensions
Following extensions are available for :
-
Aggregate
-
All
-
Any
-
Concat
-
Contains
-
Count
-
Distinct
(zero allocation) -
ElementAt
-
ElementAtOrDefault
-
Empty
-
Except
(zero allocation) -
First
-
FirstOrDefault
-
Intersect
(zero allocation) -
Last
-
LastOrDefault
-
Max
-
Min
-
OrderBy
(zero allocation) -
OrderByDescending
-
Range
-
Repeat
-
Reverse
(zero allocation) -
Select
-
SelectMany
-
Skip
-
SkipWhile
-
Sum
-
Take
-
TakeWhile
-
Union
(zero allocation) -
Where
Other Extensions
-
LongCount
-
UIntCount
-
Order
-
TryFirst
IRefStructEnumerable
public interface IRefStructEnumerable<out T, out TEnumerator>
where TEnumerator : struct, IRefStructEnumerator<T>
{
TEnumerator GetEnumerator();
}
public interface IRefStructEnumerator<T>
{
bool MoveNext();
void Reset();
ref T Current { get; }
}
ref Current
allows to avoid copy. I should be very useful when T
is a fat struct.
Duck typing with foreach
with ref
is available with zero allocation for IRefStructEnumerable
.
BCL
Following class have a StructLinq
extension method for IRefStructEnumerable
:
-
T[]
-
List<T>
(inStruct.Linq.BCL
)
Converters
Following converters are available for :
-
ToArray
-
ToList
(inStruct.Linq.BCL
) -
ToEnumerable
LINQ Extensions
Following extensions are available for :
-
All
-
Any
-
Concat
-
Contains
-
Count
-
Distinct
-
ElementAt
-
ElementAtOrDefault
-
Except
-
First
-
FirstOrDefault
-
Intersect
-
Last
-
Select
-
Skip
-
SkipWhile
-
Sum
-
Take
-
TakeWhile
-
Union
-
Where
Other Extensions
-
LongCount
-
UIntCount
-
TryFirst