Description
Description
Struct enumerators have a lot of potential for high-performance iteration of custom structures. I've seen 'struct-linq' discussed in several places. The following is a simple but practical example.
Try changing the type of arr
to T[]
and inds
to ReadOnlySpan<int>
and observe differences in stack spill and x86.
I'd love a way to write this code fully with spans and have it be performant.
Even the T[]
and int[]
version doesn't compare to the equivalent hand-written version (Test2
). It looks like loop-cloning doesn't see the enumerator as eligible.
public ref struct FilteredSpanEnumerator<T>
{
private readonly ReadOnlySpan<T> arr;
private readonly int[] inds;
private T current;
private int i;
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public FilteredSpanEnumerator(ReadOnlySpan<T> arr, int[] inds) {
this.arr = arr;
this.inds = inds;
current = default;
i = 0;
}
public T Current => current;
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public bool MoveNext() {
if (i >= inds.Length)
return false;
current = arr[inds[i++]];
return true;
}
public FilteredSpanEnumerator<T> GetEnumerator() => this;
public static void Test() => Test3(new T[100], new int[] {0, 5, 6, 12, 47, 99});
public static void Test(ReadOnlySpan<T> elements, int[] inds) {
foreach (var s in new FilteredSpanEnumerator<T>(elements, inds)) {
Console.WriteLine(s);
}
}
public static void Test2(ReadOnlySpan<T> elements, ReadOnlySpan<int> inds) {
int i = 0;
while (i < inds.Length) {
Console.WriteLine(elements[inds[i++]]);
}
}
}
Configuration
.NET 6.0.6, Win x64
Analysis
Probably a duplicate of a number of issues like #68797 #9977 related to struct promotion and loop cloning heuristics.
category:cq
theme:structs
skill-level:expert
cost:large
impact:medium