using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace CodeWalker.Core.Utils { /// /// Enumerates the lines of a . /// /// /// To get an instance of this type, use . /// public ref struct SpanSplitEnumerator { private ReadOnlySpan _remaining; private ReadOnlySpan _current; private bool _isEnumeratorActive; private char _splitBy; internal SpanSplitEnumerator(ReadOnlySpan buffer, char splitBy) { _remaining = buffer; _current = default; _isEnumeratorActive = true; _splitBy = splitBy; } /// /// Gets the line at the current position of the enumerator. /// public ReadOnlySpan Current => _current; /// /// Returns this instance as an enumerator. /// public SpanSplitEnumerator GetEnumerator() => this; /// /// Advances the enumerator to the next line of the span. /// /// /// True if the enumerator successfully advanced to the next line; false if /// the enumerator has advanced past the end of the span. /// public bool MoveNext() { if (!_isEnumeratorActive) { return false; // EOF previously reached or enumerator was never initialized } ReadOnlySpan remaining = _remaining; int idx = remaining.IndexOf(_splitBy); if ((uint)idx < (uint)remaining.Length) { _current = remaining.Slice(0, idx); _remaining = remaining.Slice(idx + 1); } else { // We've reached EOF, but we still need to return 'true' for this final // iteration so that the caller can query the Current property once more. _current = remaining; _remaining = default; _isEnumeratorActive = false; } return true; } } public static class EnumerateSplitExtensions { public static SpanSplitEnumerator EnumerateSplit(this ReadOnlySpan span, char splitBy) { return new SpanSplitEnumerator(span, splitBy); } public static SpanSplitEnumerator EnumerateSplit(this Span span, char splitBy) { return new SpanSplitEnumerator(span, splitBy); } public static SpanSplitEnumerator EnumerateSplit(this string str, char splitBy) { return new SpanSplitEnumerator(str.AsSpan(), splitBy); } } }