A game about forced loneliness, made by TACStudios
1using System; 2using System.Collections; 3using System.Collections.Generic; 4using System.Linq; 5using UnityEngine; 6 7namespace Unity.VisualScripting 8{ 9 public static class LinqUtility 10 { 11 public static IEnumerable<T> Concat<T>(params IEnumerable[] enumerables) 12 { 13 foreach (var enumerable in enumerables.NotNull()) 14 { 15 foreach (var item in enumerable.OfType<T>()) 16 { 17 yield return item; 18 } 19 } 20 } 21 22 public static IEnumerable<T> DistinctBy<T, TKey>(this IEnumerable<T> items, Func<T, TKey> property) 23 { 24 return items.GroupBy(property).Select(x => x.First()); 25 } 26 27 public static IEnumerable<T> NotNull<T>(this IEnumerable<T> enumerable) 28 { 29 return enumerable.Where(i => i != null); 30 } 31 32 public static IEnumerable<T> Yield<T>(this T t) 33 { 34 yield return t; 35 } 36 37 public static HashSet<T> ToHashSet<T>(this IEnumerable<T> enumerable) 38 { 39 return new HashSet<T>(enumerable); 40 } 41 42 public static void AddRange<T>(this ICollection<T> collection, IEnumerable<T> items) 43 { 44 foreach (var item in items) 45 { 46 collection.Add(item); 47 } 48 } 49 50 public static void AddRange(this IList list, IEnumerable items) 51 { 52 foreach (var item in items) 53 { 54 list.Add(item); 55 } 56 } 57 58 // NETUP: Replace with IReadOnlyCollection, IReadOnlyList 59 60 public static ICollection<T> AsReadOnlyCollection<T>(this IEnumerable<T> enumerable) 61 { 62 if (enumerable is ICollection<T>) 63 { 64 return (ICollection<T>)enumerable; 65 } 66 else 67 { 68 return enumerable.ToList().AsReadOnly(); 69 } 70 } 71 72 public static IList<T> AsReadOnlyList<T>(this IEnumerable<T> enumerable) 73 { 74 if (enumerable is IList<T>) 75 { 76 return (IList<T>)enumerable; 77 } 78 else 79 { 80 return enumerable.ToList().AsReadOnly(); 81 } 82 } 83 84 public static IEnumerable<T> Flatten<T> 85 ( 86 this IEnumerable<T> source, 87 Func<T, IEnumerable<T>> childrenSelector 88 ) 89 { 90 var flattenedList = source; 91 92 foreach (var element in source) 93 { 94 flattenedList = flattenedList.Concat(childrenSelector(element).Flatten(childrenSelector)); 95 } 96 97 return flattenedList; 98 } 99 100 public static IEnumerable<T> IntersectAll<T>(this IEnumerable<IEnumerable<T>> groups) 101 { 102 HashSet<T> hashSet = null; 103 104 foreach (var group in groups) 105 { 106 if (hashSet == null) 107 { 108 hashSet = new HashSet<T>(group); 109 } 110 else 111 { 112 hashSet.IntersectWith(group); 113 } 114 } 115 116 return hashSet == null ? Enumerable.Empty<T>() : hashSet.AsEnumerable(); 117 } 118 119 public static IEnumerable<T> OrderByDependencies<T>(this IEnumerable<T> source, Func<T, IEnumerable<T>> getDependencies, bool throwOnCycle = true) 120 { 121 var sorted = new List<T>(); 122 var visited = HashSetPool<T>.New(); 123 124 foreach (var item in source) 125 { 126 OrderByDependenciesVisit(item, visited, sorted, getDependencies, throwOnCycle); 127 } 128 129 HashSetPool<T>.Free(visited); 130 131 return sorted; 132 } 133 134 private static void OrderByDependenciesVisit<T>(T item, HashSet<T> visited, List<T> sorted, Func<T, IEnumerable<T>> getDependencies, bool throwOnCycle) 135 { 136 if (!visited.Contains(item)) 137 { 138 visited.Add(item); 139 140 foreach (var dependency in getDependencies(item)) 141 { 142 OrderByDependenciesVisit(dependency, visited, sorted, getDependencies, throwOnCycle); 143 } 144 145 sorted.Add(item); 146 } 147 else 148 { 149 if (throwOnCycle && !sorted.Contains(item)) 150 { 151 throw new InvalidOperationException("Cyclic dependency."); 152 } 153 } 154 } 155 156 public static IEnumerable<T> OrderByDependers<T>(this IEnumerable<T> source, Func<T, IEnumerable<T>> getDependers, bool throwOnCycle = true) 157 { 158 // TODO: Optimize, or use another algorithm (Kahn's?) 159 160 // Convert dependers to dependencies 161 var dependencies = new Dictionary<T, HashSet<T>>(); 162 163 foreach (var dependency in source) 164 { 165 foreach (var depender in getDependers(dependency)) 166 { 167 if (!dependencies.ContainsKey(depender)) 168 { 169 dependencies.Add(depender, new HashSet<T>()); 170 } 171 172 dependencies[depender].Add(dependency); 173 } 174 } 175 176 return source.OrderByDependencies(depender => 177 { 178 if (dependencies.ContainsKey(depender)) 179 { 180 return dependencies[depender]; 181 } 182 else 183 { 184 return Enumerable.Empty<T>(); 185 } 186 }, throwOnCycle); 187 } 188 189 public static IEnumerable<T> Catch<T>(this IEnumerable<T> source, Action<Exception> @catch) 190 { 191 Ensure.That(nameof(source)).IsNotNull(source); 192 193 using (var enumerator = source.GetEnumerator()) 194 { 195 bool success; 196 197 do 198 { 199 try 200 { 201 success = enumerator.MoveNext(); 202 } 203 catch (OperationCanceledException) 204 { 205 yield break; 206 } 207 catch (Exception ex) 208 { 209 @catch?.Invoke(ex); 210 success = false; 211 } 212 213 if (success) 214 { 215 yield return enumerator.Current; 216 } 217 } 218 while (success); 219 } 220 } 221 222 public static IEnumerable<T> Catch<T>(this IEnumerable<T> source, ICollection<Exception> exceptions) 223 { 224 Ensure.That(nameof(exceptions)).IsNotNull(exceptions); 225 226 return source.Catch(exceptions.Add); 227 } 228 229 public static IEnumerable<T> CatchAsLogError<T>(this IEnumerable<T> source, string message) 230 { 231 return source.Catch((ex) => Debug.LogError(message + "\n" + ex.ToString())); 232 } 233 234 public static IEnumerable<T> CatchAsLogWarning<T>(this IEnumerable<T> source, string message) 235 { 236 return source.Catch((ex) => Debug.LogWarning(message + "\n" + ex.ToString())); 237 } 238 } 239}