C
C#17mo ago
DaVinki

❔ ✅ Using a foreach loop on a custom enumerator

I created my own enumerator using the IEnumerator<T> interface but refactored it into a ref struct which can't implement interfaces. How can I use foreach with it? I noticed that Span<T>.Enumerator does this but probably because it's a part of .NET
using System.Numerics;

namespace common_vector_ops;

public ref struct VectorIterator<T> where T : struct
{
public int Index { get; private set; }
public int Increment { get; }
public Span<T> VectorizedSpan { get; }

public VectorIterator() : this(Span<T>.Empty)
{
}

public VectorIterator(T[] array)
{
VectorizedSpan = array.AsSpan();
Increment = Vector<T>.Count;
Index = -Increment;
}

public VectorIterator(Span<T> span)
{
VectorizedSpan = span;
Increment = Vector<T>.Count;
Index = -Increment;
}

public bool MoveNext()
{
Index += Increment;
return Index <= VectorizedSpan.Length - Increment;
}

public void Reset()
{
Index = -Increment;
}

public Vector<T> Current => new Vector<T>(VectorizedSpan[Index..]);
}
using System.Numerics;

namespace common_vector_ops;

public ref struct VectorIterator<T> where T : struct
{
public int Index { get; private set; }
public int Increment { get; }
public Span<T> VectorizedSpan { get; }

public VectorIterator() : this(Span<T>.Empty)
{
}

public VectorIterator(T[] array)
{
VectorizedSpan = array.AsSpan();
Increment = Vector<T>.Count;
Index = -Increment;
}

public VectorIterator(Span<T> span)
{
VectorizedSpan = span;
Increment = Vector<T>.Count;
Index = -Increment;
}

public bool MoveNext()
{
Index += Increment;
return Index <= VectorizedSpan.Length - Increment;
}

public void Reset()
{
Index = -Increment;
}

public Vector<T> Current => new Vector<T>(VectorizedSpan[Index..]);
}
8 Replies
Anton
Anton17mo ago
you don't have to it will work with foreach as is also make the current property readonly you have to add GetEnumerator method
DaVinki
DaVinki17mo ago
How would I add this to a Span type? It already has a GetEnumerator method which just enumerates over the elements instead which the foreach was using
Anton
Anton17mo ago
make a wrapper and return that from a method or something
DaVinki
DaVinki17mo ago
I just added the method to the enumerator itself and used that in the foreach, didn't know it worked like that
Anton
Anton17mo ago
yeah you can do it like that, even though it's better to split these up into two types. the enumerable should not contain the state of enumeration, it should be able to produce new enumerators without restrictions
DaVinki
DaVinki17mo ago
What do you reckon it would be called? SpanSpan? SpanEnumeratorWrapper? Seems unnecessary for the user and program to create a new object that lives for 1 method call which just returns another object anyways
Anton
Anton17mo ago
if you don't need to support getting the enumerator multiple times, then there is no reason otherwise, name it blahEnumerable ig
Accord
Accord17mo ago
Was this issue resolved? If so, run /close - otherwise I will mark this as stale and this post will be archived until there is new activity.