You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

105 lines
4.4 KiB

  1. using System;
  2. using System.Collections;
  3. using System.Collections.Generic;
  4. using System.Linq;
  5. using System.Text;
  6. using System.Threading.Tasks;
  7. namespace IPA.Utilities
  8. {
  9. /// <summary>
  10. /// Extensions for <see cref="IEnumerable{T}"/> that don't currently exist in <c>System.Linq</c>.
  11. /// </summary>
  12. public static class EnumerableExtensions
  13. {
  14. /// <summary>
  15. /// Adds a value to the beginning of the sequence.
  16. /// </summary>
  17. /// <typeparam name="T">the type of the elements of <paramref name="seq"/></typeparam>
  18. /// <param name="seq">a sequence of values</param>
  19. /// <param name="prep">the value to prepend to <paramref name="seq"/></param>
  20. /// <returns>a new sequence beginning with <paramref name="prep"/></returns>
  21. public static IEnumerable<T> Prepend<T>(this IEnumerable<T> seq, T prep)
  22. => new PrependEnumerable<T>(seq, prep);
  23. private sealed class PrependEnumerable<T> : IEnumerable<T>
  24. {
  25. private readonly IEnumerable<T> rest;
  26. private readonly T first;
  27. public PrependEnumerable(IEnumerable<T> rest, T first)
  28. {
  29. this.rest = rest;
  30. this.first = first;
  31. }
  32. public IEnumerator<T> GetEnumerator()
  33. { // TODO: a custom impl that is less garbage
  34. yield return first;
  35. foreach (var v in rest) yield return v;
  36. }
  37. IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
  38. }
  39. /// <summary>
  40. /// Adds a value to the end of the sequence.
  41. /// </summary>
  42. /// <typeparam name="T">the type of the elements of <paramref name="seq"/></typeparam>
  43. /// <param name="seq">a sequence of values</param>
  44. /// <param name="app">the value to append to <paramref name="seq"/></param>
  45. /// <returns>a new sequence ending with <paramref name="app"/></returns>
  46. public static IEnumerable<T> Append<T>(this IEnumerable<T> seq, T app)
  47. => new AppendEnumerable<T>(seq, app);
  48. private sealed class AppendEnumerable<T> : IEnumerable<T>
  49. {
  50. private readonly IEnumerable<T> rest;
  51. private readonly T last;
  52. public AppendEnumerable(IEnumerable<T> rest, T last)
  53. {
  54. this.rest = rest;
  55. this.last = last;
  56. }
  57. public IEnumerator<T> GetEnumerator()
  58. { // TODO: a custom impl that is less garbage
  59. foreach (var v in rest) yield return v;
  60. yield return last;
  61. }
  62. IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
  63. }
  64. /// <summary>
  65. /// LINQ extension method that filters <see langword="null"/> elements out of an enumeration.
  66. /// </summary>
  67. /// <typeparam name="T">the type of the enumeration</typeparam>
  68. /// <param name="self">the enumeration to filter</param>
  69. /// <returns>a filtered enumerable</returns>
  70. public static IEnumerable<T> NonNull<T>(this IEnumerable<T> self) where T : class
  71. => self.Where(o => o != null);
  72. /// <summary>
  73. /// LINQ extension method that filters <see langword="null"/> elements out of an enumeration based on a converter.
  74. /// </summary>
  75. /// <typeparam name="T">the type of the enumeration</typeparam>
  76. /// <typeparam name="U">the type to compare to null</typeparam>
  77. /// <param name="self">the enumeration to filter</param>
  78. /// <param name="pred">the predicate to select for filtering</param>
  79. /// <returns>a filtered enumerable</returns>
  80. public static IEnumerable<T> NonNull<T, U>(this IEnumerable<T> self, Func<T, U> pred) where U : class
  81. => self.Where(o => pred(o) != null);
  82. /// <summary>
  83. /// LINQ extension method that filters <see langword="null"/> elements from an enumeration of nullable types.
  84. /// </summary>
  85. /// <typeparam name="T">the underlying type of the nullable enumeration</typeparam>
  86. /// <param name="self">the enumeration to filter</param>
  87. /// <returns>a filtered enumerable</returns>
  88. public static IEnumerable<T> NonNull<T>(this IEnumerable<T?> self) where T : struct
  89. => self.Where(o => o != null).Select(o => o.Value);
  90. }
  91. }