Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Save mgravell/a5cc87683198c0ce657c0b778a1a5e23 to your computer and use it in GitHub Desktop.
Save mgravell/a5cc87683198c0ce657c0b778a1a5e23 to your computer and use it in GitHub Desktop.
string src = "abc";
foreach (var chunk in src.Find(42))
{
// woohoo, this compiles!
}
static class MyHelperExtensions
{
// just exists to make the API available; "notImportant" is *all* of your
// additional state
public static MyCustomEnumerable Find(this string source, int notImportant)
=> new(source, notImportant);
}
// the "Enumerable" wrapper is meant to be repeatable and just has
// state required to *begin* a particular operation (not the actual
// thinking state); this could be a ref struct if we also need to
// store spans or refs (the latter depends on the specific runtime)
readonly struct MyCustomEnumerable
{
private readonly string _source;
private readonly int _notImportant; // other inputs here
public MyCustomEnumerable(string source, int notImportant)
{
_source = source;
_notImportant = notImportant;
}
public Enumerator GetEnumerator() => new(in this);
// the "Enumerator" is the actual thinking logic and state required
// between operations; by making this a ref struct, we are allowed
// to store an intermediate Span<char> etc, avoiding fetching .Span
// repeatedly
public ref struct Enumerator
{
private readonly MyCustomEnumerable src;
public Enumerator(scoped in MyCustomEnumerable src)
=> this.src = src;
// this is the actual iteration "find next" logic, that should update
// Current and report true or false
public bool MoveNext() => throw new NotImplementedException();
public Span<char> Current { get; private set; }
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment