#nullable enable using System; using System.Collections; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace IPA.Utilities { /// /// Extensions for that don't currently exist in System.Linq. /// public static class EnumerableExtensions { /// /// Adds a value to the beginning of the sequence. /// /// the type of the elements of /// a sequence of values /// the value to prepend to /// a new sequence beginning with public static IEnumerable Prepend(this IEnumerable seq, T prep) => new PrependEnumerable(seq, prep); private sealed class PrependEnumerable : IEnumerable { private readonly IEnumerable rest; private readonly T first; public PrependEnumerable(IEnumerable rest, T first) { this.rest = rest; this.first = first; } public PrependEnumerator GetEnumerator() => new(this); public struct PrependEnumerator : IEnumerator { private readonly IEnumerator restEnum; private readonly PrependEnumerable enumerable; private int state; internal PrependEnumerator(PrependEnumerable enumerable) { this.enumerable = enumerable; restEnum = enumerable.rest.GetEnumerator(); state = 0; Current = default!; } public T Current { get; private set; } object? IEnumerator.Current => Current; public void Dispose() => restEnum.Dispose(); public bool MoveNext() { switch (state) { case 0: Current = enumerable.first; state++; return true; case 1: if (!restEnum.MoveNext()) { state = 2; return false; } else Current = restEnum.Current; return true; case 2: default: return false; } } public void Reset() { restEnum.Reset(); state = 0; } } IEnumerator IEnumerable.GetEnumerator() => new PrependEnumerator(this); IEnumerator IEnumerable.GetEnumerator() => GetEnumerator(); } /// /// Adds a value to the end of the sequence. /// /// the type of the elements of /// a sequence of values /// the value to append to /// a new sequence ending with public static IEnumerable Append(this IEnumerable seq, T app) => new AppendEnumerable(seq, app); private sealed class AppendEnumerable : IEnumerable { private readonly IEnumerable rest; private readonly T last; public AppendEnumerable(IEnumerable rest, T last) { this.rest = rest; this.last = last; } public AppendEnumerator GetEnumerator() => new(this); public struct AppendEnumerator : IEnumerator { private readonly IEnumerator restEnum; private readonly AppendEnumerable enumerable; private int state; internal AppendEnumerator(AppendEnumerable enumerable) { this.enumerable = enumerable; restEnum = enumerable.rest.GetEnumerator(); state = 0; Current = default!; } public T Current { get; private set; } object? IEnumerator.Current => Current; public void Dispose() => restEnum.Dispose(); public bool MoveNext() { switch (state) { case 0: if (!restEnum.MoveNext()) { state = 1; goto case 1; } else Current = restEnum.Current; return true; case 1: Current = enumerable.last; state++; return true; case 2: default: return false; } } public void Reset() { restEnum.Reset(); state = 0; } } IEnumerator IEnumerable.GetEnumerator() => GetEnumerator(); IEnumerator IEnumerable.GetEnumerator() => GetEnumerator(); } /// /// LINQ-style extension method that filters elements out of an enumeration. /// /// the type of the enumeration /// the enumeration to filter /// a filtered enumerable public static IEnumerable NonNull(this IEnumerable self) where T : class => self.Where(o => o != null)!; /// /// LINQ-style extension method that filters elements out of an enumeration based on a converter. /// /// the type of the enumeration /// the type to compare to null /// the enumeration to filter /// the predicate to select for filtering /// a filtered enumerable public static IEnumerable NonNull(this IEnumerable self, Func pred) where U : class => self.Where(o => pred(o) != null); /// /// LINQ-style extension method that filters elements from an enumeration of nullable types. /// /// the underlying type of the nullable enumeration /// the enumeration to filter /// a filtered enumerable public static IEnumerable NonNull(this IEnumerable self) where T : struct => self.Where(o => o != null).Select(o => o!.Value); /// /// LINQ-style extension method that filters elements out of an enumeration based on a converter to a nullable type. /// /// the type of the enumeration /// the type of the predicate's resulting nullable /// the enumeration to filter /// the predicate to select for filtering /// a filtered enumerable public static IEnumerable NonNull(this IEnumerable self, Func pred) where U : struct => self.Where(o => pred(o) != null); } }