10using System.Collections.Generic;
20 public static class QueryOperatorExtensions {
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);
35 Array.Copy(slice.BackingArray, dstArray, slice.Count);
36 collection.CopyTo(dstArray, slice.Count);
38 return new Query<T>(dstArray, slice.Count + collection.Count);
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);
56 Array.Copy(slice.BackingArray, dstArray, slice.Count);
57 Array.Copy(otherSlice.BackingArray, 0, dstArray, slice.Count, otherSlice.Count);
59 return new Query<T>(dstArray, slice.Count + otherSlice.Count);
72 public static Query<T> Distinct<T>(
this Query<T> query) {
75 query.Deconstruct(out array, out count);
77 HashSet<T>
set = Pool<HashSet<T>>.Spawn();
79 for (
int i = 0; i < count; i++) {
83 Array.Clear(array, 0, array.Length);
86 foreach (var item
in set) {
87 array[count++] = item;
91 Pool<HashSet<T>>.Recycle(
set);
93 return new Query<T>(array, count);
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);
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];
117 return new Query<T>(dstArray, dstCount);
125 public static Query<T> OrderBy<T, K>(
this Query<T> query, Func<T, K> selector) where K : IComparable<K> {
128 query.Deconstruct(out array, out count);
130 var comparer = FunctorComparer<T, K>.Ascending(selector);
131 Array.Sort(array, 0, count, comparer);
134 return new Query<T>(array, count);
141 public static Query<T> OrderByDescending<T, K>(
this Query<T> query, Func<T, K> selector) where K : IComparable<K> {
144 query.Deconstruct(out array, out count);
146 var comparer = FunctorComparer<T, K>.Descending(selector);
147 Array.Sort(array, 0, count, comparer);
150 return new Query<T>(array, count);
162 public static Query<T> Repeat<T>(
this Query<T> query,
int times) {
164 throw new ArgumentException(
"The repetition count must be non-negative.");
167 using (var slice = query.Deconstruct()) {
168 var dstArray = ArrayPool<T>.Spawn(slice.Count * times);
170 for (
int i = 0; i < times; i++) {
171 Array.Copy(slice.BackingArray, 0, dstArray, i * slice.Count, slice.Count);
174 return new Query<T>(dstArray, slice.Count * times);
186 public static Query<T> Reverse<T>(
this Query<T> query) {
189 query.Deconstruct(out array, out count);
191 Utils.Reverse(array, 0, count);
193 return new Query<T>(array, count);
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]);
212 return new Query<K>(dstArray, slice.Count);
226 public static Query<K> SelectMany<T, K>(
this Query<T> query, Func<T, ICollection<K>> selector) {
227 using (var slice = query.Deconstruct()) {
229 for (
int i = 0; i < slice.Count; i++) {
230 totalCount += selector(slice[i]).Count;
233 var dstArray = ArrayPool<K>.Spawn(totalCount);
236 for (
int i = 0; i < slice.Count; i++) {
237 var collection = selector(slice[i]);
238 collection.CopyTo(dstArray, targetIndex);
239 targetIndex += collection.Count;
242 return new Query<K>(dstArray, totalCount);
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);
260 for (
int i = 0; i < slice.Count; i++) {
261 slices[i] = selector(slice[i]).Deconstruct();
262 totalCount += slices[i].Count;
265 var dstArray = ArrayPool<K>.Spawn(totalCount);
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;
274 ArrayPool<Query<K>.QuerySlice>.Recycle(slices);
276 return new Query<K>(dstArray, totalCount);
291 public static Query<T> Skip<T>(
this Query<T> query,
int toSkip) {
294 query.Deconstruct(out array, out count);
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);
301 return new Query<T>(array, resultCount);
314 public static Query<T> SkipWhile<T>(
this Query<T> query, Func<T, bool> predicate) {
317 query.Deconstruct(out array, out count);
320 while (toSkip < count) {
321 if (predicate(array[toSkip])) {
328 int resultCount = count - toSkip;
329 Array.Copy(array, toSkip, array, 0, resultCount);
330 Array.Clear(array, resultCount, array.Length - resultCount);
332 return new Query<T>(array, resultCount);
338 public static Query<T> Sort<T>(
this Query<T> query) where T : IComparable<T> {
341 query.Deconstruct(out array, out count);
343 Array.Sort(array, 0, count);
345 return new Query<T>(array, count);
351 public static Query<T> SortDescending<T>(
this Query<T> query) where T : IComparable<T> {
354 query.Deconstruct(out array, out count);
356 Array.Sort(array, 0, count);
357 Utils.Reverse(array, 0, count);
359 return new Query<T>(array, count);
372 public static Query<T> Take<T>(
this Query<T> query,
int toTake) {
375 query.Deconstruct(out array, out count);
377 count = Mathf.Min(count, toTake);
378 Array.Clear(array, count, array.Length - count);
380 return new Query<T>(array, count);
393 public static Query<T> TakeWhile<T>(
this Query<T> query, Func<T, bool> predicate) {
396 query.Deconstruct(out array, out count);
399 for (takeCount = 0; takeCount < count; takeCount++) {
400 if (!predicate(array[takeCount])) {
405 Array.Clear(array, takeCount, array.Length - takeCount);
407 return new Query<T>(array, takeCount);
419 public static Query<T> Where<T>(
this Query<T> query, Func<T, bool> predicate) {
422 query.Deconstruct(out array, out count);
425 for (
int i = 0; i < count; i++) {
426 if (predicate(array[i])) {
427 array[writeIndex++] = array[i];
431 Array.Clear(array, writeIndex, array.Length - writeIndex);
433 return new Query<T>(array, writeIndex);
439 public static Query<T> ValidUnityObjs<T>(
this Query<T> query) where T :
UnityEngine.Object {
440 return query.Where(t => {
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);
460 for (
int i = 0; i < slice.Count; i++) {
461 dstArray[i] =
new IndexedValue<T>() {
467 return new Query<IndexedValue<T>>(dstArray, slice.Count);
482 public static Query<PrevPair<T>> WithPrevious<T>(
this Query<T> query,
483 int offset = 1,
bool includeStart =
false)
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);
492 for (
int i = 0; i < Mathf.Min(slice.Count, offset); i++) {
493 dstArray[dstIndex++] =
new PrevPair<T>() {
501 for (
int i = offset; i < slice.Count; i++) {
502 dstArray[dstIndex++] =
new PrevPair<T>() {
504 prev = slice[i - offset],
509 return new Query<PrevPair<T>>(dstArray, resultCount);
525 public static Query<NextPair<T>> WithNext<T>(
this Query<T> query,
526 int offset = 1,
bool includeEnd =
false)
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);
535 for (
int i = 0; i < slice.Count - offset; i++) {
536 dstArray[dstIndex++] =
new NextPair<T>() {
538 next = slice[i + offset],
544 for (
int i = slice.Count - offset; i < slice.Count; i++) {
545 dstArray[dstIndex++] =
new NextPair<T>() {
553 return new Query<NextPair<T>>(dstArray, resultCount);
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);
574 var tmpArray = ArrayPool<K>.Spawn(collection.Count);
575 collection.CopyTo(tmpArray, 0);
577 for (
int i = 0; i < resultCount; i++) {
578 resultArray[i] = selector(slice[i], tmpArray[i]);
581 ArrayPool<K>.Recycle(tmpArray);
583 return new Query<V>(resultArray, resultCount);
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);
605 for (
int i = 0; i < resultCount; i++) {
606 resultArray[i] = selector(slice[i], otherSlice[i]);
609 return new Query<V>(resultArray, resultCount);
654 private class FunctorComparer<T, K> : IComparer<T> where K : IComparable<K> {
656 private static FunctorComparer<T, K> _single;
658 private Func<T, K> _functor;
661 private FunctorComparer() { }
663 public static FunctorComparer<T, K> Ascending(Func<T, K> functor) {
664 return single(functor, 1);
667 public static FunctorComparer<T, K> Descending(Func<T, K> functor) {
668 return single(functor, -1);
671 private static FunctorComparer<T, K> single(Func<T, K> functor,
int sign) {
672 if (_single ==
null) {
673 _single =
new FunctorComparer<T, K>();
675 _single._functor = functor;
676 _single._sign = sign;
680 public void Clear() {
684 public int Compare(T x, T y) {
685 return _sign * _functor(x).CompareTo(_functor(y));
T value
The current element of the sequence
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 value
The current element of the sequence
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.