using System;
using System.Collections;
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 where T : IEquatable?
{
private ReadOnlySpan _remaining;
private ReadOnlySpan _current;
private bool _isEnumeratorActive;
private readonly T _splitBy;
private readonly ReadOnlySpan _splitBySpan;
internal SpanSplitEnumerator(ReadOnlySpan buffer, T 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 readonly 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 ref struct SpanSplitEnumeratorAny where T : IEquatable?
{
private ReadOnlySpan _remaining;
private ReadOnlySpan _current;
private bool _isEnumeratorActive;
private readonly ReadOnlySpan _splitBy;
internal SpanSplitEnumeratorAny(ReadOnlySpan buffer, ReadOnlySpan splitBy)
{
_remaining = buffer;
_current = default;
_isEnumeratorActive = true;
_splitBy = splitBy;
}
///
/// Gets the line at the current position of the enumerator.
///
public readonly ReadOnlySpan Current => _current;
///
/// Returns this instance as an enumerator.
///
public readonly SpanSplitEnumeratorAny 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.IndexOfAny(_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, T splitBy) where T : IEquatable
{
return new SpanSplitEnumerator(span, splitBy);
}
public static SpanSplitEnumeratorAny EnumerateSplitAny(this ReadOnlySpan span, ReadOnlySpan splitBy) where T : IEquatable
{
return new SpanSplitEnumeratorAny(span, splitBy);
}
public static SpanSplitEnumerator EnumerateSplit(this Span span, T splitBy) where T : IEquatable
{
return new SpanSplitEnumerator(span, splitBy);
}
public static SpanSplitEnumeratorAny EnumerateSplitAny(this Span span, ReadOnlySpan splitBy) where T : IEquatable
{
return new SpanSplitEnumeratorAny(span, splitBy);
}
public static SpanSplitEnumerator EnumerateSplit(this string str, char splitBy)
{
return EnumerateSplit(str.AsSpan(), splitBy);
}
public static SpanSplitEnumeratorAny EnumerateSplitAny(this string str, ReadOnlySpan splitBy)
{
return EnumerateSplitAny(str.AsSpan(), splitBy);
}
public static ReverseSpanSplitEnumerator ReverseEnumerateSplit(this ReadOnlySpan span, T splitBy) where T : IEquatable
{
return new ReverseSpanSplitEnumerator(span, splitBy);
}
public static ReverseSpanSplitEnumerator ReverseEnumerateSplit(this Span span, T splitBy) where T : IEquatable
{
return new ReverseSpanSplitEnumerator(span, splitBy);
}
public static ReverseSpanSplitEnumerator ReverseEnumerateSplit(this string str, char splitBy)
{
return ReverseEnumerateSplit(str.AsSpan(), splitBy);
}
}
public ref struct ReverseSpanSplitEnumerator where T : IEquatable?
{
private ReadOnlySpan _remaining;
private ReadOnlySpan _current;
private bool _isEnumeratorActive;
private T _splitBy;
internal ReverseSpanSplitEnumerator(ReadOnlySpan buffer, T splitBy)
{
_remaining = buffer;
_current = default;
_isEnumeratorActive = true;
_splitBy = splitBy;
}
///
/// Gets the line at the current position of the enumerator.
///
public readonly ReadOnlySpan Current => _current;
///
/// Returns this instance as an enumerator.
///
public readonly ReverseSpanSplitEnumerator 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.LastIndexOf(_splitBy);
if ((uint)idx < (uint)remaining.Length)
{
_current = remaining.Slice(idx + 1);
_remaining = remaining.Slice(0, idx);
}
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;
}
}
}