https://github.com/reegeek/StructLinq
Implementation in C# of LINQ concept with struct
https://github.com/reegeek/StructLinq
allocation-free csharp fast linq struct
Last synced: 10 months ago
JSON representation
Implementation in C# of LINQ concept with struct
- Host: GitHub
- URL: https://github.com/reegeek/StructLinq
- Owner: reegeek
- License: mit
- Created: 2019-02-08T10:35:44.000Z (about 7 years ago)
- Default Branch: master
- Last Pushed: 2024-01-19T04:30:11.000Z (about 2 years ago)
- Last Synced: 2025-04-13T04:09:20.997Z (11 months ago)
- Topics: allocation-free, csharp, fast, linq, struct
- Language: C#
- Homepage:
- Size: 986 KB
- Stars: 302
- Watchers: 8
- Forks: 11
- Open Issues: 33
-
Metadata Files:
- Readme: README.md
- License: LICENSE
Awesome Lists containing this project
README
# StructLinq
[](https://github.com/reegeek/StructLinq/releases)
[](https://www.nuget.org/packages/StructLinq/) 
[](https://dev.azure.com/reegeek/StrucLinq/_build/latest?definitionId=2&branchName=master)
[](https://github.com/reegeek/StructLinq/actions?query=workflow%3Acontinuous)
[](https://github.com/reegeek/StructLinq/stargazers) [](https://github.com/reegeek/StructLinq/network) [](https://github.com/reegeek/StructLinq/blob/master/LICENSE)
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](#Installation)
- [Usage](#Usage)
- [Performances](#Performances)
- [Features](#Features)
- [BCL bindings](#BCL)
- [Transformers](#Transformers)
- [Converters](#Converters)
- [LINQ Extensions](#LINQ-Extensions)
- [Other Extensions](#Other-Extensions)
- [IRefStructEnumerable](#IRefStructEnumerable)
---
## Installation
This library is distributed via [NuGet](https://www.nuget.org/).
To install [`StructLinq`](https://www.nuget.org/packages/StructLinq/) :
```
PM> Install-Package StructLinq
```
## Usage
`StructLinq` use massively generic concept and struct "specialization".
```csharp
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](Documents/BenchmarksResults).
For example following linq sequence:
```csharp
list
.Where(x => (x & 1) == 0)
.Select(x => x * 2)
.Sum();
```
can be replace by:
```csharp
list
.ToStructEnumerable()
.Where(x => (x & 1) == 0)
.Select(x => x * 2)
.Sum();
```
or if you want zero allocation by:
```csharp
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:
```csharp
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](src/StructLinq.Benchmark/ListWhereSelectSum.cs) results are:
``` ini
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[]`
- `List` (in [`Struct.Linq.BCL`](https://www.nuget.org/packages/StructLinq.BCL/))
- `Dictionary` (in [`Struct.Linq.BCL`](https://www.nuget.org/packages/StructLinq.BCL/))
- `Hashset` (in [`Struct.Linq.BCL`](https://www.nuget.org/packages/StructLinq.BCL/))
- `ImmutableArray` (in [`Struct.Linq.BCL`](https://www.nuget.org/packages/StructLinq.BCL/))
### Converters
Following converters are available for :
- `ToArray`
- `ToList` (in [`Struct.Linq.BCL`](https://www.nuget.org/packages/StructLinq.BCL/))
- `ToEnumerable`
### LINQ Extensions
Following extensions are available for :
- `Aggregate`
- `All`
- `Any`
- `Concat`
- `Contains`
- `Count`
- `Distinct`([zero allocation](Documents/BenchmarksResults/Distinct.md))
- `ElementAt`
- `ElementAtOrDefault`
- `Empty`
- `Except`([zero allocation](Documents/BenchmarksResults/Except.md))
- `First`
- `FirstOrDefault`
- `Intersect`([zero allocation](Documents/BenchmarksResults/Intersect.md))
- `Last`
- `LastOrDefault`
- `Max`
- `Min`
- `OrderBy`([zero allocation](Documents/BenchmarksResults/OrderByArrayOfInt.md))
- `OrderByDescending`
- `Range`
- `Repeat`
- `Reverse`([zero allocation](Documents/BenchmarksResults/Reverse.md))
- `Select`
- `SelectMany`
- `Skip`
- `SkipWhile`
- `Sum`
- `Take`
- `TakeWhile`
- `Union`([zero allocation](Documents/BenchmarksResults/Union.md))
- `Where`
### Other Extensions
- `LongCount`
- `UIntCount`
- `Order`
- `TryFirst`
## IRefStructEnumerable
```csharp
public interface IRefStructEnumerable
where TEnumerator : struct, IRefStructEnumerator
{
TEnumerator GetEnumerator();
}
public interface IRefStructEnumerator
{
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` (in [`Struct.Linq.BCL`](https://www.nuget.org/packages/StructLinq.BCL/))
### Converters
Following converters are available for :
- `ToArray`
- `ToList` (in [`Struct.Linq.BCL`](https://www.nuget.org/packages/StructLinq.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`