Skip to content

Instantly share code, notes, and snippets.

@Mart-Bogdan
Created June 15, 2025 11:26
Show Gist options
  • Save Mart-Bogdan/77a90216de92963fc3ca625ff62885d9 to your computer and use it in GitHub Desktop.
Save Mart-Bogdan/77a90216de92963fc3ca625ff62885d9 to your computer and use it in GitHub Desktop.
Dotnet inlinable iterables (enumerables) WIP
using System.Collections;
using System.Runtime.CompilerServices;
// using DelegateTo;
namespace ConsoleApp1;
class Program
{
[MethodImpl(MethodImplOptions.NoInlining | MethodImplOptions.AggressiveOptimization)]
static void Main(string[] args)
{
MyArrayWrap<int> arr = CreateArray();
// (new int[5]).AsSpan()
var kek = arr.Where(new PredIntIsEven());
// var kek = arr.GetEnumerator().Where(new PredIntIsEven());
foreach (int item in kek)
{
Console.WriteLine(item);
}
}
[MethodImpl(MethodImplOptions.NoInlining)]
private static MyArrayWrap<int> CreateArray()
{
return new MyArrayWrap<int>{array = new []{1,1,1,1,2,2,3,4,5,6,7,8,9}};
}
}
public struct PredIntIsEven: IPredicate<int>
{
// [MethodImpl(MethodImplOptions.AggressiveInlining)]
public bool Matches(in int item)
{
return (item & 1) == 0;
// return item > 5 ;
}
}
public interface IPredicate<T>{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
bool Matches(in T item);
}
// public static class MyArrayWrapExt {
//
// [MethodImpl(MethodImplOptions.AggressiveInlining)]
// public static WhereEnumerable<T, TInner, TInnerIter, TPredicate> Where<T, TInner, TInnerIter, TPredicate>(this TInner @this, TPredicate predicate)
// where TInner : IIterable<T, TInnerIter>
// where TInnerIter:IITerator<T>
// where TPredicate : IPredicate<T>
// {
// return new WhereEnumerable<T, TInner, TInnerIter, TPredicate>(@this, predicate);
// }
//
// }
public struct WhereEnumerable<T, TInner, TInnerIter, TPredicate > : IIterable<T, WhereEnumerable<T, TInner, TInnerIter, TPredicate >, WhereEnumerator<T, TInnerIter, TPredicate>>
where TInner : IIterable<T, TInner, TInnerIter>
where TInnerIter:IITerator<T>
where TPredicate:IPredicate<T>
{
private TInner _inner;
private TPredicate _predicate;
public WhereEnumerable(TInner inner, TPredicate predicate)
{
_inner = inner;
_predicate = predicate;
}
public WhereEnumerator<T, TInnerIter, TPredicate> GetEnumerator() => new(_inner.GetEnumerator(), _predicate);
}
public struct WhereEnumerator<T, TInnerIter, TPredicate> : IITerator<T> where TInnerIter:IITerator<T> where TPredicate:IPredicate<T>
{
private TInnerIter _inner;
private TPredicate _predicate;
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public WhereEnumerator(TInnerIter inner, TPredicate predicate)
{
_inner = inner;
_predicate = predicate;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public bool MoveNext()
{
do
{
if (!_inner.MoveNext())
return false;
} while (!_predicate.Matches(_inner.Current));
return true;
}
public ref T Current
{
[MethodImpl(MethodImplOptions.AggressiveInlining)] get => ref this._inner.Current;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void Dispose()
{
}
}
public interface IITerator<T>:IDisposable
{
bool MoveNext();
public ref T Current { get; }
}
public interface IIterable<T, Self, TIter>
where TIter : IITerator<T>
where Self : IIterable<T, Self, TIter>
{
TIter GetEnumerator();
// [MethodImpl(MethodImplOptions.AggressiveInlining)]
// public WhereEnumerable<T, Self, TIter, TPredicate> Where<TPredicate>( TPredicate predicate)
// where TPredicate : IPredicate<T>
// {
// return new WhereEnumerable<T, Self, TIter, TPredicate>((Self)this, predicate);
// }
}
public struct MethodsImpl<T, Self, TIter>
where TIter : IITerator<T>
where Self : IIterable<T, Self, TIter>
{
private Self self;
public MethodsImpl(Self self)
{
this.self = self;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public WhereEnumerable<T, Self, TIter, TPredicate> Where<TPredicate>( TPredicate predicate)
where TPredicate : IPredicate<T>
{
return new WhereEnumerable<T, Self, TIter, TPredicate>(self, predicate);
}
}
public partial struct MyArrayWrap<T> : IIterable<T, MyArrayWrap<T>, MyArrayWrap<T>.Enumerator>
{
public T[] array;
public Enumerator GetEnumerator() => new Enumerator(this.array);
// [GenerateDelegate(Inline = true)]
// public MethodsImpl<T, MyArrayWrap<T>, Enumerator> Methods
// {
// [MethodImpl(MethodImplOptions.AggressiveInlining)]
// get
// {
// return new MethodsImpl<T, MyArrayWrap<T>, Enumerator>( this);
// }
// }
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public WhereEnumerable<T, MyArrayWrap<T>, Enumerator, TPredicate> Where<TPredicate>( TPredicate predicate)
where TPredicate : IPredicate<T>
{
return new WhereEnumerable<T, MyArrayWrap<T>, Enumerator, TPredicate>(this, predicate);
}
public struct Enumerator : IITerator<T>
{
private T[] _array;
private int _index;
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public Enumerator(T[] array)
{
_array = array;
_index = -1;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public bool MoveNext()
{
int num = this._index + 1;
if (num >= this._array.Length)
return false;
this._index = num;
return true;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void Reset()
{
_index = -1;
}
public ref T Current
{
[MethodImpl(MethodImplOptions.AggressiveInlining)] get => ref this._array[this._index];
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void Dispose()
{
}
}
}

Output

C:\Users\winnie\AppData\Local\Programs\Rider\plugins\dpa\DotFiles\JetBrains.DPA.Runner.exe --handle=13056 --backend-pid=15976 --etw-collect-flags=67108622 --detach-event-name=dpa.detach.15976.2 --refresh-interval=1 -- C:/Users/winnie/RiderProjects/StructIterables/ConsoleApp1/bin/Release/net9.0/ConsoleApp1.exe
; Assembly listing for method ConsoleApp1.Program:Main(System.String[]) (FullOpts)
; Emitting BLENDED_CODE for X64 with AVX - Windows
; FullOpts code
; optimized code
; optimized using Synthesized PGO
; rsp based frame
; fully interruptible
; with Synthesized PGO: fgCalledCount is 100
; No PGO data
; 0 inlinees with PGO data; 12 single block inlinees; 2 inlinees without PGO data

G_M000_IG01:                ;; offset=0x0000
       sub      rsp, 56
       vxorps   xmm4, xmm4, xmm4
       vmovdqa  xmmword ptr [rsp+0x20], xmm4
       xor      eax, eax
       mov      qword ptr [rsp+0x30], rax

G_M000_IG02:                ;; offset=0x0015
       call     [ConsoleApp1.Program:CreateArray():ConsoleApp1.MyArrayWrap`1[int]]
       xor      ecx, ecx
       mov      gword ptr [rsp+0x20], rax
       mov      dword ptr [rsp+0x28], -1
       mov      byte  ptr [rsp+0x30], cl
       jmp      SHORT G_M000_IG04

G_M000_IG03:                ;; offset=0x0030
       call     [System.Console:WriteLine(int)]

G_M000_IG04:                ;; offset=0x0036
       mov      ecx, dword ptr [rsp+0x28]
       inc      ecx
       mov      rax, gword ptr [rsp+0x20]
       cmp      dword ptr [rax+0x08], ecx
       jg       SHORT G_M000_IG06

G_M000_IG05:                ;; offset=0x0046
       add      rsp, 56
       ret

G_M000_IG06:                ;; offset=0x004B
       mov      dword ptr [rsp+0x28], ecx
       mov      rcx, gword ptr [rsp+0x20]
       mov      eax, dword ptr [rsp+0x28]
       cmp      eax, dword ptr [rcx+0x08]
       jae      SHORT G_M000_IG07
       mov      ecx, dword ptr [rcx+4*rax+0x10]
       test     cl, 1
       jne      SHORT G_M000_IG04
       jmp      SHORT G_M000_IG03

G_M000_IG07:                ;; offset=0x0068
       call     CORINFO_HELP_RNGCHKFAIL
       int3

; Total bytes of code 110

2
2
4
6
8

Process finished with exit code 0.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment