Tanoda
QueryOperatorExtensions.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 UnityEngine;
12
13namespace Leap.Unity.Query {
14
20 public static class QueryOperatorExtensions {
21
31 public static Query<T> Concat<T>(this Query<T> query, ICollection<T> collection) {
32 using (var slice = query.Deconstruct()) {
33 var dstArray = ArrayPool<T>.Spawn(slice.Count + collection.Count);
34
35 Array.Copy(slice.BackingArray, dstArray, slice.Count);
36 collection.CopyTo(dstArray, slice.Count);
37
38 return new Query<T>(dstArray, slice.Count + collection.Count);
39 }
40 }
41
51 public static Query<T> Concat<T>(this Query<T> query, Query<T> other) {
52 using (var slice = query.Deconstruct())
53 using (var otherSlice = other.Deconstruct()) {
54 var dstArray = ArrayPool<T>.Spawn(slice.Count + otherSlice.Count);
55
56 Array.Copy(slice.BackingArray, dstArray, slice.Count);
57 Array.Copy(otherSlice.BackingArray, 0, dstArray, slice.Count, otherSlice.Count);
58
59 return new Query<T>(dstArray, slice.Count + otherSlice.Count);
60 }
61 }
62
72 public static Query<T> Distinct<T>(this Query<T> query) {
73 T[] array;
74 int count;
75 query.Deconstruct(out array, out count);
76
77 HashSet<T> set = Pool<HashSet<T>>.Spawn();
78
79 for (int i = 0; i < count; i++) {
80 set.Add(array[i]);
81 }
82
83 Array.Clear(array, 0, array.Length);
84 count = 0;
85
86 foreach (var item in set) {
87 array[count++] = item;
88 }
89
90 set.Clear();
91 Pool<HashSet<T>>.Recycle(set);
92
93 return new Query<T>(array, count);
94 }
95
105 public static Query<T> OfType<T>(this Query<T> query, Type type) {
106 using (var slice = query.Deconstruct()) {
107 var dstArray = ArrayPool<T>.Spawn(slice.Count);
108
109 int dstCount = 0;
110 for (int i = 0; i < slice.Count; i++) {
111 if (slice[i] != null &&
112 type.IsAssignableFrom(slice[i].GetType())) {
113 dstArray[dstCount++] = slice[i];
114 }
115 }
116
117 return new Query<T>(dstArray, dstCount);
118 }
119 }
120
125 public static Query<T> OrderBy<T, K>(this Query<T> query, Func<T, K> selector) where K : IComparable<K> {
126 T[] array;
127 int count;
128 query.Deconstruct(out array, out count);
129
130 var comparer = FunctorComparer<T, K>.Ascending(selector);
131 Array.Sort(array, 0, count, comparer);
132 comparer.Clear();
133
134 return new Query<T>(array, count);
135 }
136
141 public static Query<T> OrderByDescending<T, K>(this Query<T> query, Func<T, K> selector) where K : IComparable<K> {
142 T[] array;
143 int count;
144 query.Deconstruct(out array, out count);
145
146 var comparer = FunctorComparer<T, K>.Descending(selector);
147 Array.Sort(array, 0, count, comparer);
148 comparer.Clear();
149
150 return new Query<T>(array, count);
151 }
152
162 public static Query<T> Repeat<T>(this Query<T> query, int times) {
163 if (times < 0) {
164 throw new ArgumentException("The repetition count must be non-negative.");
165 }
166
167 using (var slice = query.Deconstruct()) {
168 var dstArray = ArrayPool<T>.Spawn(slice.Count * times);
169
170 for (int i = 0; i < times; i++) {
171 Array.Copy(slice.BackingArray, 0, dstArray, i * slice.Count, slice.Count);
172 }
173
174 return new Query<T>(dstArray, slice.Count * times);
175 }
176 }
177
186 public static Query<T> Reverse<T>(this Query<T> query) {
187 T[] array;
188 int count;
189 query.Deconstruct(out array, out count);
190
191 Utils.Reverse(array, 0, count);
192
193 return new Query<T>(array, count);
194 }
195
205 public static Query<K> Select<T, K>(this Query<T> query, Func<T, K> selector) {
206 using (var slice = query.Deconstruct()) {
207 var dstArray = ArrayPool<K>.Spawn(slice.Count);
208 for (int i = 0; i < slice.Count; i++) {
209 dstArray[i] = selector(slice[i]);
210 }
211
212 return new Query<K>(dstArray, slice.Count);
213 }
214 }
215
226 public static Query<K> SelectMany<T, K>(this Query<T> query, Func<T, ICollection<K>> selector) {
227 using (var slice = query.Deconstruct()) {
228 int totalCount = 0;
229 for (int i = 0; i < slice.Count; i++) {
230 totalCount += selector(slice[i]).Count;
231 }
232
233 var dstArray = ArrayPool<K>.Spawn(totalCount);
234
235 int targetIndex = 0;
236 for (int i = 0; i < slice.Count; i++) {
237 var collection = selector(slice[i]);
238 collection.CopyTo(dstArray, targetIndex);
239 targetIndex += collection.Count;
240 }
241
242 return new Query<K>(dstArray, totalCount);
243 }
244 }
245
256 public static Query<K> SelectMany<T, K>(this Query<T> query, Func<T, Query<K>> selector) {
257 using (var slice = query.Deconstruct()) {
258 var slices = ArrayPool<Query<K>.QuerySlice>.Spawn(slice.Count);
259 int totalCount = 0;
260 for (int i = 0; i < slice.Count; i++) {
261 slices[i] = selector(slice[i]).Deconstruct();
262 totalCount += slices[i].Count;
263 }
264
265 var dstArray = ArrayPool<K>.Spawn(totalCount);
266
267 int targetIndex = 0;
268 for (int i = 0; i < slice.Count; i++) {
269 Array.Copy(slices[i].BackingArray, 0, dstArray, targetIndex, slices[i].Count);
270 targetIndex += slices[i].Count;
271 slices[i].Dispose();
272 }
273
274 ArrayPool<Query<K>.QuerySlice>.Recycle(slices);
275
276 return new Query<K>(dstArray, totalCount);
277 }
278 }
279
291 public static Query<T> Skip<T>(this Query<T> query, int toSkip) {
292 T[] array;
293 int count;
294 query.Deconstruct(out array, out count);
295
296 int resultCount = Mathf.Max(count - toSkip, 0);
297 toSkip = count - resultCount;
298 Array.Copy(array, toSkip, array, 0, resultCount);
299 Array.Clear(array, resultCount, array.Length - resultCount);
300
301 return new Query<T>(array, resultCount);
302 }
303
314 public static Query<T> SkipWhile<T>(this Query<T> query, Func<T, bool> predicate) {
315 T[] array;
316 int count;
317 query.Deconstruct(out array, out count);
318
319 int toSkip = 0;
320 while (toSkip < count) {
321 if (predicate(array[toSkip])) {
322 toSkip++;
323 } else {
324 break;
325 }
326 }
327
328 int resultCount = count - toSkip;
329 Array.Copy(array, toSkip, array, 0, resultCount);
330 Array.Clear(array, resultCount, array.Length - resultCount);
331
332 return new Query<T>(array, resultCount);
333 }
334
338 public static Query<T> Sort<T>(this Query<T> query) where T : IComparable<T> {
339 T[] array;
340 int count;
341 query.Deconstruct(out array, out count);
342
343 Array.Sort(array, 0, count);
344
345 return new Query<T>(array, count);
346 }
347
351 public static Query<T> SortDescending<T>(this Query<T> query) where T : IComparable<T> {
352 T[] array;
353 int count;
354 query.Deconstruct(out array, out count);
355
356 Array.Sort(array, 0, count);
357 Utils.Reverse(array, 0, count);
358
359 return new Query<T>(array, count);
360 }
361
372 public static Query<T> Take<T>(this Query<T> query, int toTake) {
373 T[] array;
374 int count;
375 query.Deconstruct(out array, out count);
376
377 count = Mathf.Min(count, toTake);
378 Array.Clear(array, count, array.Length - count);
379
380 return new Query<T>(array, count);
381 }
382
393 public static Query<T> TakeWhile<T>(this Query<T> query, Func<T, bool> predicate) {
394 T[] array;
395 int count;
396 query.Deconstruct(out array, out count);
397
398 int takeCount;
399 for (takeCount = 0; takeCount < count; takeCount++) {
400 if (!predicate(array[takeCount])) {
401 break;
402 }
403 }
404
405 Array.Clear(array, takeCount, array.Length - takeCount);
406
407 return new Query<T>(array, takeCount);
408 }
409
419 public static Query<T> Where<T>(this Query<T> query, Func<T, bool> predicate) {
420 T[] array;
421 int count;
422 query.Deconstruct(out array, out count);
423
424 int writeIndex = 0;
425 for (int i = 0; i < count; i++) {
426 if (predicate(array[i])) {
427 array[writeIndex++] = array[i];
428 }
429 }
430
431 Array.Clear(array, writeIndex, array.Length - writeIndex);
432
433 return new Query<T>(array, writeIndex);
434 }
435
439 public static Query<T> ValidUnityObjs<T>(this Query<T> query) where T : UnityEngine.Object {
440 return query.Where(t => {
441 UnityEngine.Object obj = t;
442 return obj != null;
443 });
444 }
445
456 public static Query<IndexedValue<T>> WithIndices<T>(this Query<T> query) {
457 using (var slice = query.Deconstruct()) {
458 var dstArray = ArrayPool<IndexedValue<T>>.Spawn(slice.Count);
459
460 for (int i = 0; i < slice.Count; i++) {
461 dstArray[i] = new IndexedValue<T>() {
462 index = i,
463 value = slice[i]
464 };
465 }
466
467 return new Query<IndexedValue<T>>(dstArray, slice.Count);
468 }
469 }
470
482 public static Query<PrevPair<T>> WithPrevious<T>(this Query<T> query,
483 int offset = 1, bool includeStart = false)
484 {
485 using (var slice = query.Deconstruct()) {
486 int resultCount = includeStart ? slice.Count : Mathf.Max(0, slice.Count - offset);
487 var dstArray = ArrayPool<PrevPair<T>>.Spawn(resultCount);
488
489 int dstIndex = 0;
490
491 if (includeStart) {
492 for (int i = 0; i < Mathf.Min(slice.Count, offset); i++) {
493 dstArray[dstIndex++] = new PrevPair<T>() {
494 value = slice[i],
495 prev = default(T),
496 hasPrev = false
497 };
498 }
499 }
500
501 for (int i = offset; i < slice.Count; i++) {
502 dstArray[dstIndex++] = new PrevPair<T>() {
503 value = slice[i],
504 prev = slice[i - offset],
505 hasPrev = true
506 };
507 }
508
509 return new Query<PrevPair<T>>(dstArray, resultCount);
510 }
511 }
512
525 public static Query<NextPair<T>> WithNext<T>(this Query<T> query,
526 int offset = 1, bool includeEnd = false)
527 {
528 offset = Math.Abs(offset);
529 using (var slice = query.Deconstruct()) {
530 int resultCount = includeEnd ? slice.Count : Mathf.Max(0, slice.Count - offset);
531 var dstArray = ArrayPool<NextPair<T>>.Spawn(resultCount);
532
533 int dstIndex = 0;
534
535 for (int i = 0; i < slice.Count - offset; i++) {
536 dstArray[dstIndex++] = new NextPair<T>() {
537 value = slice[i],
538 next = slice[i + offset],
539 hasNext = true
540 };
541 }
542
543 if (includeEnd) {
544 for (int i = slice.Count - offset; i < slice.Count; i++) {
545 dstArray[dstIndex++] = new NextPair<T>() {
546 value = slice[i],
547 next = default(T),
548 hasNext = false
549 };
550 }
551 }
552
553 return new Query<NextPair<T>>(dstArray, resultCount);
554 }
555 }
556
569 public static Query<V> Zip<T, K, V>(this Query<T> query, ICollection<K> collection, Func<T, K, V> selector) {
570 using (var slice = query.Deconstruct()) {
571 int resultCount = Mathf.Min(slice.Count, collection.Count);
572 var resultArray = ArrayPool<V>.Spawn(resultCount);
573
574 var tmpArray = ArrayPool<K>.Spawn(collection.Count);
575 collection.CopyTo(tmpArray, 0);
576
577 for (int i = 0; i < resultCount; i++) {
578 resultArray[i] = selector(slice[i], tmpArray[i]);
579 }
580
581 ArrayPool<K>.Recycle(tmpArray);
582
583 return new Query<V>(resultArray, resultCount);
584 }
585 }
586
599 public static Query<V> Zip<T, K, V>(this Query<T> query, Query<K> otherQuery, Func<T, K, V> selector) {
600 using (var slice = query.Deconstruct())
601 using (var otherSlice = otherQuery.Deconstruct()) {
602 int resultCount = Mathf.Min(slice.Count, otherSlice.Count);
603 var resultArray = ArrayPool<V>.Spawn(resultCount);
604
605 for (int i = 0; i < resultCount; i++) {
606 resultArray[i] = selector(slice[i], otherSlice[i]);
607 }
608
609 return new Query<V>(resultArray, resultCount);
610 }
611 }
612
613 public struct PrevPair<T> {
617 public T value;
618
622 public T prev;
623
628 public bool hasPrev;
629 }
630
631 public struct NextPair<T> {
635 public T value;
636
640 public T next;
641
646 public bool hasNext;
647 }
648
649 public struct IndexedValue<T> {
650 public int index;
651 public T value;
652 }
653
654 private class FunctorComparer<T, K> : IComparer<T> where K : IComparable<K> {
655 [ThreadStatic]
656 private static FunctorComparer<T, K> _single;
657
658 private Func<T, K> _functor;
659 private int _sign;
660
661 private FunctorComparer() { }
662
663 public static FunctorComparer<T, K> Ascending(Func<T, K> functor) {
664 return single(functor, 1);
665 }
666
667 public static FunctorComparer<T, K> Descending(Func<T, K> functor) {
668 return single(functor, -1);
669 }
670
671 private static FunctorComparer<T, K> single(Func<T, K> functor, int sign) {
672 if (_single == null) {
673 _single = new FunctorComparer<T, K>();
674 }
675 _single._functor = functor;
676 _single._sign = sign;
677 return _single;
678 }
679
680 public void Clear() {
681 _functor = null;
682 }
683
684 public int Compare(T x, T y) {
685 return _sign * _functor(x).CompareTo(_functor(y));
686 }
687 }
688 }
689}
Es.InkPainter.Math Math
Definition: PaintTest.cs:7
T next
If hasNext is true, the element that comes after the value.
bool hasNext
Does the next field represent the next value? If false, prev will take the default value of T.
T prev
If hasPrev is true, the element that came before value
bool hasPrev
Does the prev field represent a previous value? If false, prev will take the default value of T.