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}