Tanoda
Query.cs
Go to the documentation of this file.
1/******************************************************************************
2 * Copyright (C) Ultraleap, Inc. 2011-2020. *
3 * *
4 * Use subject to the terms of the Apache License 2.0 available at *
5 * http://www.apache.org/licenses/LICENSE-2.0, or another agreement *
6 * between Ultraleap and you, your company or other organization. *
7 ******************************************************************************/
8
9using System;
10using System.Collections.Generic;
11using System.Collections;
12
14
15 public static class QueryConversionExtensions {
16
20 public static Query<T> Query<T>(this ICollection<T> collection) {
21 return new Query<T>(collection);
22 }
23
27 public static Query<T> Query<T>(this IEnumerable<T> enumerable) {
28 List<T> list = Pool<List<T>>.Spawn();
29 try {
30 list.AddRange(enumerable);
31 return new Query<T>(list);
32 } finally {
33 list.Clear();
34 Pool<List<T>>.Recycle(list);
35 }
36 }
37
41 public static Query<T> Query<T>(this IEnumerator<T> enumerator) {
42 List<T> list = Pool<List<T>>.Spawn();
43 try {
44 while (enumerator.MoveNext()) {
45 list.Add(enumerator.Current);
46 }
47 return new Query<T>(list);
48 } finally {
49 list.Clear();
50 Pool<List<T>>.Recycle(list);
51 }
52 }
53
57 public static Query<T> Query<T>(this T[,] array) {
58 var dst = ArrayPool<T>.Spawn(array.GetLength(0) * array.GetLength(1));
59 int dstIndex = 0;
60 for (int i = 0; i < array.GetLength(0); i++) {
61 for (int j = 0; j < array.GetLength(1); j++) {
62 dst[dstIndex++] = array[i, j];
63 }
64 }
65
66 return new Query<T>(dst, array.GetLength(0) * array.GetLength(1));
67 }
68 }
69
90 public struct Query<T> {
91 private T[] _array;
92 private int _count;
93
94 private Validator _validator;
95
101 public Query(T[] array, int count) {
102 if (array == null) {
103 throw new ArgumentNullException("array");
104 }
105
106 if (count < 0) {
107 throw new ArgumentException("Count must be non-negative, but was " + count);
108 }
109
110 if (count > array.Length) {
111 throw new ArgumentException("Count was " + count + " but the provided array only had a length of " + array.Length);
112 }
113
114 _array = array;
115 _count = count;
116 _validator = Validator.Spawn();
117 }
118
122 public Query(ICollection<T> collection) {
123 _array = ArrayPool<T>.Spawn(collection.Count);
124 _count = collection.Count;
125 collection.CopyTo(_array, 0);
126
127 _validator = Validator.Spawn();
128 }
129
133 public Query(Query<T> other) {
134 other._validator.Validate();
135
136 _array = ArrayPool<T>.Spawn(other._count);
137 _count = other._count;
138 Array.Copy(other._array, _array, _count);
139
140 _validator = Validator.Spawn();
141 }
142
143 //Certain operators cannot be implemented as extension methods due to the way
144 //the generic arguments are to be consumed by the user, so there are implemented
145 //directly here in the Query class.
146 #region DIRECT IMPLEMENTED OPERATORS
147
157 public Query<K> OfType<K>() where K : T {
158 _validator.Validate();
159
160 var dstArray = ArrayPool<K>.Spawn(_count);
161
162 int dstCount = 0;
163 for (int i = 0; i < _count; i++) {
164 if (_array[i] is K) {
165 dstArray[dstCount++] = (K)_array[i];
166 }
167 }
168
169 Dispose();
170 return new Query<K>(dstArray, dstCount);
171 }
172
177 public Query<K> Cast<K>() where K : class {
178 return this.Select(item => item as K);
179 }
180
181 #endregion
182
187 public void Dispose() {
188 _validator.Validate();
189
190 ArrayPool<T>.Recycle(_array);
191 Validator.Invalidate(_validator);
192
193 _array = null;
194 _count = 0;
195 }
196
202 public void Deconstruct(out T[] array, out int count) {
203 _validator.Validate();
204
205 array = _array;
206 count = _count;
207
208 Validator.Invalidate(_validator);
209 _array = null;
210 _count = 0;
211 }
212
220 T[] array;
221 int count;
222 Deconstruct(out array, out count);
223
224 return new QuerySlice(array, count);
225 }
226
228 _validator.Validate();
229
230 T[] array;
231 int count;
232 Deconstruct(out array, out count);
233
234 return new Enumerator(array, count);
235 }
236
237 public struct Enumerator : IEnumerator<T> {
238 private T[] _array;
239 private int _count;
240 private int _nextIndex;
241
242 public T Current { get; private set; }
243
244 public Enumerator(T[] array, int count) {
245 _array = array;
246 _count = count;
247 _nextIndex = 0;
248
249 Current = default(T);
250 }
251
252 object IEnumerator.Current {
253 get {
254 if (_nextIndex == 0) {
255 throw new InvalidOperationException();
256 }
257
258 return Current;
259 }
260 }
261
262 public bool MoveNext() {
263 if (_nextIndex >= _count) {
264 return false;
265 }
266
267 Current = _array[_nextIndex++];
268 return true;
269 }
270
271 public void Dispose() {
272 ArrayPool<T>.Recycle(_array);
273 }
274
275 public void Reset() { throw new InvalidOperationException(); }
276 }
277
278 public struct QuerySlice : IDisposable {
279 public readonly T[] BackingArray;
280 public readonly int Count;
281
282 public QuerySlice(T[] array, int count) {
283 BackingArray = array;
284 Count = count;
285 }
286
287 public T this[int index] {
288 get {
289 return BackingArray[index];
290 }
291 }
292
293 public void Dispose() {
294 ArrayPool<T>.Recycle(BackingArray);
295 }
296 }
297
298 private struct Validator {
299 private static int _nextId = 1;
300
301 private Id _idRef;
302 private int _idValue;
303
304 public void Validate() {
305 if (_idValue == 0) {
306 throw new InvalidOperationException("This Query is not valid, you cannot construct a Query using the default constructor.");
307 }
308
309 if (_idRef == null || _idRef.value != _idValue) {
310 throw new InvalidOperationException("This Query has already been disposed. A Query can only be used once before it is automatically disposed.");
311 }
312 }
313
314 public static Validator Spawn() {
315 Id id = Pool<Id>.Spawn();
316 id.value = _nextId++;
317
318 return new Validator() {
319 _idRef = id,
320 _idValue = id.value
321 };
322 }
323
324 public static void Invalidate(Validator validator) {
325 validator._idRef.value = -1;
326 Pool<Id>.Recycle(validator._idRef);
327 }
328
329 private class Id {
330 public int value;
331 }
332 }
333 }
334}
Enumerator(T[] array, int count)
Definition: Query.cs:244
QuerySlice(T[] array, int count)
Definition: Query.cs:282
A Query object is a type of immutable ordered collection of elements that can be used to perform usef...
Definition: Query.cs:90
Query(Query< T > other)
Constructs a query that is an exact copy of another query.
Definition: Query.cs:133
Query(T[] array, int count)
Constructs a new query given a source array and a count. The query assumes ownership of the array,...
Definition: Query.cs:101
Query< K > OfType< K >()
Returns a new Query representing only the items of the current Query that are of a specific type.
Definition: Query.cs:157
Query(ICollection< T > collection)
Constructs a new query of the given collection.
Definition: Query.cs:122
void Deconstruct(out T[] array, out int count)
Deconstructs this Query into its base elements, the array and the count. The caller assumes ownership...
Definition: Query.cs:202
void Dispose()
Disposes of the resources that this query holds. The Query cannot be used after this method is called...
Definition: Query.cs:187
Query< K > Cast< K >()
Returns a new Query representing the current query sequence where each element is cast to a new type.
Definition: Query.cs:177
Enumerator GetEnumerator()
Definition: Query.cs:227
QuerySlice Deconstruct()
Deconstructs this Query into a simple QuerySlice construct. This is simply a utility overload of the ...
Definition: Query.cs:219