|
|
- #nullable enable
- using System;
- using System.Collections;
- using System.Collections.Generic;
- using System.Linq;
- using System.Text;
- using System.Threading.Tasks;
-
- namespace IPA.Utilities
- {
- /// <summary>
- /// Extensions for <see cref="IEnumerable{T}"/> that don't currently exist in <c>System.Linq</c>.
- /// </summary>
- public static class EnumerableExtensions
- {
- /// <summary>
- /// Adds a value to the beginning of the sequence.
- /// </summary>
- /// <typeparam name="T">the type of the elements of <paramref name="seq"/></typeparam>
- /// <param name="seq">a sequence of values</param>
- /// <param name="prep">the value to prepend to <paramref name="seq"/></param>
- /// <returns>a new sequence beginning with <paramref name="prep"/></returns>
- public static IEnumerable<T> Prepend<T>(this IEnumerable<T> seq, T prep)
- => new PrependEnumerable<T>(seq, prep);
-
- private sealed class PrependEnumerable<T> : IEnumerable<T>
- {
- private readonly IEnumerable<T> rest;
- private readonly T first;
-
- public PrependEnumerable(IEnumerable<T> rest, T first)
- {
- this.rest = rest;
- this.first = first;
- }
-
- public PrependEnumerator GetEnumerator() => new(this);
-
- public struct PrependEnumerator : IEnumerator<T>
- {
- private readonly IEnumerator<T> restEnum;
- private readonly PrependEnumerable<T> enumerable;
- private int state;
- internal PrependEnumerator(PrependEnumerable<T> 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<T> IEnumerable<T>.GetEnumerator() => new PrependEnumerator(this);
- IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
- }
-
- /// <summary>
- /// Adds a value to the end of the sequence.
- /// </summary>
- /// <typeparam name="T">the type of the elements of <paramref name="seq"/></typeparam>
- /// <param name="seq">a sequence of values</param>
- /// <param name="app">the value to append to <paramref name="seq"/></param>
- /// <returns>a new sequence ending with <paramref name="app"/></returns>
- public static IEnumerable<T> Append<T>(this IEnumerable<T> seq, T app)
- => new AppendEnumerable<T>(seq, app);
-
- private sealed class AppendEnumerable<T> : IEnumerable<T>
- {
- private readonly IEnumerable<T> rest;
- private readonly T last;
-
- public AppendEnumerable(IEnumerable<T> rest, T last)
- {
- this.rest = rest;
- this.last = last;
- }
-
- public AppendEnumerator GetEnumerator() => new(this);
-
- public struct AppendEnumerator : IEnumerator<T>
- {
- private readonly IEnumerator<T> restEnum;
- private readonly AppendEnumerable<T> enumerable;
- private int state;
- internal AppendEnumerator(AppendEnumerable<T> 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<T> IEnumerable<T>.GetEnumerator() => GetEnumerator();
- IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
- }
-
- /// <summary>
- /// LINQ-style extension method that filters <see langword="null"/> elements out of an enumeration.
- /// </summary>
- /// <typeparam name="T">the type of the enumeration</typeparam>
- /// <param name="self">the enumeration to filter</param>
- /// <returns>a filtered enumerable</returns>
- public static IEnumerable<T> NonNull<T>(this IEnumerable<T?> self) where T : class
- => self.Where(o => o != null)!;
-
- /// <summary>
- /// LINQ-style extension method that filters <see langword="null"/> elements out of an enumeration based on a converter.
- /// </summary>
- /// <typeparam name="T">the type of the enumeration</typeparam>
- /// <typeparam name="U">the type to compare to null</typeparam>
- /// <param name="self">the enumeration to filter</param>
- /// <param name="pred">the predicate to select for filtering</param>
- /// <returns>a filtered enumerable</returns>
- public static IEnumerable<T> NonNull<T, U>(this IEnumerable<T> self, Func<T, U?> pred) where U : class
- => self.Where(o => pred(o) != null);
-
- /// <summary>
- /// LINQ-style extension method that filters <see langword="null"/> elements from an enumeration of nullable types.
- /// </summary>
- /// <typeparam name="T">the underlying type of the nullable enumeration</typeparam>
- /// <param name="self">the enumeration to filter</param>
- /// <returns>a filtered enumerable</returns>
- public static IEnumerable<T> NonNull<T>(this IEnumerable<T?> self) where T : struct
- => self.Where(o => o != null).Select(o => o!.Value);
-
- /// <summary>
- /// LINQ-style extension method that filters <see langword="null"/> elements out of an enumeration based on a converter to a nullable type.
- /// </summary>
- /// <typeparam name="T">the type of the enumeration</typeparam>
- /// <typeparam name="U">the type of the predicate's resulting nullable</typeparam>
- /// <param name="self">the enumeration to filter</param>
- /// <param name="pred">the predicate to select for filtering</param>
- /// <returns>a filtered enumerable</returns>
- public static IEnumerable<T> NonNull<T, U>(this IEnumerable<T> self, Func<T, U?> pred) where U : struct
- => self.Where(o => pred(o) != null);
- }
- }
|