Skip to content

Instantly share code, notes, and snippets.

@Sergio0694
Last active January 6, 2020 00:19
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Sergio0694/3eff2b8415393b008d0fd595b69e8f62 to your computer and use it in GitHub Desktop.
Save Sergio0694/3eff2b8415393b008d0fd595b69e8f62 to your computer and use it in GitHub Desktop.
A fast and allocation-free method to enumerate items in a collection
using System.Collections.Generic;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
namespace System
{
/// <summary>
/// A <see langword="ref"/> <see langword="struct"/> that enumerates the items in a given <see cref="ReadOnlySpan{T}"/> instance
/// </summary>
/// <typeparam name="T">The type of items to enumerate</typeparam>
public readonly ref struct ReadOnlySpanEnumerator<T>
{
/// <summary>
/// The source <see cref="ReadOnlySpan{T}"/> instance
/// </summary>
private readonly ReadOnlySpan<T> Span;
/// <summary>
/// Creates a new <see cref="ReadOnlySpanEnumerator{T}"/> instance with the specified parameters
/// </summary>
/// <param name="span">The source <see cref="ReadOnlySpan{T}"/> to enumerate</param>
public ReadOnlySpanEnumerator(ReadOnlySpan<T> span)
{
Span = span;
}
/// <inheritdoc cref="IEnumerable{T}.GetEnumerator"/>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public Enumerator GetEnumerator() => new Enumerator(Span);
/// <summary>
/// An enumerator for a source <see cref="ReadOnlySpan{T}"/> instance
/// </summary>
public ref struct Enumerator
{
/// <summary>
/// The target <see cref="ReadOnlySpan{T}"/> instance
/// </summary>
private readonly ReadOnlySpan<T> Span;
/// <summary>
/// The current index
/// </summary>
private int _Index;
/// <summary>
/// Creates a new <see cref="Enumerator"/> instance with the specified parameters
/// </summary>
/// <param name="span">The source <see cref="ReadOnlySpan{T}"/> instance</param>
public Enumerator(ReadOnlySpan<T> span)
{
Span = span;
_Index = -1;
}
/// <inheritdoc cref="System.Collections.IEnumerator.MoveNext"/>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public bool MoveNext()
{
int index = _Index + 1;
if (index < Span.Length)
{
_Index = index;
return true;
}
return false;
}
/// <inheritdoc cref="IEnumerator{T}.Current"/>
public (int Index, T Value) Current
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get
{
int index = _Index;
T value = Unsafe.Add(ref MemoryMarshal.GetReference(Span), index);
return (index, value);
}
}
}
}
}
using System.Diagnostics.Contracts;
using System.Runtime.CompilerServices;
namespace System
{
/// <summary>
/// A <see langword="class"/> with some extension methods for the <see cref="string"/> type
/// </summary>
public static class StringExtensions
{
/// <summary>
/// Creates a new <see cref="ReadOnlySpanEnumerator{T}"/> instance with the specified parameters
/// </summary>
/// <param name="text">The source text to enumerate</param>
/// <returns>A <see cref="ReadOnlySpanEnumerator{T}"/> instance working on <paramref name="text"/></returns>
[Pure]
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static ReadOnlySpanEnumerator<char> Enumerate(this string text) => new ReadOnlySpanEnumerator<char>(text.AsSpan());
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment