├── .gitignore ├── Assets └── Smooth │ └── Foundations │ ├── Algebraics │ ├── Either.cs │ ├── Option.cs │ ├── Tuple.cs │ └── Unit.cs │ ├── Collections │ ├── Comparer.cs │ ├── CreateWithComparer.cs │ ├── EqualityComparer.cs │ ├── FuncEnumerable.cs │ ├── ICollectionExtensions.cs │ ├── IDictionaryExtensions.cs │ ├── IListExtensions.cs │ ├── IListStepper.cs │ ├── InspectorKeyValuePair.cs │ └── LinkedListStepper.cs │ ├── Compare │ ├── Comparers │ │ ├── EnumComparers.cs │ │ └── KeyValuePairComparers.cs │ ├── Configuration.cs │ ├── Events.cs │ ├── Examples │ │ └── ExampleConfiguration.cs │ ├── Factory.cs │ ├── Finder.cs │ └── Utilities │ │ └── LogUnregisteredOnDestroy.cs │ ├── Comparisons │ ├── Comparisons.cs │ ├── FuncComparer.cs │ ├── FuncEqualityComparer.cs │ ├── IComparableComparer.cs │ └── IEquatableEqualityComparer.cs │ ├── Delegates │ ├── DelegateExtensions.cs │ ├── Delegates.cs │ └── Tupled.cs │ ├── Dispose │ ├── Disposable.cs │ ├── DisposalQueue.cs │ └── SmoothDisposer.cs │ ├── Events │ └── GenericEvents.cs │ ├── Platform │ ├── BasePlatform.cs │ └── Runtime.cs │ ├── Pools │ ├── KeyedPool.cs │ ├── KeyedPoolWithDefaultKey.cs │ ├── Pool.cs │ ├── PoolWithInitializer.cs │ └── SystemPools.cs │ ├── Slinq │ ├── Collections │ │ ├── Grouping.cs │ │ ├── Linked.cs │ │ └── Lookup.cs │ ├── Context │ │ ├── ChainedOrPooled │ │ │ ├── AggregateContext.cs │ │ │ ├── ConcatContext.cs │ │ │ ├── EitherContext.cs │ │ │ ├── FlattenContext.cs │ │ │ ├── GroupByContext.cs │ │ │ ├── GroupJoinContext.cs │ │ │ ├── HashSetContext.cs │ │ │ ├── IntContext.cs │ │ │ ├── JoinContext.cs │ │ │ ├── LinkedContext.cs │ │ │ ├── PredicateContext.cs │ │ │ ├── SelectContext.cs │ │ │ ├── SelectOptionContext.cs │ │ │ ├── SelectSlinqContext.cs │ │ │ ├── ZipAllContext.cs │ │ │ └── ZipContext.cs │ │ ├── Mutation │ │ │ ├── BacktrackDetector.cs │ │ │ ├── BacktrackException.cs │ │ │ └── Mutator.cs │ │ └── Simple │ │ │ ├── FuncContext.cs │ │ │ ├── FuncOptionContext.cs │ │ │ ├── IEnumerableContext.cs │ │ │ ├── IListContext.cs │ │ │ ├── LinkedListContext.cs │ │ │ └── OptionContext.cs │ ├── Slinq.cs │ ├── Slinqable.cs │ └── Test │ │ ├── DistinctLinq.cs │ │ ├── DistinctSlinq.cs │ │ ├── ExceptLinq.cs │ │ ├── ExceptSlinq.cs │ │ ├── GroupByLinq.cs │ │ ├── GroupBySlinq.cs │ │ ├── GroupJoinLinq.cs │ │ ├── GroupJoinSlinq.cs │ │ ├── IntersectLinq.cs │ │ ├── IntersectSlinq.cs │ │ ├── JoinLinq.cs │ │ ├── JoinSlinq.cs │ │ ├── OrderByLinq.cs │ │ ├── OrderBySlinq.cs │ │ ├── SlinqTest.cs │ │ ├── SlinqTest.unity │ │ ├── UnionLinq.cs │ │ ├── UnionSlinq.cs │ │ ├── WhereTakeSelectAggregateLinq.cs │ │ └── WhereTakeSelectAggregateSlinq.cs │ ├── __Foundations-Git-Readme.txt │ ├── __Foundations-License.txt │ └── __Foundations-Version.txt └── README.md /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | *.meta 3 | 4 | /* 5 | !/.gitignore 6 | !/Assets/ 7 | /Assets/* 8 | !/Assets/Smooth 9 | /Assets/Smooth/* 10 | !/Assets/Smooth/Foundations 11 | -------------------------------------------------------------------------------- /Assets/Smooth/Foundations/Algebraics/Either.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using Smooth.Collections; 4 | using Smooth.Delegates; 5 | 6 | namespace Smooth.Algebraics { 7 | /// 8 | /// Struct representing a value that can be an instance of either the L (left) or the R (right) type. 9 | /// 10 | [System.Serializable] 11 | public struct Either : IComparable>, IEquatable> { 12 | /// 13 | /// True if the either contains an L value; otherwise, false; 14 | /// 15 | public readonly bool isLeft; 16 | 17 | /// 18 | /// If the either isLeft, the value contained by the either; otherwise, default(L). 19 | /// 20 | public readonly L leftValue; 21 | 22 | /// 23 | /// If the either isRight, the value contained by the either; otherwise, default(R). 24 | /// 25 | public readonly R rightValue; 26 | 27 | /// 28 | /// True if the either contains an R value; otherwise, false; 29 | /// 30 | public bool isRight { get { return !isLeft; } } 31 | 32 | /// 33 | /// If the either isLeft, the an option containing the either's value; otherwise, an empty option. 34 | /// 35 | public Option leftOption { get { return isLeft ? new Option(leftValue) : new Option(); } } 36 | 37 | /// 38 | /// If the either isRight, the an option containing the either's value; otherwise, an empty option. 39 | /// 40 | public Option rightOption { get { return isLeft ? new Option() : new Option(rightValue); } } 41 | 42 | /// 43 | /// Returns a left either containing the specified value. 44 | /// 45 | /// Value. 46 | public static Either Left(L value) { 47 | return new Either(true, value, default(R)); 48 | } 49 | 50 | /// 51 | /// Returns a right either containing the specified value. 52 | /// 53 | /// Value. 54 | public static Either Right(R value) { 55 | return new Either(false, default(L), value); 56 | } 57 | 58 | private Either(bool isLeft, L leftValue, R rightValue) { 59 | this.isLeft = isLeft; 60 | this.leftValue = leftValue; 61 | this.rightValue = rightValue; 62 | } 63 | 64 | /// 65 | /// If the either isLeft, returns leftFunc applied to the either's value; otherwise, returns rightFunc applied to the either's value. 66 | /// 67 | public V Cata(DelegateFunc leftFunc, DelegateFunc rightFunc) { 68 | return isLeft ? leftFunc(leftValue) : rightFunc(rightValue); 69 | } 70 | 71 | /// 72 | /// If the either isLeft, returns leftFunc applied to the either's value and p; otherwise, returns rightFunc applied to the either's value. 73 | /// 74 | public V Cata(DelegateFunc leftFunc, P p, DelegateFunc rightFunc) { 75 | return isLeft ? leftFunc(leftValue, p) : rightFunc(rightValue); 76 | } 77 | 78 | /// 79 | /// If the either isLeft, returns leftFunc applied to the either's value; otherwise, returns rightFunc applied to the either's value and p2. 80 | /// 81 | public V Cata(DelegateFunc leftFunc, DelegateFunc rightFunc, P2 p2) { 82 | return isLeft ? leftFunc(leftValue) : rightFunc(rightValue, p2); 83 | } 84 | 85 | /// 86 | /// If the either isLeft, returns leftFunc applied to the either's value and p; otherwise, returns rightFunc applied to the either's value and p2. 87 | /// 88 | public V Cata(DelegateFunc leftFunc, P p, DelegateFunc rightFunc, P2 p2) { 89 | return isLeft ? leftFunc(leftValue, p) : rightFunc(rightValue, p2); 90 | } 91 | 92 | /// 93 | /// If the either isLeft, applies leftAction to the either's value; otherwise, applies rightAction to the either's value. 94 | /// 95 | public void ForEach(DelegateAction leftAction, DelegateAction rightAction) { 96 | if (isLeft) leftAction(leftValue); else rightAction(rightValue); 97 | } 98 | 99 | /// 100 | /// If the either isLeft, applies leftAction to the either's value and p; otherwise, applies rightAction to the either's value. 101 | /// 102 | public void ForEach

(DelegateAction leftAction, P p, DelegateAction rightAction) { 103 | if (isLeft) leftAction(leftValue, p); else rightAction(rightValue); 104 | } 105 | 106 | ///

107 | /// If the either isLeft, applies leftAction to the either's value; otherwise, applies rightAction to the either's value and p2. 108 | /// 109 | public void ForEach(DelegateAction leftAction, DelegateAction rightAction, P2 p2) { 110 | if (isLeft) leftAction(leftValue); else rightAction(rightValue, p2); 111 | } 112 | 113 | /// 114 | /// If the either isLeft, applies leftAction to the either's value and p; otherwise, applies rightAction to the either's value and p2. 115 | /// 116 | public void ForEach(DelegateAction leftAction, P p, DelegateAction rightAction, P2 p2) { 117 | if (isLeft) leftAction(leftValue, p); else rightAction(rightValue, p2); 118 | } 119 | 120 | public override bool Equals(object o) { 121 | return o is Either && this.Equals((Either) o); 122 | } 123 | 124 | public bool Equals(Either other) { 125 | return isLeft ? other.isLeft && Smooth.Collections.EqualityComparer.Default.Equals(leftValue, other.leftValue) : 126 | !other.isLeft && Smooth.Collections.EqualityComparer.Default.Equals(rightValue, other.rightValue); 127 | } 128 | 129 | public override int GetHashCode() { 130 | return isLeft ? Smooth.Collections.EqualityComparer.Default.GetHashCode(leftValue) : 131 | Smooth.Collections.EqualityComparer.Default.GetHashCode(rightValue); 132 | } 133 | 134 | public int CompareTo(Either other) { 135 | return isLeft ? (other.isLeft ? Smooth.Collections.Comparer.Default.Compare(leftValue, other.leftValue) : -1) : 136 | other.isLeft ? 1 : Smooth.Collections.Comparer.Default.Compare(rightValue, other.rightValue); 137 | } 138 | 139 | public static bool operator == (Either lhs, Either rhs) { 140 | return lhs.Equals(rhs); 141 | } 142 | 143 | public static bool operator != (Either lhs, Either rhs) { 144 | return !lhs.Equals(rhs); 145 | } 146 | 147 | public static bool operator > (Either lhs, Either rhs) { 148 | return lhs.CompareTo(rhs) > 0; 149 | } 150 | 151 | public static bool operator < (Either lhs, Either rhs) { 152 | return lhs.CompareTo(rhs) < 0; 153 | } 154 | 155 | public static bool operator >= (Either lhs, Either rhs) { 156 | return lhs.CompareTo(rhs) >= 0; 157 | } 158 | 159 | public static bool operator <= (Either lhs, Either rhs) { 160 | return lhs.CompareTo(rhs) <= 0; 161 | } 162 | 163 | public override string ToString() { 164 | return isLeft ? "[Left: " + leftValue + " ]" : "[Right: " + rightValue + " ]"; 165 | } 166 | } 167 | } 168 | -------------------------------------------------------------------------------- /Assets/Smooth/Foundations/Algebraics/Unit.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace Smooth.Algebraics { 4 | 5 | /// 6 | /// Represents a type that holds no information. Units have no state, and all instances of Unit are considered equal. 7 | /// 8 | public struct Unit : IComparable, IEquatable { 9 | public override bool Equals(object o) { return o is Unit; } 10 | 11 | public bool Equals(Unit other) { return true; } 12 | 13 | public override int GetHashCode() { return 0; } 14 | 15 | public int CompareTo(Unit other) { return 0; } 16 | 17 | public static bool operator == (Unit lhs, Unit rhs) { return true; } 18 | 19 | public static bool operator >= (Unit lhs, Unit rhs) { return true; } 20 | 21 | public static bool operator <= (Unit lhs, Unit rhs) { return true; } 22 | 23 | public static bool operator != (Unit lhs, Unit rhs) { return false; } 24 | 25 | public static bool operator > (Unit lhs, Unit rhs) { return false; } 26 | 27 | public static bool operator < (Unit lhs, Unit rhs) { return false; } 28 | 29 | public override string ToString() { return "Unit"; } 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /Assets/Smooth/Foundations/Collections/Comparer.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using Smooth.Compare; 4 | 5 | namespace Smooth.Collections { 6 | /// 7 | /// Analog to System.Collections.Generic.Comparer. 8 | /// 9 | public abstract class Comparer : IComparer { 10 | private static IComparer _default; 11 | 12 | public static IComparer Default { 13 | get { 14 | if (_default == null) { 15 | _default = Finder.Comparer(); 16 | } 17 | return _default; 18 | } 19 | set { _default = value; } 20 | } 21 | 22 | public abstract int Compare(T lhs, T rhs); 23 | } 24 | } -------------------------------------------------------------------------------- /Assets/Smooth/Foundations/Collections/CreateWithComparer.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | 4 | namespace Smooth.Collections { 5 | 6 | #region Dictionary 7 | 8 | /// 9 | /// Helper class for instantiating Dictionary<>s without specifying a comparer. 10 | /// 11 | public static class Dictionary { 12 | 13 | /// 14 | /// Creates a new dictionary with the default comparer. 15 | /// 16 | public static Dictionary Create() { 17 | return new Dictionary(Smooth.Collections.EqualityComparer.Default); 18 | } 19 | 20 | /// 21 | /// Creates a new dictionary with the default comparer and the specified initial capacity. 22 | /// 23 | public static Dictionary Create(int capacity) { 24 | return new Dictionary(capacity, Smooth.Collections.EqualityComparer.Default); 25 | } 26 | 27 | /// 28 | /// Creates a new dictionary with the default comparer and elements copied from the specified dictionary. 29 | /// 30 | public static Dictionary Create(IDictionary dictionary) { 31 | return new Dictionary(dictionary, Smooth.Collections.EqualityComparer.Default); 32 | } 33 | 34 | } 35 | 36 | #endregion 37 | 38 | #region HashSet 39 | 40 | /// 41 | /// Helper class for instantiating HashSet<>s without specifying a comparer. 42 | /// 43 | public static class HashSet { 44 | 45 | /// 46 | /// Creates a new hash set with the default comparer. 47 | /// 48 | public static HashSet Create() { 49 | return new HashSet(Smooth.Collections.EqualityComparer.Default); 50 | } 51 | 52 | /// 53 | /// Creates a new hash set with the default comparer and elements copied from the specified collection. 54 | /// 55 | public static HashSet Create(IEnumerable collection) { 56 | return new HashSet(collection, Smooth.Collections.EqualityComparer.Default); 57 | } 58 | 59 | } 60 | 61 | #endregion 62 | 63 | #region SortedDictionary 64 | 65 | /// 66 | /// Helper class for instantiating SortedDictionary<>s without specifying a comparer. 67 | /// 68 | public static class SortedDictionary { 69 | 70 | /// 71 | /// Creates a new sorted dictionary with the default comparer. 72 | /// 73 | public static SortedDictionary Create() { 74 | return new SortedDictionary(Smooth.Collections.Comparer.Default); 75 | } 76 | 77 | /// 78 | /// Creates a new sorted dictionary with the default comparer and elements copied from the specified dictionary. 79 | /// 80 | public static SortedDictionary Create(IDictionary dictionary) { 81 | return new SortedDictionary(dictionary, Smooth.Collections.Comparer.Default); 82 | } 83 | 84 | } 85 | 86 | #endregion 87 | 88 | #region SortedList 89 | 90 | /// 91 | /// Helper class for instantiating SortedList<>s without specifying a comparer. 92 | /// 93 | public static class SortedList { 94 | 95 | /// 96 | /// Creates a new sorted list with the default comparer. 97 | /// 98 | public static SortedList Create() { 99 | return new SortedList(Smooth.Collections.Comparer.Default); 100 | } 101 | 102 | /// 103 | /// Creates a new sorted list with the default comparer and the specified initial capacity. 104 | /// 105 | public static SortedList Create(int capacity) { 106 | return new SortedList(capacity, Smooth.Collections.Comparer.Default); 107 | } 108 | 109 | /// 110 | /// Creates a new sorted list with the default comparer and elements copied from the specified dictionary. 111 | /// 112 | public static SortedList Create(IDictionary dictionary) { 113 | return new SortedList(dictionary, Smooth.Collections.Comparer.Default); 114 | } 115 | } 116 | 117 | #endregion 118 | 119 | } 120 | -------------------------------------------------------------------------------- /Assets/Smooth/Foundations/Collections/EqualityComparer.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using Smooth.Compare; 4 | 5 | namespace Smooth.Collections { 6 | /// 7 | /// Analog to System.Collections.Generic.EqualityComparer. 8 | /// 9 | public abstract class EqualityComparer : IEqualityComparer { 10 | private static IEqualityComparer _default; 11 | 12 | public static IEqualityComparer Default { 13 | get { 14 | if (_default == null) { 15 | _default = Finder.EqualityComparer(); 16 | } 17 | return _default; 18 | } 19 | set { _default = value; } 20 | } 21 | 22 | public abstract bool Equals(T lhs, T rhs); 23 | 24 | public abstract int GetHashCode(T t); 25 | } 26 | } -------------------------------------------------------------------------------- /Assets/Smooth/Foundations/Collections/FuncEnumerable.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using Smooth.Algebraics; 4 | using Smooth.Delegates; 5 | 6 | namespace Smooth.Collections { 7 | /// 8 | /// Enumerable that contains the elements defined by a seed value and step function. 9 | /// 10 | public class FuncEnumerable : IEnumerable { 11 | private readonly T seed; 12 | private readonly Either, DelegateFunc>> step; 13 | 14 | private FuncEnumerable() {} 15 | 16 | public FuncEnumerable(T seed, DelegateFunc step) { 17 | this.seed = seed; 18 | this.step = Either, DelegateFunc>>.Left(step); 19 | } 20 | 21 | public FuncEnumerable(T seed, DelegateFunc> step) { 22 | this.seed = seed; 23 | this.step = Either, DelegateFunc>>.Right(step); 24 | } 25 | 26 | public IEnumerator GetEnumerator() { 27 | if (step.isLeft) { 28 | var current = seed; 29 | while (true) { 30 | yield return current; 31 | current = step.leftValue(current); 32 | } 33 | } else { 34 | var current = new Option(seed); 35 | while (current.isSome) { 36 | yield return current.value; 37 | current = step.rightValue(current.value); 38 | } 39 | } 40 | } 41 | 42 | System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() { return GetEnumerator(); } 43 | } 44 | 45 | /// 46 | /// Enumerable that contains the elements defined by a seed value and step function. 47 | /// 48 | public class FuncEnumerable : IEnumerable { 49 | private readonly T seed; 50 | private readonly Either, DelegateFunc>> step; 51 | private readonly P parameter; 52 | 53 | private FuncEnumerable() {} 54 | 55 | public FuncEnumerable(T seed, DelegateFunc step, P parameter) { 56 | this.seed = seed; 57 | this.step = Either, DelegateFunc>>.Left(step); 58 | this.parameter = parameter; 59 | } 60 | 61 | public FuncEnumerable(T seed, DelegateFunc> step, P parameter) { 62 | this.seed = seed; 63 | this.step = Either, DelegateFunc>>.Right(step); 64 | this.parameter = parameter; 65 | } 66 | 67 | public IEnumerator GetEnumerator() { 68 | if (step.isLeft) { 69 | var current = seed; 70 | while (true) { 71 | yield return current; 72 | current = step.leftValue(current, parameter); 73 | } 74 | } else { 75 | var current = new Option(seed); 76 | while (current.isSome) { 77 | yield return current.value; 78 | current = step.rightValue(current.value, parameter); 79 | } 80 | } 81 | } 82 | 83 | System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() { return GetEnumerator(); } 84 | } 85 | } 86 | -------------------------------------------------------------------------------- /Assets/Smooth/Foundations/Collections/ICollectionExtensions.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | 4 | namespace Smooth.Collections { 5 | 6 | /// 7 | /// Extension methods for ICollection<>s. 8 | /// 9 | public static class ICollectionExtensions { 10 | 11 | #region AddAll 12 | 13 | /// 14 | /// Adds the specified values to and returns the specific collection. 15 | /// 16 | public static IC AddAll(this IC collection, params T[] values) where IC : ICollection { 17 | for (int i = 0; i < values.Length; ++i) { 18 | collection.Add(values[i]); 19 | } 20 | return collection; 21 | } 22 | 23 | /// 24 | /// Adds the specified values to and returns the specific collection. 25 | /// 26 | public static IC AddAll(this IC collection, IList values) where IC : ICollection { 27 | for (int i = 0; i < values.Count; ++i) { 28 | collection.Add(values[i]); 29 | } 30 | return collection; 31 | } 32 | 33 | /// 34 | /// Adds the specified values to and returns the specific collection. 35 | /// 36 | public static IC AddAll(this IC collection, IEnumerable values) where IC : ICollection { 37 | foreach (var value in values) { 38 | collection.Add(value); 39 | } 40 | return collection; 41 | } 42 | 43 | #endregion 44 | 45 | } 46 | 47 | } 48 | -------------------------------------------------------------------------------- /Assets/Smooth/Foundations/Collections/IDictionaryExtensions.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using Smooth.Algebraics; 4 | 5 | namespace Smooth.Collections { 6 | 7 | /// 8 | /// Extension methods for IDictionary<>s. 9 | /// 10 | public static class IDictionaryExtensions { 11 | 12 | /// 13 | /// Analog to IDictionary<K, V>.TryGetValue(K, out V) that returns an option instead of using an out parameter. 14 | /// 15 | public static Option TryGet(this IDictionary dictionary, K key) { 16 | V value; 17 | return dictionary.TryGetValue(key, out value) ? new Option(value) : new Option(); 18 | } 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /Assets/Smooth/Foundations/Collections/IListExtensions.cs: -------------------------------------------------------------------------------- 1 | using UnityEngine; 2 | using System; 3 | using System.Collections.Generic; 4 | using Smooth.Algebraics; 5 | using Smooth.Comparisons; 6 | 7 | namespace Smooth.Collections { 8 | 9 | /// 10 | /// Extension methods for IList<>s. 11 | /// 12 | public static class IListExtensions { 13 | 14 | #region Randomize 15 | 16 | /// 17 | /// If the specified list is empty, returns an empty option; otherwise, returns an option containing a random element from the specified list. 18 | /// 19 | public static Option Random(this IList list) { 20 | return list.Count == 0 ? Option.None : new Option(list[UnityEngine.Random.Range(0, list.Count)]); 21 | } 22 | 23 | /// 24 | /// Shuffles the element order of the specified list. 25 | /// 26 | public static void Shuffle(this IList ts) { 27 | var count = ts.Count; 28 | var last = count - 1; 29 | for (var i = 0; i < last; ++i) { 30 | var r = UnityEngine.Random.Range(i, count); 31 | var tmp = ts[i]; 32 | ts[i] = ts[r]; 33 | ts[r] = tmp; 34 | } 35 | } 36 | 37 | #endregion 38 | 39 | #region Sort 40 | 41 | /// 42 | /// Sorts the specified list using an insertion sort algorithm and the default sort comparer for T. 43 | /// 44 | /// 45 | /// Insertion sort is a O(n²) time complexity algorithm and should not be used on arbitrary lists. 46 | /// However, it has a best case time complexity of O(n) for lists that are already sorted and is quite fast when used on nearly sorted input. 47 | /// 48 | public static void InsertionSort(this IList ts) { 49 | InsertionSort(ts, Comparisons.Default); 50 | } 51 | 52 | /// 53 | /// Sorts the specified list using an insertion sort algorithm and the specified comparer. 54 | /// 55 | /// 56 | /// Insertion sort is a O(n²) time complexity algorithm and should not be used on arbitrary lists. 57 | /// However, it has a best case time complexity of O(n) for lists that are already sorted and is quite fast when used on nearly sorted input. 58 | /// 59 | public static void InsertionSort(this IList ts, IComparer comparer) { 60 | InsertionSort(ts, Comparisons.ToComparison(comparer)); 61 | } 62 | 63 | /// 64 | /// Sorts the specified list using an insertion sort algorithm and the specified comparison. 65 | /// 66 | /// 67 | /// Insertion sort is a O(n²) time complexity algorithm and should not be used on arbitrary lists. 68 | /// However, it has a best case time complexity of O(n) for lists that are already sorted and is quite fast when used on nearly sorted input. 69 | /// 70 | public static void InsertionSort(this IList ts, Comparison comparison) { 71 | for (int right = 1; right < ts.Count; ++right) { 72 | var insert = ts[right]; 73 | var left = right - 1; 74 | while (left >= 0 && comparison(ts[left], insert) > 0) { 75 | ts[left + 1] = ts[left]; 76 | --left; 77 | } 78 | ts[left + 1] = insert; 79 | } 80 | } 81 | 82 | #endregion 83 | 84 | } 85 | } 86 | -------------------------------------------------------------------------------- /Assets/Smooth/Foundations/Collections/IListStepper.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using Smooth.Algebraics; 4 | 5 | namespace Smooth.Collections { 6 | /// 7 | /// Helper class for enuemrating the elements of an IList using a start index and step value. 8 | /// 9 | public class IListStepper : IEnumerable { 10 | private readonly IList list; 11 | private readonly int startIndex; 12 | private readonly int step; 13 | 14 | private IListStepper() {} 15 | 16 | public IListStepper(IList list, int startIndex, int step) { 17 | this.list = list; 18 | this.startIndex = startIndex; 19 | this.step = step; 20 | } 21 | 22 | public IEnumerator GetEnumerator() { 23 | for (int i = startIndex; 0 <= i && i < list.Count; i += step) { 24 | yield return list[i]; 25 | } 26 | } 27 | 28 | System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() { return GetEnumerator(); } 29 | } 30 | 31 | /// 32 | /// Helper class for enuemrating the element, index pairs of an IList using a start index and step value. 33 | /// 34 | public class IListStepperWithIndex : IEnumerable> { 35 | private readonly IList list; 36 | private readonly int startIndex; 37 | private readonly int step; 38 | 39 | private IListStepperWithIndex() {} 40 | 41 | public IListStepperWithIndex(IList list, int startIndex, int step) { 42 | this.list = list; 43 | this.startIndex = startIndex; 44 | this.step = step; 45 | } 46 | 47 | public IEnumerator> GetEnumerator() { 48 | for (int i = startIndex; 0 <= i && i < list.Count; i += step) { 49 | yield return new Tuple(list[i], i); 50 | } 51 | } 52 | 53 | System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() { return GetEnumerator(); } 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /Assets/Smooth/Foundations/Collections/InspectorKeyValuePair.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | 4 | /// 5 | /// Class based key value pair for use in inspector lists and arrays. 6 | /// 7 | [System.Serializable] 8 | public abstract class InspectorKeyValuePair { 9 | public K key; 10 | public V value; 11 | 12 | public InspectorKeyValuePair() {} 13 | 14 | public InspectorKeyValuePair(K key, V value) { 15 | this.key = key; 16 | this.value = value; 17 | } 18 | 19 | public KeyValuePair ToKeyValuePair() { 20 | return new KeyValuePair(key, value); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /Assets/Smooth/Foundations/Collections/LinkedListStepper.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | 4 | namespace Smooth.Collections { 5 | /// 6 | /// Helper class for enuemrating the values in a LinkedList using a start node and step value. 7 | /// 8 | public class LinkedListStepper : IEnumerable { 9 | private readonly LinkedListNode startNode; 10 | private readonly int step; 11 | 12 | private LinkedListStepper() {} 13 | 14 | public LinkedListStepper(LinkedListNode startNode, int step) { 15 | this.startNode = startNode; 16 | this.step = step; 17 | } 18 | 19 | public IEnumerator GetEnumerator() { 20 | var node = startNode; 21 | 22 | while (node != null) { 23 | yield return node.Value; 24 | 25 | var step = this.step; 26 | while (step > 0 && node != null) { 27 | node = node.Next; 28 | --step; 29 | } 30 | while (step < 0 && node != null) { 31 | node = node.Previous; 32 | ++step; 33 | } 34 | } 35 | } 36 | 37 | System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() { return GetEnumerator(); } 38 | } 39 | 40 | /// 41 | /// Helper class for enuemrating the nodes in a LinkedList using a start node and step value. 42 | /// 43 | public class LinkedListStepperNodes : IEnumerable> { 44 | private readonly LinkedListNode startNode; 45 | private readonly int step; 46 | 47 | private LinkedListStepperNodes() {} 48 | 49 | public LinkedListStepperNodes(LinkedListNode startNode, int step) { 50 | this.startNode = startNode; 51 | this.step = step; 52 | } 53 | 54 | public IEnumerator> GetEnumerator() { 55 | var node = startNode; 56 | 57 | while (node != null) { 58 | yield return node; 59 | 60 | var step = this.step; 61 | while (step > 0 && node != null) { 62 | node = node.Next; 63 | --step; 64 | } 65 | while (step < 0 && node != null) { 66 | node = node.Previous; 67 | ++step; 68 | } 69 | } 70 | } 71 | 72 | System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() { return GetEnumerator(); } 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /Assets/Smooth/Foundations/Compare/Comparers/EnumComparers.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Runtime.InteropServices; 4 | using Smooth.Collections; 5 | 6 | namespace Smooth.Compare.Comparers { 7 | /// 8 | /// Fast, allocation free equality comparer for blittable structs with an underlying size of 32 bits or less. 9 | /// 10 | public class Blittable32EqualityComparer : Smooth.Collections.EqualityComparer { 11 | public override bool Equals(T t1, T t2) { 12 | Converter converter; 13 | converter.value = 0; 14 | converter.t = t1; 15 | var v1 = converter.value; 16 | converter.t = t2; 17 | return v1 == converter.value; 18 | } 19 | 20 | public override int GetHashCode(T t) { 21 | Converter converter; 22 | converter.value = 0; 23 | converter.t = t; 24 | return converter.value; 25 | } 26 | 27 | [StructLayout(LayoutKind.Explicit)] 28 | internal struct Converter 29 | { 30 | [FieldOffset(0)] 31 | public T t; 32 | 33 | [FieldOffset(0)] 34 | public Int32 value; 35 | } 36 | } 37 | 38 | /// 39 | /// Fast, allocation free equality comparer for blittable structs with an underlying size of 64 bits or less. 40 | /// 41 | public class Blittable64EqualityComparer : Smooth.Collections.EqualityComparer { 42 | public override bool Equals(T t1, T t2) { 43 | Converter converter; 44 | converter.value = 0; 45 | converter.t = t1; 46 | var v1 = converter.value; 47 | converter.t = t2; 48 | return v1 == converter.value; 49 | } 50 | 51 | public override int GetHashCode(T t) { 52 | Converter converter; 53 | converter.value = 0; 54 | converter.t = t; 55 | return converter.value.GetHashCode(); 56 | } 57 | 58 | [StructLayout(LayoutKind.Explicit)] 59 | internal struct Converter 60 | { 61 | [FieldOffset(0)] 62 | public T t; 63 | 64 | [FieldOffset(0)] 65 | public Int64 value; 66 | } 67 | } 68 | 69 | // /// 70 | // /// Fast, allocation free IEqualityComparer for Enums that uses System.Reflection.Emit to create JIT complied equality and hashCode functions. 71 | // /// 72 | // /// Note: This class isn't any faster than Blittable32EqualityComparer or Blittable64EqualityComparer and doesn't work on platforms without JIT complilation. 73 | // /// 74 | // /// It is provided simply as example code. 75 | // /// 76 | // public class EnumEmitEqualityComparer : Smooth.Collections.EqualityComparer { 77 | // private readonly Func equals; 78 | // private readonly Func hashCode; 79 | // 80 | // public EnumEmitEqualityComparer() { 81 | // var type = typeof(T); 82 | // 83 | // if (type.IsEnum) { 84 | // var l = Expression.Parameter(type, "l"); 85 | // var r = Expression.Parameter(type, "r"); 86 | // 87 | // this.equals = Expression.Lambda>(Expression.Equal(l, r), l, r).Compile(); 88 | // 89 | // switch (Type.GetTypeCode(type)) { 90 | // case TypeCode.Int64: 91 | // case TypeCode.UInt64: 92 | // this.hashCode = Expression.Lambda>(Expression.Call(Expression.Convert(l, typeof(Int64)), typeof(Int64).GetMethod("GetHashCode")), l).Compile(); 93 | // break; 94 | // default: 95 | // this.hashCode = Expression.Lambda>(Expression.Convert(l, typeof(Int32)), l).Compile(); 96 | // break; 97 | // } 98 | // } else { 99 | // throw new ArgumentException(GetType().Name + " can only be used with enum types."); 100 | // } 101 | // } 102 | // 103 | // public override bool Equals(T t1, T t2) { 104 | // return equals(t1, t2); 105 | // } 106 | // 107 | // public override int GetHashCode(T t) { 108 | // return hashCode(t); 109 | // } 110 | // } 111 | } 112 | -------------------------------------------------------------------------------- /Assets/Smooth/Foundations/Compare/Comparers/KeyValuePairComparers.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using Smooth.Collections; 4 | 5 | namespace Smooth.Compare.Comparers { 6 | /// 7 | /// Allocation free sort order comparer for KeyValuePairs. 8 | /// 9 | public class KeyValuePairComparer : Smooth.Collections.Comparer> { 10 | public override int Compare(KeyValuePair l, KeyValuePair r) { 11 | var c = Smooth.Collections.Comparer.Default.Compare(l.Key, r.Key); 12 | return c == 0 ? Smooth.Collections.Comparer.Default.Compare(l.Value, r.Value) : c; 13 | } 14 | } 15 | 16 | /// 17 | /// Allocation free equality comparer for KeyValuePairs. 18 | /// 19 | public class KeyValuePairEqualityComparer : Smooth.Collections.EqualityComparer> { 20 | public override bool Equals(KeyValuePair l, KeyValuePair r) { 21 | return Smooth.Collections.EqualityComparer.Default.Equals(l.Key, r.Key) && 22 | Smooth.Collections.EqualityComparer.Default.Equals(l.Value, r.Value); 23 | } 24 | 25 | public override int GetHashCode(KeyValuePair kvp) { 26 | unchecked { 27 | int hash = 17; 28 | hash = 29 * hash + Smooth.Collections.EqualityComparer.Default.GetHashCode(kvp.Key); 29 | hash = 29 * hash + Smooth.Collections.EqualityComparer.Default.GetHashCode(kvp.Value); 30 | return hash; 31 | } 32 | } 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /Assets/Smooth/Foundations/Compare/Configuration.cs: -------------------------------------------------------------------------------- 1 | using UnityEngine; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Runtime; 5 | using Smooth.Algebraics; 6 | using Smooth.Collections; 7 | using Smooth.Compare.Comparers; 8 | using Smooth.Platform; 9 | 10 | namespace Smooth.Compare { 11 | /// 12 | /// Configuration class for Smooth.Compare. 13 | /// 14 | /// To supply a custom configuration, simply add a class to your project called Smooth.Compare.CustomConfiguration that inherits from this type. 15 | /// 16 | /// If a custom configuration exists, it will override the the default configuration. 17 | /// 18 | /// Note: Don't edit this class directly, as it may get updated in future versions of Smooth.Compare. 19 | /// 20 | public class Configuration { 21 | /// 22 | /// Default constructor that simply adds a listener to Finder.OnEvent. 23 | /// 24 | /// If you supply a custom configuration, don't register types or do any comparsions from the constructor as the finder will not be fully initialized yet. 25 | /// 26 | public Configuration() { 27 | Finder.OnEvent.Handle += HandleFinderEvent; 28 | } 29 | 30 | /// 31 | /// Method called by the finder to set up registrations before any comparer requests are handled. 32 | /// 33 | /// If you supply a custom configuration and want to apply the default registrations, add a call to base.RegisterComparers() from your method override. 34 | /// 35 | public virtual void RegisterComparers() { 36 | #region Common structs without type specific equality and/or hashcode methods 37 | 38 | Finder.Register((a, b) => Color32ToInt(a) == Color32ToInt(b), Color32ToInt); 39 | 40 | #endregion 41 | 42 | #region Basic types for platforms without JIT compilation 43 | 44 | if (NoJit) { 45 | // 46 | // Note: On non-JIT platforms, you must be careful to not get too cute / abstract with your registrations or the AOT may not create 47 | // all the necessary generic types and you'll end up with JIT exceptions. When in doubt, add each registration directly with a 48 | // individual method call the compiler can easily discover with static inspection, and if supplying your own comparer 49 | // implementation either inherit from the corresponding Smooth.Collections.Comparer or wrap your comparer in a FuncComparer to 50 | // force the compiler to create the proper types. 51 | // 52 | 53 | #region System built-in types 54 | 55 | Finder.RegisterIComparableIEquatable(); 56 | 57 | Finder.RegisterIComparableIEquatable(); 58 | 59 | Finder.RegisterIComparableIEquatable(); 60 | Finder.RegisterIComparableIEquatable(); 61 | 62 | Finder.RegisterIComparableIEquatable(); 63 | Finder.RegisterIComparableIEquatable(); 64 | 65 | Finder.RegisterIComparableIEquatable(); 66 | Finder.RegisterIComparableIEquatable(); 67 | 68 | Finder.RegisterIComparableIEquatable(); 69 | Finder.RegisterIComparableIEquatable(); 70 | 71 | Finder.RegisterIComparableIEquatable(); 72 | Finder.RegisterIComparableIEquatable(); 73 | 74 | Finder.RegisterIComparableIEquatable(); 75 | 76 | #endregion 77 | 78 | #region System.Runtime handles 79 | 80 | Finder.Register((a, b) => a.Equals(b)); 81 | Finder.Register((a, b) => a == b); 82 | Finder.Register((a, b) => a == b); 83 | 84 | #endregion 85 | 86 | #region UnityEngine structs 87 | 88 | // 89 | // Note: UnityEngine structs do not adhere to the contract of equality. 90 | // 91 | // Thus they should not be used as Dictionary keys or in other use cases that rely on a correct equality implementation. 92 | // 93 | 94 | Finder.Register((a, b) => a == b); 95 | 96 | Finder.Register((a, b) => a == b); 97 | Finder.Register((a, b) => a == b); 98 | Finder.Register((a, b) => a == b); 99 | 100 | Finder.Register((a, b) => a == b); 101 | 102 | #endregion 103 | 104 | #region UnityEngine enums 105 | 106 | Finder.RegisterEnum(); 107 | Finder.RegisterEnum(); 108 | Finder.RegisterEnum(); 109 | Finder.RegisterEnum(); 110 | Finder.RegisterEnum(); 111 | Finder.RegisterEnum(); 112 | 113 | #endregion 114 | 115 | #region Smooth enums 116 | 117 | Finder.RegisterEnum(); 118 | Finder.RegisterEnum(); 119 | Finder.RegisterEnum(); 120 | 121 | #endregion 122 | } 123 | 124 | #endregion 125 | } 126 | 127 | /// 128 | /// Listens for finder events which are useful for finding potential comparison problems. 129 | /// 130 | /// The default implementation logs warnings on registration collisions, the use of inefficient or invalid comparers, and unregistered find requests for value types if JIT is disabled. 131 | /// 132 | public virtual void HandleFinderEvent(ComparerType comparerType, EventType eventType, Type type) { 133 | switch (eventType) { 134 | case EventType.FindUnregistered: 135 | if (NoJit && type.IsValueType) { 136 | Debug.LogWarning("A " + comparerType.ToStringCached() + " has been requested for a non-registered value type with JIT disabled, this is a fragile operation and may result in a JIT exception.\nType:" + type.FullName); 137 | } 138 | break; 139 | case EventType.InefficientDefault: 140 | Debug.LogWarning("A " + comparerType.ToStringCached() + " has been requested that will perform inefficient comparisons and/or cause boxing allocations.\nType:" + type.FullName); 141 | break; 142 | case EventType.InvalidDefault: 143 | Debug.LogWarning("A " + comparerType.ToStringCached() + " has been requested for a non-comparable type. Using the comparer will cause exceptions.\nType:" + type.FullName); 144 | break; 145 | case EventType.AlreadyRegistered: 146 | Debug.LogWarning("Tried to register a " + comparerType.ToStringCached() + " over an existing registration.\nType: " + type.FullName); 147 | break; 148 | default: 149 | break; 150 | } 151 | } 152 | 153 | /// 154 | /// This can be used to override the platform setting and enable or disable automatic comparer creation, which can be quite useful while testing in different environments. 155 | /// 156 | public virtual bool UseJit { get { return Runtime.hasJit; } } 157 | 158 | /// 159 | /// Convenience method for !UseJit. 160 | /// 161 | public bool NoJit { get { return !UseJit; } } 162 | 163 | /// 164 | /// If JIT is enabled, this method is called by the finder when it is asked to supply a sort order comparer for an unregistered, non-IComparable type. 165 | /// 166 | /// If you want to write custom comparers using reflection, you can do so by overriding this method. 167 | /// 168 | /// An option containing a sort order comparer for type T, or None to use the default comparer 169 | public virtual Option> Comparer() { 170 | return Factory.Comparer(); 171 | } 172 | 173 | /// 174 | /// If JIT is enabled, this method is called by the finder when it is asked to supply an equality comparer for an unregistered, non-IEquatable type.. 175 | /// 176 | /// If you want to write custom equality comparers using reflection, you can do so by overriding this method. 177 | /// 178 | /// An option containing an equality comparer for type T, or None to use the default comparer 179 | public virtual Option> EqualityComparer() { 180 | return Factory.EqualityComparer(); 181 | } 182 | 183 | /// 184 | /// Converts a 32-bit color to a 32-bit integer without loss of information 185 | /// 186 | public static int Color32ToInt(Color32 c) { 187 | return (c.r << 24) | (c.g << 16) | (c.b << 8) | c.a; 188 | } 189 | } 190 | } 191 | -------------------------------------------------------------------------------- /Assets/Smooth/Foundations/Compare/Events.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace Smooth.Compare { 4 | public enum ComparerType { 5 | None = 0, 6 | Comparer, 7 | EqualityComparer, 8 | } 9 | 10 | public enum EventType { 11 | None = 0, 12 | Registered, 13 | AlreadyRegistered, 14 | FindRegistered, 15 | FindUnregistered, 16 | EfficientDefault, 17 | InefficientDefault, 18 | InvalidDefault, 19 | CustomJit, 20 | FactoryJit, 21 | } 22 | 23 | public static class EventExtensions { 24 | public static string ToStringCached(this ComparerType comparerType) { 25 | switch (comparerType) { 26 | case ComparerType.Comparer: 27 | return "Sort Order Comparer"; 28 | case ComparerType.EqualityComparer: 29 | return "Equality Comparer"; 30 | default: 31 | return "Unknown"; 32 | } 33 | } 34 | } 35 | } -------------------------------------------------------------------------------- /Assets/Smooth/Foundations/Compare/Examples/ExampleConfiguration.cs: -------------------------------------------------------------------------------- 1 | using UnityEngine; 2 | using System; 3 | using System.Collections.Generic; 4 | using Smooth.Collections; 5 | using Smooth.Compare; 6 | using Smooth.Compare.Comparers; 7 | 8 | 9 | // 10 | // 11 | // Example CustomConfiguration for Smooth.Compare. 12 | // 13 | // 14 | 15 | 16 | //namespace Smooth.Compare { 17 | // public class CustomConfiguration : Configuration { 18 | // private bool hasRegistered; 19 | // 20 | // public override void RegisterComparers() { 21 | // if (NoJit) { 22 | // // 23 | // // If running without JIT, register the KeyValuePair<,> comparers that we use. 24 | // // 25 | // // These are handled automatically by the factory if JIT is enabled. 26 | // // 27 | // Finder.RegisterKeyValuePair(); 28 | // Finder.RegisterKeyValuePair(); 29 | // Finder.RegisterKeyValuePair>(); 30 | // 31 | // // 32 | // // If running without JIT, register the JITable comparers that we use. 33 | // // 34 | // Finder.RegisterIComparableIEquatable(); 35 | // Finder.Register((a, b) => a.Equals(b)); 36 | // } 37 | // 38 | // // 39 | // // Register sort order comparers for types that don't implement the IComparable<> and equality comparers for value types that don't provide type specific equality checks. 40 | // // 41 | // Finder.Register((a, b) => string.Compare(a.name, b.name)); 42 | // Finder.Register((a, b) => string.Compare(a.name, b.name), (a, b) => a.id == b.id); 43 | // Finder.Register((a, b) => string.Compare(a.name, b.name)); 44 | // 45 | // // 46 | // // Register the standard comparers. 47 | // // 48 | // base.RegisterComparers(); 49 | // 50 | // hasRegistered = true; 51 | // } 52 | // 53 | // public override void HandleFinderEvent(ComparerType comparerType, EventType eventType, Type type) { 54 | // // 55 | // // Log all registrations by other classes for debugging purposes. 56 | // // 57 | // if (hasRegistered && eventType == EventType.Registered) { 58 | // Debug.Log(comparerType.ToStringCached() + " registered for type " + type.FullName); 59 | // } 60 | // 61 | // base.HandleFinderEvent(comparerType, eventType, type); 62 | // } 63 | // 64 | // // 65 | // // Manually disable JIT when running iOS builds in the editor and we want to find potential JIT problems. 66 | // // 67 | // //public override bool UseJit { get { return false; } } 68 | // 69 | // // 70 | // // Manually enable JIT when running iOS builds in a simulator and we want to test functionality and worry about comparers later. 71 | // // 72 | // //public override bool UseJit { get { return true; } } 73 | // } 74 | // 75 | // public struct ExampleStruct1 : IEquatable, IComparable { 76 | // public uint id; 77 | // public string name; 78 | // 79 | // public override bool Equals(object o) { 80 | // return o is ExampleStruct1 && this.Equals((ExampleStruct1) o); 81 | // } 82 | // 83 | // public bool Equals(ExampleStruct1 other) { 84 | // // Note: Only compares ids, but the sort comparer uses names. 85 | // // To properly adhere to the contract of equality, a.id == b.id must imply a.name == b.name. 86 | // return this.id == other.id; 87 | // } 88 | // 89 | // public override int GetHashCode() { 90 | // return (int) id; 91 | // } 92 | // 93 | // public int CompareTo(ExampleStruct1 other) { 94 | // return string.Compare(this.name, other.name); 95 | // } 96 | // 97 | // public static bool operator == (ExampleStruct1 lhs, ExampleStruct1 rhs) { 98 | // return lhs.Equals(rhs); 99 | // } 100 | // 101 | // public static bool operator != (ExampleStruct1 lhs, ExampleStruct1 rhs) { 102 | // return !lhs.Equals(rhs); 103 | // } 104 | // 105 | // public static bool operator > (ExampleStruct1 lhs, ExampleStruct1 rhs) { 106 | // return lhs.CompareTo(rhs) > 0; 107 | // } 108 | // 109 | // public static bool operator < (ExampleStruct1 lhs, ExampleStruct1 rhs) { 110 | // return lhs.CompareTo(rhs) < 0; 111 | // } 112 | // 113 | // public static bool operator >= (ExampleStruct1 lhs, ExampleStruct1 rhs) { 114 | // return lhs.CompareTo(rhs) >= 0; 115 | // } 116 | // 117 | // public static bool operator <= (ExampleStruct1 lhs, ExampleStruct1 rhs) { 118 | // return lhs.CompareTo(rhs) <= 0; 119 | // } 120 | // 121 | // public override string ToString() { 122 | // return name; 123 | // } 124 | // } 125 | // 126 | // public struct ExampleStruct2 { 127 | // // 128 | // // The same thing as ExampleStruct1, but doesn't implement the comparable interfaces or provide a type specific == operator. 129 | // // 130 | // 131 | // public uint id; 132 | // public string name; 133 | // 134 | // public override bool Equals(object o) { 135 | // return o is ExampleStruct2 && this.Equals((ExampleStruct2) o); 136 | // } 137 | // 138 | // public bool Equals(ExampleStruct2 other) { 139 | // return this.id == other.id; 140 | // } 141 | // 142 | // public override int GetHashCode() { 143 | // return (int) id; 144 | // } 145 | // 146 | // public override string ToString() { 147 | // return name; 148 | // } 149 | // } 150 | // 151 | // public struct ExampleStruct3 { 152 | // // 153 | // // The same thing as ExampleStruct1, but doesn't override Equals(object) or have a type specific equals method. 154 | // // 155 | // // Thus we use a priori knowledge about the type to make allocation free equality comparisons. 156 | // // 157 | // 158 | // public uint id; 159 | // public string name; 160 | // 161 | // public override int GetHashCode() { 162 | // return (int) id; 163 | // } 164 | // 165 | // public override string ToString() { 166 | // return name; 167 | // } 168 | // } 169 | // 170 | // public class ExampleClass { 171 | // // 172 | // // Class version of ExampleStruct, without a type specific equals method. 173 | // // 174 | // // Equality comparisons won't box / allocate, but we still want to register a sort order comparer. 175 | // // 176 | // 177 | // public uint id; 178 | // public string name; 179 | // 180 | // public override bool Equals(object o) { 181 | // return o is ExampleClass && this.id == ((ExampleClass) o).id; 182 | // } 183 | // 184 | // public override int GetHashCode() { 185 | // return (int) id; 186 | // } 187 | // 188 | // public override string ToString() { 189 | // return name; 190 | // } 191 | // } 192 | //} 193 | -------------------------------------------------------------------------------- /Assets/Smooth/Foundations/Compare/Factory.cs: -------------------------------------------------------------------------------- 1 | using UnityEngine; 2 | using System; 3 | using System.Collections; 4 | using System.Collections.Generic; 5 | using System.Linq; 6 | using System.Linq.Expressions; 7 | using System.Reflection; 8 | using Smooth.Algebraics; 9 | using Smooth.Collections; 10 | using Smooth.Comparisons; 11 | using Smooth.Compare.Comparers; 12 | 13 | namespace Smooth.Compare { 14 | public static class Factory { 15 | private const int hashCodeSeed = 17; 16 | private const int hashCodeStepMultiplier = 29; 17 | 18 | #region Comparer 19 | 20 | /// 21 | /// Returns an option containing a sort order comparer for type T, or None if no comparer can be created. 22 | /// 23 | /// This method will create comparers for the following types: 24 | /// 25 | /// System.Collections.KeyValuePair<,>. 26 | /// 27 | public static Option> Comparer() { 28 | var type = typeof(T); 29 | 30 | if (!type.IsValueType) { 31 | return Option>.None; 32 | } else if (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(KeyValuePair<,>)) { 33 | return new Option>(KeyValuePairComparer(type)); 34 | } else { 35 | return Option>.None; 36 | } 37 | } 38 | 39 | #endregion 40 | 41 | #region EqualityComparer 42 | 43 | /// 44 | /// Returns an option containing an equality comparer for type T, or None if no comparer can be created. 45 | /// 46 | /// This method will create comparers for the following types: 47 | /// 48 | /// Enumerations, 49 | /// System.Collections.KeyValuePair<,>s, 50 | /// Value types T with a public T.Equals(T) method or ==(T,T) operator. 51 | /// 52 | public static Option> EqualityComparer() { 53 | var type = typeof(T); 54 | 55 | if (!type.IsValueType) { 56 | return Option>.None; 57 | } else if (type.IsEnum) { 58 | return new Option>(EnumEqualityComparer(type)); 59 | } else if (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(KeyValuePair<,>)) { 60 | return new Option>(KeyValuePairEqualityComparer(type)); 61 | } else { 62 | var l = Expression.Parameter(type, "l"); 63 | var r = Expression.Parameter(type, "r"); 64 | 65 | var expression = EqualsExpression(l, r); 66 | 67 | return expression.isSome ? 68 | new Option>(new FuncEqualityComparer(Expression.Lambda>(expression.value, l, r).Compile())) : 69 | Option>.None; 70 | } 71 | } 72 | 73 | #endregion 74 | 75 | #region Expressions 76 | 77 | private static Expression HashCodeSeed() { 78 | return Expression.Constant(hashCodeSeed, typeof(int)); 79 | } 80 | 81 | private static Expression HashCodeStepMultiplier() { 82 | return Expression.Constant(hashCodeStepMultiplier, typeof(int)); 83 | } 84 | 85 | /// 86 | /// Returns an option containing an expression that compares l and r for equality without casting, or None if no such comparison can be found. 87 | /// 88 | public static Option EqualsExpression(Expression l, Expression r) { 89 | try { 90 | var expression = Expression.Equal(l, r); 91 | var method = expression.Method; 92 | if (method != null) { 93 | var ps = method.GetParameters(); 94 | if (ps[0].ParameterType == l.Type && ps[1].ParameterType == r.Type) { 95 | return new Option(expression); 96 | } 97 | } 98 | } catch (InvalidOperationException) { 99 | } catch (Exception e) { 100 | Debug.LogError(e); 101 | } 102 | 103 | try { 104 | var mi = l.Type.GetMethod( 105 | "Equals", 106 | BindingFlags.Public | BindingFlags.Instance, 107 | null, 108 | new Type[] { r.Type }, 109 | null 110 | ); 111 | 112 | if (mi != null && mi.GetParameters()[0].ParameterType == r.Type) { 113 | return new Option(Expression.Call(l, mi, r)); 114 | } 115 | } catch (Exception e) { 116 | Debug.LogError(e); 117 | } 118 | 119 | return Option.None; 120 | } 121 | 122 | /// 123 | /// Returns a tuple containing: 124 | /// an Expression for the default sort order comparer for type T, and 125 | /// a MethodInfo for the comparer's Compare(T, T) method. 126 | /// 127 | public static Tuple ExistingComparer() { 128 | return ExistingComparer(typeof(T)); 129 | } 130 | 131 | /// 132 | /// Returns a tuple containing: 133 | /// an Expression for the default comparer for the specified type, and 134 | /// a MethodInfo for the comparer's Compare(T, T) method. 135 | /// 136 | public static Tuple ExistingComparer(Type type) { 137 | var pi = typeof(Smooth.Collections.Comparer<>).MakeGenericType(type).GetProperty( 138 | "Default", 139 | BindingFlags.Public | BindingFlags.Static, 140 | null, 141 | typeof(IComparer<>).MakeGenericType(type), 142 | Type.EmptyTypes, 143 | null); 144 | 145 | var c = Expression.Property(null, pi); 146 | 147 | return new Tuple( 148 | c, 149 | c.Type.GetMethod("Compare", BindingFlags.Public | BindingFlags.Instance, null, new Type[] { type, type }, null)); 150 | } 151 | 152 | /// 153 | /// Returns a tuple containing: 154 | /// an expression for the default equality comparer for type T, and 155 | /// a MethodInfo for the comparer's Equals(T, T) method, and 156 | /// a MethodInfo for the comparer's GetHashCode(T) method. 157 | /// 158 | public static Tuple ExistingEqualityComparer() { 159 | return ExistingEqualityComparer(typeof(T)); 160 | } 161 | 162 | /// 163 | /// Returns a tuple containing: 164 | /// an expression for the default equality comparer for the specified type, and 165 | /// a MethodInfo for the comparer's Equals(T, T) method, and 166 | /// a MethodInfo for the comparer's GetHashCode(T) method. 167 | /// 168 | public static Tuple ExistingEqualityComparer(Type type) { 169 | var pi = typeof(Smooth.Collections.EqualityComparer<>).MakeGenericType(type).GetProperty( 170 | "Default", 171 | BindingFlags.Public | BindingFlags.Static, 172 | null, 173 | typeof(IEqualityComparer<>).MakeGenericType(type), 174 | Type.EmptyTypes, 175 | null); 176 | 177 | var ec = Expression.Property(null, pi); 178 | 179 | return new Tuple( 180 | ec, 181 | ec.Type.GetMethod("Equals", BindingFlags.Public | BindingFlags.Instance, null, new Type[] { type, type }, null), 182 | ec.Type.GetMethod("GetHashCode", BindingFlags.Public | BindingFlags.Instance, null, new Type[] { type }, null)); 183 | } 184 | 185 | #endregion 186 | 187 | #region Comparers for specific types 188 | 189 | private static IComparer KeyValuePairComparer(Type type) { 190 | var l = Expression.Parameter(type, "l"); 191 | var r = Expression.Parameter(type, "r"); 192 | 193 | var keyL = Expression.Property(l, "Key"); 194 | var keyR = Expression.Property(r, "Key"); 195 | 196 | var valueL = Expression.Property(l, "Value"); 197 | var valueR = Expression.Property(r, "Value"); 198 | 199 | var keyComparer = ExistingComparer(keyL.Type); 200 | var valueComparer = ExistingComparer(valueL.Type); 201 | 202 | var keysCompared = Expression.Lambda>(Expression.Call(keyComparer._1, keyComparer._2, keyL, keyR), l, r).Compile(); 203 | var valuesCompared = Expression.Lambda>(Expression.Call(valueComparer._1, valueComparer._2, valueL, valueR), l, r).Compile(); 204 | 205 | return new FuncComparer((lhs, rhs) => { var c = keysCompared(lhs, rhs); return c == 0 ? valuesCompared(lhs, rhs) : c; }); 206 | } 207 | 208 | #endregion 209 | 210 | #region EqualityComparers for specific types 211 | 212 | private static IEqualityComparer EnumEqualityComparer(Type type) { 213 | switch(Type.GetTypeCode(type)) { 214 | case TypeCode.Int64: 215 | case TypeCode.UInt64: 216 | return new Blittable64EqualityComparer(); 217 | default: 218 | return new Blittable32EqualityComparer(); 219 | } 220 | } 221 | 222 | private static IEqualityComparer KeyValuePairEqualityComparer(Type type) { 223 | var l = Expression.Parameter(type, "l"); 224 | var r = Expression.Parameter(type, "r"); 225 | 226 | var keyL = Expression.Property(l, "Key"); 227 | var keyR = Expression.Property(r, "Key"); 228 | 229 | var valueL = Expression.Property(l, "Value"); 230 | var valueR = Expression.Property(r, "Value"); 231 | 232 | var keyComparer = ExistingEqualityComparer(keyL.Type); 233 | var valueComparer = ExistingEqualityComparer(valueL.Type); 234 | 235 | var keysEqual = Expression.Call(keyComparer._1, keyComparer._2, keyL, keyR); 236 | var valuesEqual = Expression.Call(valueComparer._1, valueComparer._2, valueL, valueR); 237 | 238 | var equals = Expression.And(keysEqual, valuesEqual); 239 | 240 | var hashCodeKey = Expression.Call(keyComparer._1, keyComparer._3, keyL); 241 | var hashCodeValue = Expression.Call(valueComparer._1, valueComparer._3, valueL); 242 | 243 | var hashCode = HashCodeSeed(); 244 | var hashCodeStepMultiplier = HashCodeStepMultiplier(); 245 | 246 | hashCode = BinaryExpression.Add(hashCodeKey, BinaryExpression.Multiply(hashCode, hashCodeStepMultiplier)); 247 | hashCode = BinaryExpression.Add(hashCodeValue, BinaryExpression.Multiply(hashCode, hashCodeStepMultiplier)); 248 | 249 | return new FuncEqualityComparer( 250 | Expression.Lambda>(equals, l, r).Compile(), 251 | Expression.Lambda>(hashCode, l).Compile()); 252 | } 253 | 254 | #endregion 255 | } 256 | } 257 | -------------------------------------------------------------------------------- /Assets/Smooth/Foundations/Compare/Utilities/LogUnregisteredOnDestroy.cs: -------------------------------------------------------------------------------- 1 | using UnityEngine; 2 | using System; 3 | using System.Text; 4 | using System.Collections.Generic; 5 | using Smooth.Collections; 6 | using Smooth.Compare; 7 | 8 | using EventType=Smooth.Compare.EventType; 9 | 10 | #if !UNITY_3_5 11 | namespace Smooth.Compare.Utilities { 12 | #endif 13 | /// 14 | /// Simple utility that listens to finder events and logs all requests for unregistered comparers when the component is destroyed. 15 | /// 16 | /// This can be useful when running an application meant for a non-JIT platform in a JIT-enabled simulator so you can test many code paths, then track down and fix any potential comparer issues. 17 | /// 18 | public class LogUnregisteredOnDestroy : MonoBehaviour { 19 | public bool destroyOnLoad; 20 | 21 | // Note: We don't use the registered comparer for Type because we want to add our event listener ASAP 22 | protected HashSet comparers = new HashSet(); 23 | protected HashSet equalityComparers = new HashSet(); 24 | 25 | protected void Awake() { 26 | if (!destroyOnLoad) { 27 | DontDestroyOnLoad(gameObject); 28 | } 29 | 30 | Finder.OnEvent.Handle += HandleFinderEvent; 31 | } 32 | 33 | protected void OnDestroy() { 34 | Finder.OnEvent.Handle -= HandleFinderEvent; 35 | 36 | if (comparers.Count > 0 || equalityComparers.Count > 0) { 37 | var sb = new StringBuilder(); 38 | 39 | if (comparers.Count > 0) { 40 | sb.Append("Unregistered ").Append(ComparerType.Comparer.ToStringCached()).AppendLine("s :"); 41 | foreach (var type in comparers) { 42 | sb.AppendLine(type.FullName); 43 | } 44 | } 45 | 46 | if (equalityComparers.Count > 0) { 47 | if (sb.Length > 0) { 48 | sb.AppendLine(); 49 | } 50 | sb.Append("Unregistered ").Append(ComparerType.EqualityComparer.ToStringCached()).AppendLine("s :"); 51 | foreach (var type in equalityComparers) { 52 | sb.AppendLine(type.FullName); 53 | } 54 | } 55 | 56 | Debug.Log(sb.ToString()); 57 | } 58 | } 59 | 60 | protected virtual void HandleFinderEvent(ComparerType comparerType, EventType eventType, Type type) { 61 | if (eventType == EventType.FindUnregistered && type.IsValueType) { 62 | switch (comparerType) { 63 | case ComparerType.Comparer: 64 | comparers.Add(type); 65 | break; 66 | case ComparerType.EqualityComparer: 67 | equalityComparers.Add(type); 68 | break; 69 | default: 70 | break; 71 | } 72 | } 73 | } 74 | } 75 | #if !UNITY_3_5 76 | } 77 | #endif 78 | -------------------------------------------------------------------------------- /Assets/Smooth/Foundations/Comparisons/Comparisons.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using Smooth.Delegates; 4 | 5 | namespace Smooth.Comparisons { 6 | /// 7 | /// Provides various methods for creating comparisons. 8 | /// 9 | public static class Comparisons { 10 | /// 11 | /// Reverses the ordering of the specified comparison. 12 | /// 13 | public static Comparison Reverse(Comparison comparison) { 14 | return (a, b) => comparison(b, a); 15 | } 16 | 17 | /// 18 | /// Prepends null sorting to the specified reference type comparison, with nulls preceeding non-nulls. 19 | /// 20 | public static Comparison NullsFirst(Comparison comparison) where T : class { 21 | return (a, b) => a == null ? (b == null ? 0 : -1) : b == null ? 1 : comparison(a, b); 22 | } 23 | 24 | /// 25 | /// Prepends null sorting to the specified reference type comparison, with nulls suceeding non-nulls. 26 | /// 27 | public static Comparison NullsLast(Comparison comparison) where T : class { 28 | return (a, b) => a == null ? (b == null ? 0 : 1) : b == null ? -1 : comparison(a, b); 29 | } 30 | 31 | /// 32 | /// Converts the specified comparison for value type T into a comparison for Nullables, with nulls preceeding non-nulls. 33 | /// 34 | public static Comparison> NullableNullsFirst(Comparison comparison) where T : struct { 35 | return (a, b) => a == null ? (b == null ? 0 : -1) : b == null ? 1 : comparison(a.Value, b.Value); 36 | } 37 | 38 | /// 39 | /// Converts the specified comparison for value type T into a comparison for Nullables, with nulls suceeding non-nulls. 40 | /// 41 | public static Comparison> NullableNullsLast(Comparison comparison) where T : struct { 42 | return (a, b) => a == null ? (b == null ? 0 : 1) : b == null ? -1 : comparison(a.Value, b.Value); 43 | } 44 | } 45 | 46 | /// 47 | /// Caches delegates for the comparsion methods of IComparers and IEqualityComparers. 48 | /// 49 | public static class Comparisons { 50 | private static Dictionary, Comparison> toComparison = new Dictionary, Comparison>(); 51 | private static Dictionary, DelegateFunc> toPredicate = new Dictionary, DelegateFunc>(); 52 | 53 | /// 54 | /// The comparison method of the default sort comparer for T in delegate form. 55 | /// 56 | public static Comparison Default { get { return ToComparison(Smooth.Collections.Comparer.Default); } } 57 | 58 | /// 59 | /// The comparison method of the default equality comparer for T in delegate form. 60 | /// 61 | public static DelegateFunc DefaultPredicate { get { return ToPredicate(Smooth.Collections.EqualityComparer.Default); } } 62 | 63 | /// 64 | /// Returns the comparison method of the specfied sort comparer in delegate form. 65 | /// 66 | public static Comparison ToComparison(IComparer comparer) { 67 | Comparison c; 68 | lock (toComparison) { 69 | if (!toComparison.TryGetValue(comparer, out c)) { 70 | c = comparer.Compare; 71 | toComparison[comparer] = c; 72 | } 73 | } 74 | return c; 75 | } 76 | 77 | /// 78 | /// Returns the comparison method of the specfied equality comparer in delegate form. 79 | /// 80 | public static DelegateFunc ToPredicate(IEqualityComparer equalityComparer) { 81 | DelegateFunc c; 82 | lock (toPredicate) { 83 | if (!toPredicate.TryGetValue(equalityComparer, out c)) { 84 | c = equalityComparer.Equals; 85 | toPredicate[equalityComparer] = c; 86 | } 87 | } 88 | return c; 89 | } 90 | } 91 | } 92 | -------------------------------------------------------------------------------- /Assets/Smooth/Foundations/Comparisons/FuncComparer.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using Smooth.Collections; 4 | 5 | namespace Smooth.Comparisons { 6 | /// 7 | /// Performs type-specific comparisons using the comparison delegate supplied to the constructor. 8 | /// 9 | public class FuncComparer : Smooth.Collections.Comparer { 10 | private readonly Comparison comparison; 11 | 12 | /// 13 | /// Instantiate a comparer for type T using the specified comparison 14 | /// 15 | public FuncComparer(Comparison comparison) { 16 | this.comparison = comparison; 17 | } 18 | 19 | public FuncComparer(IComparer comparer) { 20 | this.comparison = comparer.Compare; 21 | } 22 | 23 | public override int Compare(T t1, T t2) { 24 | return comparison(t1, t2); 25 | } 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /Assets/Smooth/Foundations/Comparisons/FuncEqualityComparer.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using Smooth.Collections; 4 | 5 | namespace Smooth.Comparisons { 6 | /// 7 | /// Performs type-specific equality comparisons and hashCode generation using the functions supplied to the constructor. 8 | /// 9 | public class FuncEqualityComparer : Smooth.Collections.EqualityComparer { 10 | private readonly Func equals; 11 | private readonly Func hashCode; 12 | 13 | /// 14 | /// Instantiate an equality comparer for type T using the specified equality function and T.GetHashCode() 15 | /// 16 | public FuncEqualityComparer(Func equals) { 17 | this.equals = equals; 18 | this.hashCode = typeof(T).IsClass ? (Func) (t => t == null ? 0 : t.GetHashCode()) : (Func) (t => t.GetHashCode()); 19 | } 20 | 21 | /// 22 | /// Instantiate an equality comparer for type T with the specified equality and hashCode functions 23 | /// 24 | public FuncEqualityComparer(Func equals, Func hashCode) { 25 | this.equals = equals; 26 | this.hashCode = hashCode; 27 | } 28 | 29 | public FuncEqualityComparer(IEqualityComparer equalityComparer) { 30 | this.equals = equalityComparer.Equals; 31 | this.hashCode = equalityComparer.GetHashCode; 32 | } 33 | 34 | public override bool Equals(T t1, T t2) { 35 | return equals(t1, t2); 36 | } 37 | 38 | public override int GetHashCode(T t) { 39 | return hashCode(t); 40 | } 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /Assets/Smooth/Foundations/Comparisons/IComparableComparer.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using Smooth.Collections; 4 | 5 | namespace Smooth.Comparisons { 6 | /// 7 | /// Allocation free sort order comparer for type T where T implements IComparable. 8 | /// 9 | /// Only useful to circumvent potential JIT exceptions on platforms without JIT compilation. 10 | /// 11 | public class IComparableComparer : Smooth.Collections.Comparer where T : IComparable { 12 | public override int Compare(T l, T r) { 13 | return l.CompareTo(r); 14 | } 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /Assets/Smooth/Foundations/Comparisons/IEquatableEqualityComparer.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using Smooth.Collections; 4 | 5 | namespace Smooth.Comparisons { 6 | /// 7 | /// Allocation free equality comparer for type T where T implements IEquatable. 8 | /// 9 | /// Only useful to circumvent potential JIT exceptions on platforms without JIT compilation. 10 | /// 11 | public class IEquatableEqualityComparer : Smooth.Collections.EqualityComparer where T : IEquatable { 12 | public override bool Equals(T l, T r) { 13 | return l.Equals(r); 14 | } 15 | 16 | public override int GetHashCode(T t) { 17 | return t.GetHashCode(); 18 | } 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /Assets/Smooth/Foundations/Delegates/DelegateExtensions.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace Smooth.Delegates { 4 | /// 5 | /// Provides extension methods related to delegate usage. 6 | /// 7 | public static class DelegateExtensions { 8 | /// 9 | /// Calls the specified action with the specified value. 10 | /// 11 | public static void Apply(this T t, DelegateAction a) { 12 | a(t); 13 | } 14 | 15 | /// 16 | /// Calls the specified action with the specified value and parameter. 17 | /// 18 | public static void Apply(this T t, DelegateAction a, P p) { 19 | a(t, p); 20 | } 21 | 22 | /// 23 | /// Calls the specified function with the specified value and returns the result. 24 | /// 25 | public static U Apply(this T t, DelegateFunc f) { 26 | return f(t); 27 | } 28 | 29 | /// 30 | /// Calls the specified function with the specified value and parameter and returns the result. 31 | /// 32 | public static U Apply(this T t, DelegateFunc f, P p) { 33 | return f(t, p); 34 | } 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /Assets/Smooth/Foundations/Delegates/Delegates.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace Smooth.Delegates { 4 | public delegate void DelegateAction(); 5 | public delegate void DelegateAction(T1 _1); 6 | public delegate void DelegateAction(T1 _1, T2 _2); 7 | public delegate void DelegateAction(T1 _1, T2 _2, T3 _3); 8 | public delegate void DelegateAction(T1 _1, T2 _2, T3 _3, T4 _4); 9 | public delegate void DelegateAction(T1 _1, T2 _2, T3 _3, T4 _4, T5 _5); 10 | public delegate void DelegateAction(T1 _1, T2 _2, T3 _3, T4 _4, T5 _5, T6 _6); 11 | public delegate void DelegateAction(T1 _1, T2 _2, T3 _3, T4 _4, T5 _5, T6 _6, T7 _7); 12 | public delegate void DelegateAction(T1 _1, T2 _2, T3 _3, T4 _4, T5 _5, T6 _6, T7 _7, T8 _8); 13 | public delegate void DelegateAction(T1 _1, T2 _2, T3 _3, T4 _4, T5 _5, T6 _6, T7 _7, T8 _8, T9 _9); 14 | 15 | public delegate R DelegateFunc(); 16 | public delegate R DelegateFunc(T1 _1); 17 | public delegate R DelegateFunc(T1 _1, T2 _2); 18 | public delegate R DelegateFunc(T1 _1, T2 _2, T3 _3); 19 | public delegate R DelegateFunc(T1 _1, T2 _2, T3 _3, T4 _4); 20 | public delegate R DelegateFunc(T1 _1, T2 _2, T3 _3, T4 _4, T5 _5); 21 | public delegate R DelegateFunc(T1 _1, T2 _2, T3 _3, T4 _4, T5 _5, T6 _6); 22 | public delegate R DelegateFunc(T1 _1, T2 _2, T3 _3, T4 _4, T5 _5, T6 _6, T7 _7); 23 | public delegate R DelegateFunc(T1 _1, T2 _2, T3 _3, T4 _4, T5 _5, T6 _6, T7 _7, T8 _8); 24 | public delegate R DelegateFunc(T1 _1, T2 _2, T3 _3, T4 _4, T5 _5, T6 _6, T7 _7, T8 _8, T9 _9); 25 | } -------------------------------------------------------------------------------- /Assets/Smooth/Foundations/Delegates/Tupled.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Smooth.Algebraics; 3 | 4 | namespace Smooth.Delegates { 5 | 6 | /// 7 | /// Provides methods for invoking a delegate that takes individual parameters using a tuple. 8 | /// 9 | /// Many Smooth methods allow the use of an optional parameter that is passed to a delegate in order to capture state without allocating a closure. One use case of this class is to convert a tupled state parameter into individual parameters. 10 | /// 11 | /// For instance: 12 | /// 13 | /// option.Where((player, p) => player.team == p._1 && player.score > p._2, Tuple.Create(myTeam, myScore)) 14 | /// 15 | /// Could be written as: 16 | /// 17 | /// option.Where((v, p) => Tupled.Call((player, team, score) => player.team == team && player.score > score, v, p), Tuple.Create(myTeam, myScore)) 18 | /// 19 | /// While this form is slightly longer and requires an extra method call, it can be useful as a "quick and dirty" way to use meaningful parameter names in complicated delegates. 20 | /// 21 | public static class Tupled { 22 | 23 | #region Action, Tuple 24 | 25 | public static void Call(this DelegateAction action, Tuple t) { 26 | action(t._1); 27 | } 28 | 29 | public static void Call(this DelegateAction action, Tuple t) { 30 | action(t._1, t._2); 31 | } 32 | 33 | public static void Call(this DelegateAction action, Tuple t) { 34 | action(t._1, t._2, t._3); 35 | } 36 | 37 | public static void Call(this DelegateAction action, Tuple t) { 38 | action(t._1, t._2, t._3, t._4); 39 | } 40 | 41 | public static void Call(this DelegateAction action, Tuple t) { 42 | action(t._1, t._2, t._3, t._4, t._5); 43 | } 44 | 45 | public static void Call(this DelegateAction action, Tuple t) { 46 | action(t._1, t._2, t._3, t._4, t._5, t._6); 47 | } 48 | 49 | public static void Call(this DelegateAction action, Tuple t) { 50 | action(t._1, t._2, t._3, t._4, t._5, t._6, t._7); 51 | } 52 | 53 | public static void Call(this DelegateAction action, Tuple t) { 54 | action(t._1, t._2, t._3, t._4, t._5, t._6, t._7, t._8); 55 | } 56 | 57 | public static void Call(this DelegateAction action, Tuple t) { 58 | action(t._1, t._2, t._3, t._4, t._5, t._6, t._7, t._8, t._9); 59 | } 60 | 61 | #endregion 62 | 63 | #region Action, First, Tuple 64 | 65 | public static void Call(this DelegateAction action, F first, Tuple t) { 66 | action(first, t._1); 67 | } 68 | 69 | public static void Call(this DelegateAction action, F first, Tuple t) { 70 | action(first, t._1, t._2); 71 | } 72 | 73 | public static void Call(this DelegateAction action, F first, Tuple t) { 74 | action(first, t._1, t._2, t._3); 75 | } 76 | 77 | public static void Call(this DelegateAction action, F first, Tuple t) { 78 | action(first, t._1, t._2, t._3, t._4); 79 | } 80 | 81 | public static void Call(this DelegateAction action, F first, Tuple t) { 82 | action(first, t._1, t._2, t._3, t._4, t._5); 83 | } 84 | 85 | public static void Call(this DelegateAction action, F first, Tuple t) { 86 | action(first, t._1, t._2, t._3, t._4, t._5, t._6); 87 | } 88 | 89 | public static void Call(this DelegateAction action, F first, Tuple t) { 90 | action(first, t._1, t._2, t._3, t._4, t._5, t._6, t._7); 91 | } 92 | 93 | public static void Call(this DelegateAction action, F first, Tuple t) { 94 | action(first, t._1, t._2, t._3, t._4, t._5, t._6, t._7, t._8); 95 | } 96 | 97 | #endregion 98 | 99 | #region Func, Tuple 100 | 101 | public static R Call(this DelegateFunc func, Tuple t) { 102 | return func(t._1); 103 | } 104 | 105 | public static R Call(this DelegateFunc func, Tuple t) { 106 | return func(t._1, t._2); 107 | } 108 | 109 | public static R Call(this DelegateFunc func, Tuple t) { 110 | return func(t._1, t._2, t._3); 111 | } 112 | 113 | public static R Call(this DelegateFunc func, Tuple t) { 114 | return func(t._1, t._2, t._3, t._4); 115 | } 116 | 117 | public static R Call(this DelegateFunc func, Tuple t) { 118 | return func(t._1, t._2, t._3, t._4, t._5); 119 | } 120 | 121 | public static R Call(this DelegateFunc func, Tuple t) { 122 | return func(t._1, t._2, t._3, t._4, t._5, t._6); 123 | } 124 | 125 | public static R Call(this DelegateFunc func, Tuple t) { 126 | return func(t._1, t._2, t._3, t._4, t._5, t._6, t._7); 127 | } 128 | 129 | public static R Call(this DelegateFunc func, Tuple t) { 130 | return func(t._1, t._2, t._3, t._4, t._5, t._6, t._7, t._8); 131 | } 132 | 133 | public static R Call(this DelegateFunc func, Tuple t) { 134 | return func(t._1, t._2, t._3, t._4, t._5, t._6, t._7, t._8, t._9); 135 | } 136 | 137 | #endregion 138 | 139 | #region Func, First, Tuple 140 | 141 | public static R Call(this DelegateFunc func, F first, Tuple t) { 142 | return func(first, t._1); 143 | } 144 | 145 | public static R Call(this DelegateFunc func, F first, Tuple t) { 146 | return func(first, t._1, t._2); 147 | } 148 | 149 | public static R Call(this DelegateFunc func, F first, Tuple t) { 150 | return func(first, t._1, t._2, t._3); 151 | } 152 | 153 | public static R Call(this DelegateFunc func, F first, Tuple t) { 154 | return func(first, t._1, t._2, t._3, t._4); 155 | } 156 | 157 | public static R Call(this DelegateFunc func, F first, Tuple t) { 158 | return func(first, t._1, t._2, t._3, t._4, t._5); 159 | } 160 | 161 | public static R Call(this DelegateFunc func, F first, Tuple t) { 162 | return func(first, t._1, t._2, t._3, t._4, t._5, t._6); 163 | } 164 | 165 | public static R Call(this DelegateFunc func, F first, Tuple t) { 166 | return func(first, t._1, t._2, t._3, t._4, t._5, t._6, t._7); 167 | } 168 | 169 | public static R Call(this DelegateFunc func, F first, Tuple t) { 170 | return func(first, t._1, t._2, t._3, t._4, t._5, t._6, t._7, t._8); 171 | } 172 | 173 | #endregion 174 | 175 | } 176 | } 177 | -------------------------------------------------------------------------------- /Assets/Smooth/Foundations/Dispose/Disposable.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Smooth.Delegates; 3 | using Smooth.Pools; 4 | 5 | namespace Smooth.Dispose { 6 | 7 | #if UNITY_IOS || UNITY_PS3 || UNITY_XBOX360 || UNITY_WII 8 | 9 | /// 10 | /// Wrapper around a value that uses the IDisposable interface to dispose of the value. 11 | /// 12 | /// On iOS, this is a struct to avoid compute_class_bitmap errors. 13 | /// 14 | /// On other platforms, it is a pooled object to avoid boxing when disposed by a using block with the Unity compiler. 15 | /// 16 | public struct Disposable : IDisposable { 17 | /// 18 | /// Borrows a wrapper for the specified value and disposal delegate. 19 | /// 20 | public static Disposable Borrow(T value, DelegateAction dispose) { 21 | return new Disposable(value, dispose); 22 | } 23 | 24 | private readonly DelegateAction dispose; 25 | 26 | /// 27 | /// The wrapped value. 28 | /// 29 | public readonly T value; 30 | 31 | public Disposable(T value, DelegateAction dispose) { 32 | this.value = value; 33 | this.dispose = dispose; 34 | } 35 | 36 | /// 37 | /// Relinquishes ownership of the wrapper and disposes the wrapped value. 38 | /// 39 | public void Dispose() { 40 | dispose(value); 41 | } 42 | 43 | /// 44 | /// Relinquishes ownership of the wrapper and adds it to the disposal queue. 45 | /// 46 | public void DisposeInBackground() { 47 | DisposalQueue.Enqueue(this); 48 | } 49 | } 50 | 51 | #else 52 | 53 | /// 54 | /// Wrapper around a value that uses the IDisposable interface to dispose of the value. 55 | /// 56 | /// On IOS, this is a value type to avoid compute_class_bitmap errors. 57 | /// 58 | /// On other platforms, it is a pooled object to avoid boxing when disposed by a using block with the Unity compiler. 59 | /// 60 | public class Disposable : IDisposable { 61 | private static readonly Pool> pool = new Pool>( 62 | () => new Disposable(), 63 | wrapper => { 64 | wrapper.dispose(wrapper.value); 65 | wrapper.dispose = t => {}; 66 | wrapper.value = default(T); 67 | } 68 | ); 69 | 70 | /// 71 | /// Borrows a wrapper for the specified value and disposal delegate. 72 | /// 73 | public static Disposable Borrow(T value, DelegateAction dispose) { 74 | var wrapper = pool.Borrow(); 75 | wrapper.value = value; 76 | wrapper.dispose = dispose; 77 | return wrapper; 78 | } 79 | 80 | private DelegateAction dispose; 81 | 82 | /// 83 | /// The wrapped value. 84 | /// 85 | public T value { get; private set; } 86 | 87 | private Disposable() {} 88 | 89 | /// 90 | /// Relinquishes ownership of the wrapper, disposes the wrapped value, and returns the wrapper to the pool. 91 | /// 92 | public void Dispose() { 93 | pool.Release(this); 94 | } 95 | 96 | /// 97 | /// Relinquishes ownership of the wrapper and adds it to the disposal queue. 98 | /// 99 | public void DisposeInBackground() { 100 | DisposalQueue.Enqueue(this); 101 | } 102 | } 103 | 104 | #endif 105 | 106 | } -------------------------------------------------------------------------------- /Assets/Smooth/Foundations/Dispose/DisposalQueue.cs: -------------------------------------------------------------------------------- 1 | using UnityEngine; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Threading; 5 | 6 | namespace Smooth.Dispose { 7 | 8 | /// 9 | /// Queues pooled resources for cleanup by a background thread. 10 | /// 11 | /// By default, the disposal thread is woken up at the end of LateUpdate, when there is likely to be free CPU time available while GPU operations are in progress. 12 | /// 13 | /// Various pools may be locked and unlocked while resources are released, potentially causing contention if pooled resources are borrowed during the disposal process. 14 | /// 15 | /// Advanced users who are using pools from the main thread during the rendering phase may want to customize the point in the Unity event loop when the queue lock is pulsed, potentially pulsing from a Camera event. 16 | /// 17 | public static class DisposalQueue { 18 | private static readonly object queueLock = new object(); 19 | private static Queue enqueue = new Queue(); 20 | private static Queue dispose = new Queue(); 21 | 22 | /// 23 | /// Adds the specified item to the disposal queue. 24 | /// 25 | public static void Enqueue(IDisposable item) { 26 | lock (queueLock) { 27 | enqueue.Enqueue(item); 28 | } 29 | } 30 | 31 | /// 32 | /// Pulses the queue lock, potentially waking up the disposal thread. 33 | /// 34 | public static void Pulse() { 35 | lock (queueLock) { 36 | Monitor.Pulse(queueLock); 37 | } 38 | } 39 | 40 | private static void Dispose() { 41 | while (true) { 42 | lock (queueLock) { 43 | while (enqueue.Count == 0) { 44 | Monitor.Wait(queueLock); 45 | } 46 | var t = enqueue; 47 | enqueue = dispose; 48 | dispose = t; 49 | } 50 | while (dispose.Count > 0) { 51 | try { 52 | dispose.Dequeue().Dispose(); 53 | } catch (ThreadAbortException) { 54 | } catch (Exception e) { 55 | Debug.LogError(e); 56 | } 57 | } 58 | } 59 | } 60 | 61 | static DisposalQueue() { 62 | new Thread(new ThreadStart(Dispose)).Start(); 63 | new GameObject(typeof(SmoothDisposer).Name).AddComponent(); 64 | } 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /Assets/Smooth/Foundations/Dispose/SmoothDisposer.cs: -------------------------------------------------------------------------------- 1 | using UnityEngine; 2 | using System; 3 | using Smooth.Dispose; 4 | 5 | public class SmoothDisposer : MonoBehaviour { 6 | private static SmoothDisposer instance; 7 | 8 | private void Awake() { 9 | if (instance) { 10 | Debug.LogWarning("Only one " + GetType().Name + " should exist at a time, instantiated by the " + typeof(DisposalQueue).Name + " class."); 11 | Destroy(this); 12 | } else { 13 | instance = this; 14 | DontDestroyOnLoad(this); 15 | } 16 | } 17 | 18 | private void LateUpdate() { 19 | DisposalQueue.Pulse(); 20 | } 21 | } -------------------------------------------------------------------------------- /Assets/Smooth/Foundations/Events/GenericEvents.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Smooth.Delegates; 3 | 4 | namespace Smooth.Events { 5 | /// 6 | /// Struct wrapped event that allows raising the event from outside the containing class. 7 | /// 8 | public struct GenericEvent { 9 | /// 10 | /// The wrapped event. 11 | /// 12 | public event DelegateAction Handle; 13 | 14 | /// 15 | /// Raises the wrapped event. 16 | /// 17 | public void Raise() { var handle = Handle; if (handle != null) { handle(); } } 18 | } 19 | 20 | /// 21 | /// Struct wrapped event that allows raising the event from outside the containing class. 22 | /// 23 | public struct GenericEvent { 24 | /// 25 | /// The wrapped event. 26 | /// 27 | public event DelegateAction Handle; 28 | 29 | /// 30 | /// Raises the wrapped event with the specifed parameter. 31 | /// 32 | public void Raise(T1 t1) { var handle = Handle; if (handle != null) { handle(t1); } } 33 | } 34 | 35 | /// 36 | /// Struct wrapped event that allows raising the event from outside the containing class. 37 | /// 38 | public struct GenericEvent { 39 | /// 40 | /// The wrapped event. 41 | /// 42 | public event DelegateAction Handle; 43 | 44 | /// 45 | /// Raises the wrapped event with the specifed parameters. 46 | /// 47 | public void Raise(T1 t1, T2 t2) { var handle = Handle; if (handle != null) { handle(t1, t2); } } 48 | } 49 | 50 | /// 51 | /// Struct wrapped event that allows raising the event from outside the containing class. 52 | /// 53 | public struct GenericEvent { 54 | /// 55 | /// The wrapped event. 56 | /// 57 | public event DelegateAction Handle; 58 | 59 | /// 60 | /// Raises the wrapped event with the specifed parameters. 61 | /// 62 | public void Raise(T1 t1, T2 t2, T3 t3) { var handle = Handle; if (handle != null) { handle(t1, t2, t3); } } 63 | } 64 | 65 | /// 66 | /// Struct wrapped event that allows raising the event from outside the containing class. 67 | /// 68 | public struct GenericEvent { 69 | /// 70 | /// The wrapped event. 71 | /// 72 | public event DelegateAction Handle; 73 | 74 | /// 75 | /// Raises the wrapped event with the specifed parameters. 76 | /// 77 | public void Raise(T1 t1, T2 t2, T3 t3, T4 t4) { var handle = Handle; if (handle != null) { handle(t1, t2, t3, t4); } } 78 | } 79 | 80 | /// 81 | /// Struct wrapped event that allows raising the event from outside the containing class. 82 | /// 83 | public struct GenericEvent { 84 | /// 85 | /// The wrapped event. 86 | /// 87 | public event DelegateAction Handle; 88 | 89 | /// 90 | /// Raises the wrapped event with the specifed parameters. 91 | /// 92 | public void Raise(T1 t1, T2 t2, T3 t3, T4 t4, T5 t5) { var handle = Handle; if (handle != null) { handle(t1, t2, t3, t4, t5); } } 93 | } 94 | 95 | /// 96 | /// Struct wrapped event that allows raising the event from outside the containing class. 97 | /// 98 | public struct GenericEvent { 99 | /// 100 | /// The wrapped event. 101 | /// 102 | public event DelegateAction Handle; 103 | 104 | /// 105 | /// Raises the wrapped event with the specifed parameters. 106 | /// 107 | public void Raise(T1 t1, T2 t2, T3 t3, T4 t4, T5 t5, T6 t6) { var handle = Handle; if (handle != null) { handle(t1, t2, t3, t4, t5, t6); } } 108 | } 109 | 110 | /// 111 | /// Struct wrapped event that allows raising the event from outside the containing class. 112 | /// 113 | public struct GenericEvent { 114 | /// 115 | /// The wrapped event. 116 | /// 117 | public event DelegateAction Handle; 118 | 119 | /// 120 | /// Raises the wrapped event with the specifed parameters. 121 | /// 122 | public void Raise(T1 t1, T2 t2, T3 t3, T4 t4, T5 t5, T6 t6, T7 t7) { var handle = Handle; if (handle != null) { handle(t1, t2, t3, t4, t5, t6, t7); } } 123 | } 124 | 125 | /// 126 | /// Struct wrapped event that allows raising the event from outside the containing class. 127 | /// 128 | public struct GenericEvent { 129 | /// 130 | /// The wrapped event. 131 | /// 132 | public event DelegateAction Handle; 133 | 134 | /// 135 | /// Raises the wrapped event with the specifed parameters. 136 | /// 137 | public void Raise(T1 t1, T2 t2, T3 t3, T4 t4, T5 t5, T6 t6, T7 t7, T8 t8) { var handle = Handle; if (handle != null) { handle(t1, t2, t3, t4, t5, t6, t7, t8); } } 138 | } 139 | 140 | /// 141 | /// Struct wrapped event that allows raising the event from outside the containing class. 142 | /// 143 | public struct GenericEvent { 144 | /// 145 | /// The wrapped event. 146 | /// 147 | public event DelegateAction Handle; 148 | 149 | /// 150 | /// Raises the wrapped event with the specifed parameters. 151 | /// 152 | public void Raise(T1 t1, T2 t2, T3 t3, T4 t4, T5 t5, T6 t6, T7 t7, T8 t8, T9 t9) { var handle = Handle; if (handle != null) { handle(t1, t2, t3, t4, t5, t6, t7, t8, t9); } } 153 | } 154 | } 155 | -------------------------------------------------------------------------------- /Assets/Smooth/Foundations/Platform/BasePlatform.cs: -------------------------------------------------------------------------------- 1 | using UnityEngine; 2 | using System; 3 | 4 | namespace Smooth.Platform { 5 | 6 | /// 7 | /// Enumeration representing the base platforms for Unity builds. 8 | /// 9 | public enum BasePlatform { 10 | None = 0, 11 | Android = 100, 12 | Bb10 = 200, 13 | Flash = 300, 14 | Ios = 400, 15 | Linux = 500, 16 | Metro = 600, 17 | NaCl = 700, 18 | Osx = 800, 19 | Ps3 = 900, 20 | Tizen = 1000, 21 | Wii = 1100, 22 | Windows = 1200, 23 | Wp8 = 1300, 24 | Xbox360 = 1400, 25 | } 26 | 27 | /// 28 | /// Extension methods related to the runtime / base platform. 29 | /// 30 | public static class PlatformExtensions { 31 | 32 | /// 33 | /// Returns the base platform for the specified runtime platform. 34 | /// 35 | public static BasePlatform ToBasePlatform(this RuntimePlatform runtimePlatform) { 36 | switch (runtimePlatform) { 37 | case RuntimePlatform.IPhonePlayer: 38 | return BasePlatform.Ios; 39 | case RuntimePlatform.Android: 40 | return BasePlatform.Android; 41 | case RuntimePlatform.WindowsEditor: 42 | case RuntimePlatform.WindowsPlayer: 43 | case RuntimePlatform.WindowsWebPlayer: 44 | return BasePlatform.Windows; 45 | case RuntimePlatform.OSXEditor: 46 | case RuntimePlatform.OSXPlayer: 47 | case RuntimePlatform.OSXWebPlayer: 48 | case RuntimePlatform.OSXDashboardPlayer: 49 | return BasePlatform.Osx; 50 | case RuntimePlatform.LinuxPlayer: 51 | return BasePlatform.Linux; 52 | case RuntimePlatform.WiiPlayer: 53 | return BasePlatform.Wii; 54 | case RuntimePlatform.XBOX360: 55 | return BasePlatform.Xbox360; 56 | case RuntimePlatform.PS3: 57 | return BasePlatform.Ps3; 58 | case RuntimePlatform.FlashPlayer: 59 | return BasePlatform.Flash; 60 | case RuntimePlatform.NaCl: 61 | return BasePlatform.NaCl; 62 | #if !UNITY_3_5 && !UNITY_4_0 && !UNITY_4_1 63 | case RuntimePlatform.WP8Player: 64 | return BasePlatform.Wp8; 65 | case RuntimePlatform.MetroPlayerX86: 66 | case RuntimePlatform.MetroPlayerX64: 67 | case RuntimePlatform.MetroPlayerARM: 68 | return BasePlatform.Metro; 69 | case RuntimePlatform.BB10Player: 70 | return BasePlatform.Bb10; 71 | case RuntimePlatform.TizenPlayer: 72 | return BasePlatform.Tizen; 73 | #endif 74 | default: 75 | return BasePlatform.None; 76 | } 77 | } 78 | 79 | /// 80 | /// Returns true if the specified platform supports JIT compilation; otherwise, false. 81 | /// 82 | public static bool HasJit(this RuntimePlatform runtimePlatform) { 83 | return ( 84 | runtimePlatform != RuntimePlatform.IPhonePlayer && 85 | runtimePlatform != RuntimePlatform.PS3 && 86 | runtimePlatform != RuntimePlatform.XBOX360 && 87 | runtimePlatform != RuntimePlatform.WiiPlayer); 88 | } 89 | 90 | /// 91 | /// Returns true if the specified platform supports JIT compilation; otherwise, false. 92 | /// 93 | public static bool HasJit(this BasePlatform basePlatform) { 94 | return ( 95 | basePlatform != BasePlatform.Ios && 96 | basePlatform != BasePlatform.Ps3 && 97 | basePlatform != BasePlatform.Xbox360 && 98 | basePlatform != BasePlatform.Wii); 99 | } 100 | 101 | /// 102 | /// Returns true if the specified platform does not support JIT compilation; otherwise, false. 103 | /// 104 | public static bool NoJit(this RuntimePlatform runtimePlatform) { 105 | return !HasJit(runtimePlatform); 106 | } 107 | 108 | /// 109 | /// Returns true if the specified platform does not support JIT compilation; otherwise, false. 110 | /// 111 | public static bool NoJit(this BasePlatform basePlatform) { 112 | return !HasJit(basePlatform); 113 | } 114 | } 115 | } 116 | -------------------------------------------------------------------------------- /Assets/Smooth/Foundations/Platform/Runtime.cs: -------------------------------------------------------------------------------- 1 | using UnityEngine; 2 | using System; 3 | 4 | namespace Smooth.Platform { 5 | 6 | /// 7 | /// Helper class that provides information about the target platform. 8 | /// 9 | public static class Runtime { 10 | 11 | /// 12 | /// The target runtime platform. 13 | /// 14 | public static readonly RuntimePlatform platform = Application.platform; 15 | 16 | /// 17 | /// The base platform of the target runtime. 18 | /// 19 | public static readonly BasePlatform basePlatform = platform.ToBasePlatform(); 20 | 21 | /// 22 | /// True if the base platform supports JIT compilation; otherwise false. 23 | /// 24 | public static readonly bool hasJit = basePlatform.HasJit(); 25 | 26 | /// 27 | /// True if the base platform does not support JIT compilation; otherwise false. 28 | /// 29 | public static readonly bool noJit = !hasJit; 30 | 31 | } 32 | } -------------------------------------------------------------------------------- /Assets/Smooth/Foundations/Pools/KeyedPool.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using Smooth.Delegates; 4 | using Smooth.Dispose; 5 | 6 | namespace Smooth.Pools { 7 | /// 8 | /// Pool that lends values of type T with an associated key of type K. 9 | /// 10 | public class KeyedPool { 11 | private readonly Dictionary> keyToValues = new Dictionary>(); 12 | 13 | private readonly DelegateFunc create; 14 | private readonly DelegateFunc reset; 15 | private readonly DelegateAction release; 16 | 17 | private KeyedPool() {} 18 | 19 | /// 20 | /// Creates a new keyed pool with the specified value creation and reset delegates. 21 | /// 22 | public KeyedPool(DelegateFunc create, DelegateFunc reset) { 23 | this.create = create; 24 | this.reset = reset; 25 | this.release = Release; 26 | } 27 | 28 | /// 29 | /// Borrows a value with the specified key from the pool. 30 | /// 31 | public T Borrow(K key) { 32 | lock (keyToValues) { 33 | Stack values; 34 | return keyToValues.TryGetValue(key, out values) && values.Count > 0 ? values.Pop() : create(key); 35 | } 36 | } 37 | 38 | /// 39 | /// Relinquishes ownership of the specified value and returns it to the pool. 40 | /// 41 | public void Release(T value) { 42 | var key = reset(value); 43 | lock (keyToValues) { 44 | Stack values; 45 | if (!keyToValues.TryGetValue(key, out values)) { 46 | values = new Stack(); 47 | keyToValues[key] = values; 48 | } 49 | values.Push(value); 50 | } 51 | } 52 | 53 | /// 54 | /// Borrows a wrapped value with the specified key from the pool. 55 | /// 56 | public Disposable BorrowDisposable(K key) { 57 | return Disposable.Borrow(Borrow(key), release); 58 | } 59 | } 60 | } -------------------------------------------------------------------------------- /Assets/Smooth/Foundations/Pools/KeyedPoolWithDefaultKey.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using Smooth.Algebraics; 4 | using Smooth.Delegates; 5 | using Smooth.Dispose; 6 | 7 | namespace Smooth.Pools { 8 | /// 9 | /// Pool that lends values of type T with an associated key of type K and defines a default key. 10 | /// 11 | public class KeyedPoolWithDefaultKey : KeyedPool { 12 | private readonly Either> defaultKey; 13 | 14 | /// 15 | /// Creates a new keyed pool with the specified creation delegate, reset delegate, and default key. 16 | /// 17 | public KeyedPoolWithDefaultKey(DelegateFunc create, DelegateFunc reset, K defaultKey) : base (create, reset) { 18 | this.defaultKey = Either>.Left(defaultKey); 19 | } 20 | 21 | /// 22 | /// Creates a new keyed pool with the specified creation delegate, reset delegate, and default key. 23 | /// 24 | public KeyedPoolWithDefaultKey(DelegateFunc create, DelegateFunc reset, DelegateFunc defaultKeyFunc) : base (create, reset) { 25 | this.defaultKey = Either>.Right(defaultKeyFunc); 26 | } 27 | 28 | /// 29 | /// Borrows a value with the default key from the pool. 30 | /// 31 | public T Borrow() { 32 | return Borrow(defaultKey.isLeft ? defaultKey.leftValue : defaultKey.rightValue()); 33 | } 34 | 35 | /// 36 | /// Borrows a wrapped value with the default key from the pool. 37 | /// 38 | public Disposable BorrowDisposable() { 39 | return BorrowDisposable(defaultKey.isLeft ? defaultKey.leftValue : defaultKey.rightValue()); 40 | } 41 | } 42 | } -------------------------------------------------------------------------------- /Assets/Smooth/Foundations/Pools/Pool.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using Smooth.Delegates; 4 | using Smooth.Dispose; 5 | 6 | namespace Smooth.Pools { 7 | /// 8 | /// Pool that lends values of type T. 9 | /// 10 | public class Pool { 11 | private readonly Stack values = new Stack(); 12 | 13 | private readonly DelegateFunc create; 14 | private readonly DelegateAction reset; 15 | private readonly DelegateAction release; 16 | 17 | private Pool() {} 18 | 19 | /// 20 | /// Creates a new pool with the specified value creation and reset delegates. 21 | /// 22 | public Pool(DelegateFunc create, DelegateAction reset) { 23 | this.create = create; 24 | this.reset = reset; 25 | this.release = Release; 26 | } 27 | 28 | /// 29 | /// Borrows a value from the pool. 30 | /// 31 | public T Borrow() { 32 | lock (values) { 33 | return values.Count > 0 ? values.Pop() : create(); 34 | } 35 | } 36 | 37 | /// 38 | /// Relinquishes ownership of the specified value and returns it to the pool. 39 | /// 40 | public void Release(T value) { 41 | reset(value); 42 | lock (values) { 43 | values.Push(value); 44 | } 45 | } 46 | 47 | /// 48 | /// Borrows a wrapped value from the pool. 49 | /// 50 | public Disposable BorrowDisposable() { 51 | return Disposable.Borrow(Borrow(), release); 52 | } 53 | } 54 | } -------------------------------------------------------------------------------- /Assets/Smooth/Foundations/Pools/PoolWithInitializer.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using Smooth.Algebraics; 4 | using Smooth.Delegates; 5 | using Smooth.Dispose; 6 | 7 | namespace Smooth.Pools { 8 | /// 9 | /// Pool that lends values of type T with an optional initializer that takes a value of type U. 10 | /// 11 | public class PoolWithInitializer : Pool { 12 | private readonly DelegateAction initialize; 13 | 14 | /// 15 | /// Creates a new pool with the specified creation, reset, and initialization delegates. 16 | /// 17 | public PoolWithInitializer(DelegateFunc create, DelegateAction reset, DelegateAction initialize) : base (create, reset) { 18 | this.initialize = initialize; 19 | } 20 | 21 | /// 22 | /// Borrows a value from the pool and initializes it with the specified value. 23 | /// 24 | public T Borrow(U u) { 25 | var value = Borrow(); 26 | initialize(value, u); 27 | return value; 28 | } 29 | 30 | /// 31 | /// Borrows a wrapped value from from the pool and initializes it with the specified value. 32 | /// 33 | public Disposable BorrowDisposable(U u) { 34 | var wrapper = BorrowDisposable(); 35 | initialize(wrapper.value, u); 36 | return wrapper; 37 | } 38 | } 39 | } -------------------------------------------------------------------------------- /Assets/Smooth/Foundations/Pools/SystemPools.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Text; 4 | using Smooth.Dispose; 5 | 6 | namespace Smooth.Pools { 7 | /// 8 | /// Singleton Dictionary pool. 9 | /// 10 | public static class DictionaryPool { 11 | private static readonly KeyedPoolWithDefaultKey, Dictionary> _Instance = 12 | new KeyedPoolWithDefaultKey, Dictionary>( 13 | comparer => new Dictionary(comparer), 14 | dictionary => { dictionary.Clear(); return dictionary.Comparer; }, 15 | () => Smooth.Collections.EqualityComparer.Default 16 | ); 17 | 18 | /// 19 | /// Singleton Dictionary pool instance. 20 | /// 21 | public static KeyedPoolWithDefaultKey, Dictionary> Instance { get { return _Instance; } } 22 | } 23 | 24 | /// 25 | /// Singleton HashSet pool. 26 | /// 27 | public static class HashSetPool { 28 | private static readonly KeyedPoolWithDefaultKey, HashSet> _Instance = 29 | new KeyedPoolWithDefaultKey, HashSet>( 30 | comparer => new HashSet(comparer), 31 | hashSet => { hashSet.Clear(); return hashSet.Comparer; }, 32 | () => Smooth.Collections.EqualityComparer.Default 33 | ); 34 | 35 | /// 36 | /// Singleton HashSet pool instance. 37 | /// 38 | public static KeyedPoolWithDefaultKey, HashSet> Instance { get { return _Instance; } } 39 | } 40 | 41 | /// 42 | /// Singleton List pool. 43 | /// 44 | public static class ListPool { 45 | private static readonly Pool> _Instance = new Pool>( 46 | () => new List(), 47 | list => list.Clear()); 48 | 49 | /// 50 | /// Singleton List pool instance. 51 | /// 52 | public static Pool> Instance { get { return _Instance; } } 53 | } 54 | 55 | /// 56 | /// Singleton LinkedList pool. 57 | /// 58 | public static class LinkedListPool { 59 | private static readonly Pool> _Instance = new Pool>( 60 | () => new LinkedList(), 61 | list => { 62 | var node = list.First; 63 | while (node != null) { 64 | list.RemoveFirst(); 65 | LinkedListNodePool.Instance.Release(node); 66 | node = list.First; 67 | } 68 | } 69 | ); 70 | 71 | /// 72 | /// Singleton LinkedList pool instance. 73 | /// 74 | public static Pool> Instance { get { return _Instance; } } 75 | } 76 | 77 | /// 78 | /// Singleton LinkedListNode pool. 79 | /// 80 | public static class LinkedListNodePool { 81 | private static readonly PoolWithInitializer, T> _Instance = new PoolWithInitializer, T>( 82 | () => new LinkedListNode(default(T)), 83 | node => node.Value = default(T), 84 | (node, value) => node.Value = value 85 | ); 86 | 87 | /// 88 | /// Singleton LinkedListNode pool instance. 89 | /// 90 | public static PoolWithInitializer, T> Instance { get { return _Instance; } } 91 | } 92 | 93 | /// 94 | /// Singleton StringBuilder pool. 95 | /// 96 | public static class StringBuilderPool { 97 | private static readonly Pool _Instance = new Pool( 98 | () => new StringBuilder(), 99 | sb => sb.Length = 0); 100 | 101 | /// 102 | /// Singleton StringBuilder pool instance. 103 | /// 104 | public static Pool Instance { get { return _Instance; } } 105 | } 106 | } 107 | -------------------------------------------------------------------------------- /Assets/Smooth/Foundations/Slinq/Collections/Grouping.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace Smooth.Slinq.Collections { 4 | /// 5 | /// Represents a list of values associated with a key. 6 | /// 7 | /// The values are stored in Linked form to allow element reordering without the creation of new list nodes. 8 | /// 9 | public struct Grouping { 10 | /// 11 | /// The key associtated with the values. 12 | /// 13 | public readonly K key; 14 | 15 | /// 16 | /// The values associated with the key. 17 | /// 18 | public LinkedHeadTail values; 19 | 20 | /// 21 | /// Returns a grouping for the specified key and values. 22 | /// 23 | public Grouping(K key, LinkedHeadTail values) { 24 | this.key = key; 25 | this.values = values; 26 | } 27 | } 28 | 29 | /// 30 | /// Represents a list of values associated with a key. 31 | /// 32 | /// The values are stored in Slinq form for API simplicity and consistency. 33 | /// 34 | public struct Grouping { 35 | /// 36 | /// The key associtated with the values. 37 | /// 38 | public readonly K key; 39 | 40 | /// 41 | /// The values associated with the key. 42 | /// 43 | public Slinq values; 44 | 45 | /// 46 | /// Returns a grouping for the specified key and values. 47 | /// 48 | public Grouping(K key, Slinq values) { 49 | this.key = key; 50 | this.values = values; 51 | } 52 | } 53 | 54 | /// 55 | /// Extension methods for performing operations related to groupings without specifying generic parameters. 56 | /// 57 | public static class Grouping { 58 | /// 59 | /// Returns a grouping for the specified key and values. 60 | /// 61 | public static Grouping Create(K key, LinkedHeadTail values) { 62 | return new Grouping(key, values); 63 | } 64 | 65 | /// 66 | /// Returns a grouping for the specified key and values. 67 | /// 68 | public static Grouping Create(K key, Slinq values) { 69 | return new Grouping(key, values); 70 | } 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /Assets/Smooth/Foundations/Slinq/Context/ChainedOrPooled/AggregateContext.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Smooth.Algebraics; 3 | using Smooth.Delegates; 4 | 5 | namespace Smooth.Slinq.Context { 6 | 7 | #region Bare 8 | 9 | public struct AggregateContext { 10 | 11 | #region Slinqs 12 | 13 | public static Slinq> AggregateRunning(Slinq slinq, U seed, DelegateFunc selector) { 14 | return new Slinq>( 15 | skip, 16 | remove, 17 | dispose, 18 | new AggregateContext(slinq, seed, selector)); 19 | } 20 | 21 | #endregion 22 | 23 | #region Context 24 | 25 | private bool needsMove; 26 | private Slinq chained; 27 | private U acc; 28 | private readonly DelegateFunc selector; 29 | 30 | #pragma warning disable 0414 31 | private BacktrackDetector bd; 32 | #pragma warning restore 0414 33 | 34 | private AggregateContext(Slinq chained, U seed, DelegateFunc selector) { 35 | this.needsMove = false; 36 | this.chained = chained; 37 | this.acc = seed; 38 | this.selector = selector; 39 | 40 | this.bd = BacktrackDetector.Borrow(); 41 | } 42 | 43 | #endregion 44 | 45 | #region Delegates 46 | 47 | private static readonly Mutator> skip = Skip; 48 | private static readonly Mutator> remove = Remove; 49 | private static readonly Mutator> dispose = Dispose; 50 | 51 | private static void Skip(ref AggregateContext context, out Option next) { 52 | context.bd.DetectBacktrack(); 53 | 54 | if (context.needsMove) { 55 | context.chained.skip(ref context.chained.context, out context.chained.current); 56 | } else { 57 | context.needsMove = true; 58 | } 59 | 60 | if (context.chained.current.isSome) { 61 | context.acc = context.selector(context.acc, context.chained.current.value); 62 | next = new Option(context.acc); 63 | } else { 64 | next = new Option(); 65 | context.bd.Release(); 66 | } 67 | } 68 | 69 | private static void Remove(ref AggregateContext context, out Option next) { 70 | context.bd.DetectBacktrack(); 71 | 72 | context.needsMove = false; 73 | context.chained.remove(ref context.chained.context, out context.chained.current); 74 | Skip(ref context, out next); 75 | } 76 | 77 | private static void Dispose(ref AggregateContext context, out Option next) { 78 | next = new Option(); 79 | context.bd.Release(); 80 | context.chained.dispose(ref context.chained.context, out context.chained.current); 81 | } 82 | 83 | #endregion 84 | 85 | } 86 | 87 | #endregion 88 | 89 | #region With parameter 90 | 91 | public struct AggregateContext { 92 | 93 | #region Slinqs 94 | 95 | public static Slinq> AggregateRunning(Slinq slinq, U seed, DelegateFunc selector, P parameter) { 96 | return new Slinq>( 97 | skip, remove, dispose, 98 | new AggregateContext(slinq, seed, selector, parameter)); 99 | } 100 | 101 | #endregion 102 | 103 | #region Context 104 | 105 | private bool needsMove; 106 | private Slinq chained; 107 | private U acc; 108 | private readonly DelegateFunc selector; 109 | private readonly P parameter; 110 | 111 | #pragma warning disable 0414 112 | private BacktrackDetector bd; 113 | #pragma warning restore 0414 114 | 115 | private AggregateContext(Slinq chained, U seed, DelegateFunc selector, P parameter) { 116 | this.needsMove = false; 117 | this.chained = chained; 118 | this.acc = seed; 119 | this.selector = selector; 120 | this.parameter = parameter; 121 | 122 | this.bd = BacktrackDetector.Borrow(); 123 | } 124 | 125 | #endregion 126 | 127 | #region Delegates 128 | 129 | private static readonly Mutator> skip = Skip; 130 | private static readonly Mutator> remove = Remove; 131 | private static readonly Mutator> dispose = Dispose; 132 | 133 | private static void Skip(ref AggregateContext context, out Option next) { 134 | context.bd.DetectBacktrack(); 135 | 136 | if (context.needsMove) { 137 | context.chained.skip(ref context.chained.context, out context.chained.current); 138 | } else { 139 | context.needsMove = true; 140 | } 141 | 142 | if (context.chained.current.isSome) { 143 | context.acc = context.selector(context.acc, context.chained.current.value, context.parameter); 144 | next = new Option(context.acc); 145 | } else { 146 | next = new Option(); 147 | context.bd.Release(); 148 | } 149 | } 150 | 151 | private static void Remove(ref AggregateContext context, out Option next) { 152 | context.bd.DetectBacktrack(); 153 | 154 | context.needsMove = false; 155 | context.chained.remove(ref context.chained.context, out context.chained.current); 156 | Skip(ref context, out next); 157 | } 158 | 159 | private static void Dispose(ref AggregateContext context, out Option next) { 160 | next = new Option(); 161 | context.bd.Release(); 162 | context.chained.dispose(ref context.chained.context, out context.chained.current); 163 | } 164 | 165 | #endregion 166 | 167 | } 168 | 169 | #endregion 170 | 171 | } 172 | 173 | 174 | -------------------------------------------------------------------------------- /Assets/Smooth/Foundations/Slinq/Context/ChainedOrPooled/ConcatContext.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Smooth.Algebraics; 3 | 4 | namespace Smooth.Slinq.Context { 5 | public struct ConcatContext { 6 | 7 | #region Slinqs 8 | 9 | public static Slinq> Concat(Slinq first, Slinq second) { 10 | return new Slinq>( 11 | skip, 12 | remove, 13 | dispose, 14 | new ConcatContext(first, second)); 15 | } 16 | 17 | #endregion 18 | 19 | #region Context 20 | 21 | private bool needsMove; 22 | private Slinq first; 23 | private Slinq second; 24 | 25 | #pragma warning disable 0414 26 | private BacktrackDetector bd; 27 | #pragma warning restore 0414 28 | 29 | private ConcatContext(Slinq first, Slinq second) { 30 | this.needsMove = false; 31 | this.first = first; 32 | this.second = second; 33 | 34 | this.bd = BacktrackDetector.Borrow(); 35 | } 36 | 37 | #endregion 38 | 39 | #region Delegates 40 | 41 | private static readonly Mutator> skip = Skip; 42 | private static readonly Mutator> remove = Remove; 43 | private static readonly Mutator> dispose = Dispose; 44 | 45 | private static void Skip(ref ConcatContext context, out Option next) { 46 | context.bd.DetectBacktrack(); 47 | 48 | if (context.needsMove) { 49 | if (context.first.current.isSome) { 50 | context.first.skip(ref context.first.context, out context.first.current); 51 | } else { 52 | context.second.skip(ref context.second.context, out context.second.current); 53 | } 54 | } else { 55 | context.needsMove = true; 56 | } 57 | 58 | next = context.first.current.isSome ? context.first.current : context.second.current; 59 | 60 | if (!next.isSome) { 61 | context.bd.Release(); 62 | } 63 | } 64 | 65 | 66 | private static void Remove(ref ConcatContext context, out Option next) { 67 | context.bd.DetectBacktrack(); 68 | 69 | context.needsMove = false; 70 | if (context.first.current.isSome) { 71 | context.first.remove(ref context.first.context, out context.first.current); 72 | } else { 73 | context.second.remove(ref context.second.context, out context.second.current); 74 | } 75 | Skip(ref context, out next); 76 | } 77 | 78 | private static void Dispose(ref ConcatContext context, out Option next) { 79 | next = new Option(); 80 | 81 | context.bd.Release(); 82 | 83 | if (context.first.current.isSome) { 84 | context.first.dispose(ref context.first.context, out context.first.current); 85 | if (context.second.current.isSome) { 86 | context.second.dispose(ref context.second.context, out context.second.current); 87 | } 88 | } else { 89 | context.second.dispose(ref context.second.context, out context.second.current); 90 | } 91 | } 92 | 93 | #endregion 94 | 95 | } 96 | } 97 | 98 | 99 | -------------------------------------------------------------------------------- /Assets/Smooth/Foundations/Slinq/Context/ChainedOrPooled/EitherContext.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Smooth.Algebraics; 3 | 4 | namespace Smooth.Slinq.Context { 5 | public struct EitherContext { 6 | 7 | #region Slinqs 8 | 9 | public static Slinq> Left(Slinq left) { 10 | return new Slinq>( 11 | skip, 12 | remove, 13 | dispose, 14 | new EitherContext(left, default(Slinq), true)); 15 | } 16 | 17 | public static Slinq> Right(Slinq right) { 18 | return new Slinq>( 19 | skip, 20 | remove, 21 | dispose, 22 | new EitherContext(default(Slinq), right, false)); 23 | } 24 | 25 | #endregion 26 | 27 | #region Context 28 | 29 | private readonly bool isLeft; 30 | private bool needsMove; 31 | private Slinq left; 32 | private Slinq right; 33 | 34 | #pragma warning disable 0414 35 | private BacktrackDetector bd; 36 | #pragma warning restore 0414 37 | 38 | private EitherContext(Slinq left, Slinq right, bool isLeft) { 39 | this.needsMove = false; 40 | this.isLeft = isLeft; 41 | this.left = left; 42 | this.right = right; 43 | 44 | this.bd = BacktrackDetector.Borrow(); 45 | } 46 | 47 | #endregion 48 | 49 | #region Delegates 50 | 51 | private static readonly Mutator> skip = Skip; 52 | private static readonly Mutator> remove = Remove; 53 | private static readonly Mutator> dispose = Dispose; 54 | 55 | private static void Skip(ref EitherContext context, out Option next) { 56 | context.bd.DetectBacktrack(); 57 | 58 | if (context.needsMove) { 59 | if (context.isLeft) { 60 | context.left.skip(ref context.left.context, out context.left.current); 61 | } else { 62 | context.right.skip(ref context.right.context, out context.right.current); 63 | } 64 | } else { 65 | context.needsMove = true; 66 | } 67 | 68 | next = context.isLeft ? context.left.current : context.right.current; 69 | 70 | if (!next.isSome) { 71 | context.bd.Release(); 72 | } 73 | } 74 | 75 | 76 | private static void Remove(ref EitherContext context, out Option next) { 77 | context.bd.DetectBacktrack(); 78 | 79 | context.needsMove = false; 80 | if (context.isLeft) { 81 | context.left.remove(ref context.left.context, out context.left.current); 82 | } else { 83 | context.right.remove(ref context.right.context, out context.right.current); 84 | } 85 | Skip(ref context, out next); 86 | } 87 | 88 | private static void Dispose(ref EitherContext context, out Option next) { 89 | next = Option.None; 90 | 91 | context.bd.Release(); 92 | 93 | if (context.isLeft) { 94 | context.left.dispose(ref context.left.context, out context.left.current); 95 | } else { 96 | context.right.dispose(ref context.right.context, out context.right.current); 97 | } 98 | } 99 | 100 | #endregion 101 | 102 | } 103 | } 104 | 105 | 106 | -------------------------------------------------------------------------------- /Assets/Smooth/Foundations/Slinq/Context/ChainedOrPooled/FlattenContext.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Smooth.Algebraics; 3 | 4 | namespace Smooth.Slinq.Context { 5 | 6 | #region Slinq 7 | 8 | public struct FlattenContext { 9 | 10 | #region Slinqs 11 | 12 | public static Slinq> Flatten(Slinq, C2> slinq) { 13 | return new Slinq>( 14 | skip, 15 | remove, 16 | dispose, 17 | new FlattenContext(slinq)); 18 | } 19 | 20 | #endregion 21 | 22 | #region Context 23 | 24 | private bool needsMove; 25 | private Slinq, C2> chained; 26 | private Slinq selected; 27 | 28 | #pragma warning disable 0414 29 | private BacktrackDetector bd; 30 | #pragma warning restore 0414 31 | 32 | private FlattenContext(Slinq, C2> chained) { 33 | this.needsMove = false; 34 | this.chained = chained; 35 | this.selected = chained.current.isSome ? chained.current.value : new Slinq(); 36 | 37 | this.bd = BacktrackDetector.Borrow(); 38 | } 39 | 40 | #endregion 41 | 42 | #region Delegates 43 | 44 | private static readonly Mutator> skip = Skip; 45 | private static readonly Mutator> remove = Remove; 46 | private static readonly Mutator> dispose = Dispose; 47 | 48 | private static void Skip(ref FlattenContext context, out Option next) { 49 | context.bd.DetectBacktrack(); 50 | 51 | if (context.needsMove) { 52 | context.selected.skip(ref context.selected.context, out context.selected.current); 53 | } else { 54 | context.needsMove = true; 55 | } 56 | 57 | if (!context.selected.current.isSome && context.chained.current.isSome) { 58 | context.chained.skip(ref context.chained.context, out context.chained.current); 59 | while (context.chained.current.isSome) { 60 | context.selected = context.chained.current.value; 61 | if (context.selected.current.isSome) { 62 | break; 63 | } else { 64 | context.chained.skip(ref context.chained.context, out context.chained.current); 65 | } 66 | } 67 | } 68 | 69 | next = context.selected.current; 70 | 71 | if (!next.isSome) { 72 | context.bd.Release(); 73 | } 74 | } 75 | 76 | private static void Remove(ref FlattenContext context, out Option next) { 77 | context.bd.DetectBacktrack(); 78 | 79 | context.needsMove = false; 80 | context.selected.remove(ref context.selected.context, out context.selected.current); 81 | Skip(ref context, out next); 82 | } 83 | 84 | private static void Dispose(ref FlattenContext context, out Option next) { 85 | next = new Option(); 86 | context.bd.Release(); 87 | context.chained.dispose(ref context.chained.context, out context.chained.current); 88 | context.selected.dispose(ref context.selected.context, out context.selected.current); 89 | } 90 | 91 | #endregion 92 | 93 | } 94 | 95 | #endregion 96 | 97 | #region Option 98 | 99 | public struct FlattenContext { 100 | 101 | #region Slinqs 102 | 103 | public static Slinq> Flatten(Slinq, C> slinq) { 104 | return new Slinq>( 105 | skip, 106 | remove, 107 | dispose, 108 | new FlattenContext(slinq)); 109 | } 110 | 111 | #endregion 112 | 113 | #region Context 114 | 115 | private bool needsMove; 116 | private Slinq, C> chained; 117 | 118 | #pragma warning disable 0414 119 | private BacktrackDetector bd; 120 | #pragma warning restore 0414 121 | 122 | private FlattenContext(Slinq, C> chained) { 123 | this.needsMove = false; 124 | this.chained = chained; 125 | 126 | this.bd = BacktrackDetector.Borrow(); 127 | } 128 | 129 | #endregion 130 | 131 | #region Delegates 132 | 133 | private static readonly Mutator> skip = Skip; 134 | private static readonly Mutator> remove = Remove; 135 | private static readonly Mutator> dispose = Dispose; 136 | 137 | private static void Skip(ref FlattenContext context, out Option next) { 138 | context.bd.DetectBacktrack(); 139 | 140 | if (context.needsMove) { 141 | context.chained.skip(ref context.chained.context, out context.chained.current); 142 | } else { 143 | context.needsMove = true; 144 | } 145 | 146 | while (context.chained.current.isSome && !context.chained.current.value.isSome) { 147 | context.chained.skip(ref context.chained.context, out context.chained.current); 148 | } 149 | 150 | if (context.chained.current.isSome) { 151 | next = context.chained.current.value; 152 | } else { 153 | next = new Option(); 154 | context.bd.Release(); 155 | } 156 | } 157 | 158 | private static void Remove(ref FlattenContext context, out Option next) { 159 | context.bd.DetectBacktrack(); 160 | 161 | context.needsMove = false; 162 | context.chained.remove(ref context.chained.context, out context.chained.current); 163 | Skip(ref context, out next); 164 | } 165 | 166 | private static void Dispose(ref FlattenContext context, out Option next) { 167 | next = new Option(); 168 | context.bd.Release(); 169 | context.chained.dispose(ref context.chained.context, out context.chained.current); 170 | } 171 | 172 | #endregion 173 | 174 | } 175 | 176 | #endregion 177 | 178 | } 179 | -------------------------------------------------------------------------------- /Assets/Smooth/Foundations/Slinq/Context/ChainedOrPooled/GroupByContext.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Smooth.Algebraics; 3 | using Smooth.Slinq.Collections; 4 | 5 | namespace Smooth.Slinq.Context { 6 | 7 | public struct GroupByContext { 8 | 9 | #region Slinqs 10 | 11 | public static Slinq>, GroupByContext> Slinq(Lookup lookup, bool release) { 12 | return new Slinq>, GroupByContext>( 13 | slinqedSkip, 14 | slinqedRemove, 15 | slinqedDispose, 16 | new GroupByContext(lookup, release)); 17 | } 18 | 19 | public static Slinq, GroupByContext> SlinqLinked(Lookup lookup, bool release) { 20 | return new Slinq, GroupByContext>( 21 | linkedSkip, 22 | linkedRemove, 23 | linkedDispose, 24 | new GroupByContext(lookup, release)); 25 | } 26 | 27 | #endregion 28 | 29 | #region Instance 30 | 31 | private readonly Lookup lookup; 32 | private readonly bool release; 33 | private Linked runner; 34 | 35 | #pragma warning disable 0414 36 | private BacktrackDetector bd; 37 | #pragma warning restore 0414 38 | 39 | private GroupByContext(Lookup lookup, bool release) { 40 | this.lookup = lookup; 41 | this.release = release; 42 | this.runner = lookup.keys.head; 43 | 44 | this.bd = BacktrackDetector.Borrow(); 45 | } 46 | 47 | #endregion 48 | 49 | #region Delegates 50 | 51 | #region Linked 52 | 53 | private static readonly Mutator, GroupByContext> linkedSkip = LinkedSkip; 54 | private static readonly Mutator, GroupByContext> linkedRemove = LinkedRemove; 55 | private static readonly Mutator, GroupByContext> linkedDispose = LinkedDispose; 56 | 57 | private static void LinkedSkip(ref GroupByContext context, out Option> next) { 58 | context.bd.DetectBacktrack(); 59 | 60 | if (context.runner == null) { 61 | next = new Option>(); 62 | context.bd.Release(); 63 | if (context.release) { 64 | context.lookup.DisposeInBackground(); 65 | } 66 | } else { 67 | next = new Option>( 68 | new Grouping(context.runner.value, 69 | context.release ? 70 | context.lookup.RemoveValues(context.runner.value) : 71 | context.lookup.GetValues(context.runner.value))); 72 | context.runner = context.runner.next; 73 | } 74 | } 75 | 76 | private static void LinkedRemove(ref GroupByContext context, out Option> next) { 77 | throw new NotSupportedException(); 78 | } 79 | 80 | private static void LinkedDispose(ref GroupByContext context, out Option> next) { 81 | next = new Option>(); 82 | context.bd.Release(); 83 | if (context.release) { 84 | context.lookup.DisposeInBackground(); 85 | } 86 | } 87 | 88 | #endregion 89 | 90 | #region Slinqed 91 | 92 | private static readonly Mutator>, GroupByContext> slinqedSkip = SlinqedSkip; 93 | private static readonly Mutator>, GroupByContext> slinqedRemove = SlinqedRemove; 94 | private static readonly Mutator>, GroupByContext> slinqedDispose = SlinqedDispose; 95 | 96 | private static void SlinqedSkip(ref GroupByContext context, out Option>> next) { 97 | context.bd.DetectBacktrack(); 98 | 99 | if (context.runner == null) { 100 | next = new Option>>(); 101 | context.bd.Release(); 102 | if (context.release) { 103 | context.lookup.DisposeInBackground(); 104 | } 105 | } else { 106 | next = new Option>>( 107 | new Grouping>(context.runner.value, 108 | context.release ? 109 | context.lookup.RemoveValues(context.runner.value).SlinqAndDispose() : 110 | context.lookup.GetValues(context.runner.value).SlinqAndKeep())); 111 | context.runner = context.runner.next; 112 | } 113 | } 114 | 115 | private static void SlinqedRemove(ref GroupByContext context, out Option>> next) { 116 | throw new NotSupportedException(); 117 | } 118 | 119 | private static void SlinqedDispose(ref GroupByContext context, out Option>> next) { 120 | next = new Option>>(); 121 | context.bd.Release(); 122 | if (context.release) { 123 | context.lookup.DisposeInBackground(); 124 | } 125 | } 126 | 127 | #endregion 128 | 129 | #endregion 130 | 131 | } 132 | } -------------------------------------------------------------------------------- /Assets/Smooth/Foundations/Slinq/Context/ChainedOrPooled/GroupJoinContext.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Smooth.Algebraics; 3 | using Smooth.Delegates; 4 | using Smooth.Slinq.Collections; 5 | 6 | namespace Smooth.Slinq.Context { 7 | 8 | #region Bare 9 | 10 | public struct GroupJoinContext { 11 | 12 | #region Slinqs 13 | 14 | public static Slinq> GroupJoin(Lookup lookup, Slinq outer, DelegateFunc outerSelector, DelegateFunc>, U> resultSelector, bool release) { 15 | return new Slinq>( 16 | skip, 17 | remove, 18 | dispose, 19 | new GroupJoinContext(lookup, outer, outerSelector, resultSelector, release)); 20 | } 21 | 22 | #endregion 23 | 24 | #region Instance 25 | 26 | private bool needsMove; 27 | private readonly Lookup lookup; 28 | private readonly DelegateFunc outerSelector; 29 | private readonly DelegateFunc>, U> resultSelector; 30 | private readonly bool release; 31 | private Slinq chained; 32 | 33 | #pragma warning disable 0414 34 | private BacktrackDetector bd; 35 | #pragma warning restore 0414 36 | 37 | private GroupJoinContext(Lookup lookup, Slinq outer, DelegateFunc outerSelector, DelegateFunc>, U> resultSelector, bool release) { 38 | this.needsMove = false; 39 | this.lookup = lookup; 40 | this.outerSelector = outerSelector; 41 | this.resultSelector = resultSelector; 42 | this.chained = outer; 43 | this.release = release; 44 | 45 | this.bd = BacktrackDetector.Borrow(); 46 | } 47 | 48 | #endregion 49 | 50 | #region Delegates 51 | 52 | private static readonly Mutator> skip = Skip; 53 | private static readonly Mutator> remove = Remove; 54 | private static readonly Mutator> dispose = Dispose; 55 | 56 | private static void Skip(ref GroupJoinContext context, out Option next) { 57 | context.bd.DetectBacktrack(); 58 | 59 | if (context.needsMove) { 60 | context.chained.skip(ref context.chained.context, out context.chained.current); 61 | } else { 62 | context.needsMove = true; 63 | } 64 | 65 | if (context.chained.current.isSome) { 66 | var bd = BacktrackDetector.Borrow(); 67 | next = new Option(context.resultSelector( 68 | context.chained.current.value, 69 | context.lookup.GetValues(context.outerSelector(context.chained.current.value)).SlinqAndKeep(bd))); 70 | bd.TryReleaseShared(); 71 | } else { 72 | next = new Option(); 73 | context.bd.Release(); 74 | if (context.release) { 75 | context.lookup.DisposeInBackground(); 76 | } 77 | } 78 | } 79 | 80 | private static void Remove(ref GroupJoinContext context, out Option next) { 81 | context.bd.DetectBacktrack(); 82 | 83 | context.needsMove = false; 84 | context.chained.remove(ref context.chained.context, out context.chained.current); 85 | Skip(ref context, out next); 86 | } 87 | 88 | private static void Dispose(ref GroupJoinContext context, out Option next) { 89 | next = new Option(); 90 | context.bd.Release(); 91 | context.chained.dispose(ref context.chained.context, out context.chained.current); 92 | if (context.release) { 93 | context.lookup.DisposeInBackground(); 94 | } 95 | } 96 | 97 | #endregion 98 | 99 | } 100 | 101 | #endregion 102 | 103 | #region With parameter 104 | 105 | public struct GroupJoinContext { 106 | 107 | #region Slinqs 108 | 109 | public static Slinq> GroupJoin(Lookup lookup, Slinq outer, DelegateFunc outerSelector, DelegateFunc>, P, U> resultSelector, P parameter, bool release) { 110 | return new Slinq>( 111 | skip, 112 | remove, 113 | dispose, 114 | new GroupJoinContext(lookup, outer, outerSelector, resultSelector, parameter, release)); 115 | } 116 | 117 | #endregion 118 | 119 | #region Instance 120 | 121 | private bool needsMove; 122 | private readonly Lookup lookup; 123 | private readonly DelegateFunc outerSelector; 124 | private readonly DelegateFunc>, P, U> resultSelector; 125 | private readonly P parameter; 126 | private readonly bool release; 127 | private Slinq chained; 128 | 129 | #pragma warning disable 0414 130 | private BacktrackDetector bd; 131 | #pragma warning restore 0414 132 | 133 | private GroupJoinContext(Lookup lookup, Slinq outer, DelegateFunc outerSelector, DelegateFunc>, P, U> resultSelector, P parameter, bool release) { 134 | this.needsMove = false; 135 | this.lookup = lookup; 136 | this.outerSelector = outerSelector; 137 | this.resultSelector = resultSelector; 138 | this.parameter = parameter; 139 | this.chained = outer; 140 | this.release = release; 141 | 142 | this.bd = BacktrackDetector.Borrow(); 143 | } 144 | 145 | #endregion 146 | 147 | #region Delegates 148 | 149 | private static readonly Mutator> skip = Skip; 150 | private static readonly Mutator> remove = Remove; 151 | private static readonly Mutator> dispose = Dispose; 152 | 153 | private static void Skip(ref GroupJoinContext context, out Option next) { 154 | context.bd.DetectBacktrack(); 155 | 156 | if (context.needsMove) { 157 | context.chained.skip(ref context.chained.context, out context.chained.current); 158 | } else { 159 | context.needsMove = true; 160 | } 161 | 162 | if (context.chained.current.isSome) { 163 | var bd = BacktrackDetector.Borrow(); 164 | next = new Option(context.resultSelector( 165 | context.chained.current.value, 166 | context.lookup.GetValues(context.outerSelector(context.chained.current.value, context.parameter)).SlinqAndKeep(bd), 167 | context.parameter)); 168 | bd.TryReleaseShared(); 169 | } else { 170 | next = new Option(); 171 | context.bd.Release(); 172 | if (context.release) { 173 | context.lookup.DisposeInBackground(); 174 | } 175 | } 176 | } 177 | 178 | private static void Remove(ref GroupJoinContext context, out Option next) { 179 | context.bd.DetectBacktrack(); 180 | 181 | context.needsMove = false; 182 | context.chained.remove(ref context.chained.context, out context.chained.current); 183 | Skip(ref context, out next); 184 | } 185 | 186 | private static void Dispose(ref GroupJoinContext context, out Option next) { 187 | next = new Option(); 188 | context.bd.Release(); 189 | context.chained.dispose(ref context.chained.context, out context.chained.current); 190 | if (context.release) { 191 | context.lookup.DisposeInBackground(); 192 | } 193 | } 194 | 195 | #endregion 196 | 197 | } 198 | 199 | #endregion 200 | 201 | } 202 | -------------------------------------------------------------------------------- /Assets/Smooth/Foundations/Slinq/Context/ChainedOrPooled/IntContext.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Smooth.Algebraics; 3 | 4 | namespace Smooth.Slinq.Context { 5 | public struct IntContext { 6 | 7 | #region Slinqs 8 | 9 | public static Slinq> Take(Slinq slinq, int count) { 10 | return new Slinq>( 11 | skip, 12 | remove, 13 | dispose, 14 | new IntContext(slinq, count)); 15 | } 16 | 17 | #endregion 18 | 19 | #region Context 20 | 21 | private bool needsMove; 22 | private Slinq chained; 23 | private int count; 24 | 25 | #pragma warning disable 0414 26 | private BacktrackDetector bd; 27 | #pragma warning restore 0414 28 | 29 | private IntContext(Slinq chained, int count) { 30 | this.needsMove = false; 31 | this.chained = chained; 32 | this.count = count; 33 | 34 | this.bd = BacktrackDetector.Borrow(); 35 | } 36 | 37 | #endregion 38 | 39 | #region Delegates 40 | 41 | private static readonly Mutator> skip = Skip; 42 | private static readonly Mutator> remove = Remove; 43 | private static readonly Mutator> dispose = Dispose; 44 | 45 | private static void Skip(ref IntContext context, out Option next) { 46 | context.bd.DetectBacktrack(); 47 | 48 | if (context.count-- > 0) { 49 | if (context.needsMove) { 50 | context.chained.skip(ref context.chained.context, out context.chained.current); 51 | } else { 52 | context.needsMove = true; 53 | } 54 | } else if (context.chained.current.isSome) { 55 | context.chained.dispose(ref context.chained.context, out context.chained.current); 56 | } 57 | 58 | next = context.chained.current; 59 | 60 | if (!next.isSome) { 61 | context.bd.Release(); 62 | } 63 | } 64 | 65 | private static void Remove(ref IntContext context, out Option next) { 66 | context.bd.DetectBacktrack(); 67 | 68 | context.needsMove = false; 69 | context.chained.remove(ref context.chained.context, out context.chained.current); 70 | Skip(ref context, out next); 71 | } 72 | 73 | private static void Dispose(ref IntContext context, out Option next) { 74 | next = new Option(); 75 | context.bd.Release(); 76 | context.chained.dispose(ref context.chained.context, out context.chained.current); 77 | } 78 | 79 | #endregion 80 | 81 | } 82 | } 83 | 84 | 85 | -------------------------------------------------------------------------------- /Assets/Smooth/Foundations/Slinq/Context/ChainedOrPooled/JoinContext.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Smooth.Algebraics; 3 | using Smooth.Delegates; 4 | using Smooth.Slinq.Collections; 5 | 6 | namespace Smooth.Slinq.Context { 7 | 8 | #region Bare 9 | 10 | public struct JoinContext { 11 | 12 | #region Slinqs 13 | 14 | public static Slinq> Join(Lookup lookup, Slinq outer, DelegateFunc outerSelector, DelegateFunc resultSelector, bool release) { 15 | return new Slinq>( 16 | skip, 17 | remove, 18 | dispose, 19 | new JoinContext(lookup, outer, outerSelector, resultSelector, release)); 20 | } 21 | 22 | #endregion 23 | 24 | #region Instance 25 | 26 | private bool needsMove; 27 | private readonly Lookup lookup; 28 | private readonly DelegateFunc outerSelector; 29 | private readonly DelegateFunc resultSelector; 30 | private readonly bool release; 31 | private Slinq chained; 32 | private Linked inner; 33 | 34 | #pragma warning disable 0414 35 | private BacktrackDetector bd; 36 | #pragma warning restore 0414 37 | 38 | private JoinContext(Lookup lookup, Slinq outer, DelegateFunc outerSelector, DelegateFunc resultSelector, bool release) { 39 | this.needsMove = false; 40 | this.lookup = lookup; 41 | this.outerSelector = outerSelector; 42 | this.resultSelector = resultSelector; 43 | this.chained = outer; 44 | this.release = release; 45 | 46 | LinkedHeadTail iht; 47 | this.inner = chained.current.isSome && lookup.dictionary.TryGetValue(outerSelector(chained.current.value), out iht) ? iht.head : null; 48 | 49 | this.bd = BacktrackDetector.Borrow(); 50 | } 51 | 52 | #endregion 53 | 54 | #region Delegates 55 | 56 | private static readonly Mutator> skip = Skip; 57 | private static readonly Mutator> remove = Remove; 58 | private static readonly Mutator> dispose = Dispose; 59 | 60 | private static void Skip(ref JoinContext context, out Option next) { 61 | context.bd.DetectBacktrack(); 62 | 63 | if (context.needsMove) { 64 | context.inner = context.inner.next; 65 | } else { 66 | context.needsMove = true; 67 | } 68 | 69 | if (context.inner == null && context.chained.current.isSome) { 70 | context.chained.skip(ref context.chained.context, out context.chained.current); 71 | while (context.chained.current.isSome) { 72 | context.inner = context.lookup.GetValues(context.outerSelector(context.chained.current.value)).head; 73 | if (context.inner == null) { 74 | context.chained.skip(ref context.chained.context, out context.chained.current); 75 | } else { 76 | break; 77 | } 78 | } 79 | } 80 | 81 | if (context.chained.current.isSome) { 82 | next = new Option(context.resultSelector(context.chained.current.value, context.inner.value)); 83 | } else { 84 | next = new Option(); 85 | context.bd.Release(); 86 | if (context.release) { 87 | context.lookup.DisposeInBackground(); 88 | } 89 | } 90 | } 91 | 92 | private static void Remove(ref JoinContext context, out Option next) { 93 | context.bd.DetectBacktrack(); 94 | 95 | context.needsMove = false; 96 | context.chained.remove(ref context.chained.context, out context.chained.current); 97 | 98 | context.inner = context.chained.current.isSome ? 99 | context.lookup.GetValues(context.outerSelector(context.chained.current.value)).head : 100 | null; 101 | 102 | Skip(ref context, out next); 103 | } 104 | 105 | private static void Dispose(ref JoinContext context, out Option next) { 106 | next = new Option(); 107 | context.bd.Release(); 108 | context.chained.dispose(ref context.chained.context, out context.chained.current); 109 | if (context.release) { 110 | context.lookup.DisposeInBackground(); 111 | } 112 | } 113 | 114 | #endregion 115 | 116 | } 117 | 118 | #endregion 119 | 120 | #region With parameter 121 | 122 | public struct JoinContext { 123 | 124 | #region Slinqs 125 | 126 | public static Slinq> Join(Lookup lookup, Slinq outer, DelegateFunc outerSelector, DelegateFunc resultSelector, P parameter, bool release) { 127 | return new Slinq>( 128 | skip, 129 | remove, 130 | dispose, 131 | new JoinContext(lookup, outer, outerSelector, resultSelector, parameter, release)); 132 | } 133 | 134 | #endregion 135 | 136 | #region Instance 137 | 138 | private bool needsMove; 139 | private readonly Lookup lookup; 140 | private readonly DelegateFunc outerSelector; 141 | private readonly DelegateFunc resultSelector; 142 | private readonly P parameter; 143 | private readonly bool release; 144 | private Slinq chained; 145 | private Linked inner; 146 | 147 | #pragma warning disable 0414 148 | private BacktrackDetector bd; 149 | #pragma warning restore 0414 150 | 151 | private JoinContext(Lookup lookup, Slinq outer, DelegateFunc outerSelector, DelegateFunc resultSelector, P parameter, bool release) { 152 | this.needsMove = false; 153 | this.lookup = lookup; 154 | this.outerSelector = outerSelector; 155 | this.resultSelector = resultSelector; 156 | this.parameter = parameter; 157 | this.chained = outer; 158 | this.release = release; 159 | 160 | LinkedHeadTail iht; 161 | this.inner = chained.current.isSome && lookup.dictionary.TryGetValue(outerSelector(chained.current.value, parameter), out iht) ? iht.head : null; 162 | 163 | this.bd = BacktrackDetector.Borrow(); 164 | } 165 | 166 | #endregion 167 | 168 | #region Delegates 169 | 170 | private static readonly Mutator> skip = Skip; 171 | private static readonly Mutator> remove = Remove; 172 | private static readonly Mutator> dispose = Dispose; 173 | 174 | private static void Skip(ref JoinContext context, out Option next) { 175 | context.bd.DetectBacktrack(); 176 | 177 | if (context.needsMove) { 178 | context.inner = context.inner.next; 179 | } else { 180 | context.needsMove = true; 181 | } 182 | 183 | if (context.inner == null && context.chained.current.isSome) { 184 | context.chained.skip(ref context.chained.context, out context.chained.current); 185 | while (context.chained.current.isSome) { 186 | context.inner = context.lookup.GetValues(context.outerSelector(context.chained.current.value, context.parameter)).head; 187 | if (context.inner == null) { 188 | context.chained.skip(ref context.chained.context, out context.chained.current); 189 | } else { 190 | break; 191 | } 192 | } 193 | } 194 | 195 | if (context.chained.current.isSome) { 196 | next = new Option(context.resultSelector(context.chained.current.value, context.inner.value, context.parameter)); 197 | } else { 198 | next = new Option(); 199 | context.bd.Release(); 200 | if (context.release) { 201 | context.lookup.DisposeInBackground(); 202 | } 203 | } 204 | } 205 | 206 | private static void Remove(ref JoinContext context, out Option next) { 207 | context.bd.DetectBacktrack(); 208 | 209 | context.needsMove = false; 210 | context.chained.remove(ref context.chained.context, out context.chained.current); 211 | 212 | context.inner = context.chained.current.isSome ? 213 | context.lookup.GetValues(context.outerSelector(context.chained.current.value, context.parameter)).head : 214 | null; 215 | 216 | Skip(ref context, out next); 217 | } 218 | 219 | private static void Dispose(ref JoinContext context, out Option next) { 220 | next = new Option(); 221 | context.bd.Release(); 222 | context.chained.dispose(ref context.chained.context, out context.chained.current); 223 | if (context.release) { 224 | context.lookup.DisposeInBackground(); 225 | } 226 | } 227 | 228 | #endregion 229 | 230 | } 231 | 232 | #endregion 233 | 234 | } 235 | -------------------------------------------------------------------------------- /Assets/Smooth/Foundations/Slinq/Context/ChainedOrPooled/LinkedContext.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Smooth.Algebraics; 3 | using Smooth.Slinq.Collections; 4 | 5 | namespace Smooth.Slinq.Context { 6 | 7 | #region Just values 8 | 9 | public struct LinkedContext { 10 | 11 | #region Slinqs 12 | 13 | public static Slinq> Slinq(LinkedHeadTail list, bool release) { 14 | return new Slinq>( 15 | skip, 16 | remove, 17 | dispose, 18 | new LinkedContext(list, BacktrackDetector.Borrow(), release)); 19 | } 20 | 21 | public static Slinq> Slinq(LinkedHeadTail list, BacktrackDetector bd, bool release) { 22 | return new Slinq>( 23 | skip, 24 | remove, 25 | dispose, 26 | new LinkedContext(list, bd, release)); 27 | } 28 | 29 | #endregion 30 | 31 | #region Instance 32 | 33 | private readonly LinkedHeadTail list; 34 | private readonly bool release; 35 | private Linked runner; 36 | 37 | #pragma warning disable 0414 38 | private BacktrackDetector bd; 39 | #pragma warning restore 0414 40 | 41 | private LinkedContext(LinkedHeadTail list, BacktrackDetector bd, bool release) { 42 | this.list = list; 43 | this.runner = list.head; 44 | this.release = release; 45 | 46 | this.bd = bd; 47 | } 48 | 49 | #endregion 50 | 51 | #region Delegates 52 | 53 | private static readonly Mutator> skip = Skip; 54 | private static readonly Mutator> remove = Remove; 55 | private static readonly Mutator> dispose = Dispose; 56 | 57 | private static void Skip(ref LinkedContext context, out Option next) { 58 | context.bd.DetectBacktrack(); 59 | 60 | if (context.runner == null) { 61 | next = new Option(); 62 | context.bd.Release(); 63 | if (context.release) { 64 | context.list.DisposeInBackground(); 65 | } 66 | } else { 67 | next = new Option(context.runner.value); 68 | context.runner = context.runner.next; 69 | } 70 | } 71 | 72 | private static void Remove(ref LinkedContext context, out Option next) { 73 | throw new NotSupportedException(); 74 | } 75 | 76 | private static void Dispose(ref LinkedContext context, out Option next) { 77 | next = new Option(); 78 | context.bd.Release(); 79 | if (context.release) { 80 | context.list.DisposeInBackground(); 81 | } 82 | } 83 | 84 | #endregion 85 | 86 | } 87 | 88 | #endregion 89 | 90 | #region Keyed 91 | 92 | public struct LinkedContext { 93 | 94 | #region Slinqs 95 | 96 | public static Slinq> Slinq(LinkedHeadTail list, bool release) { 97 | return new Slinq>( 98 | skip, 99 | remove, 100 | dispose, 101 | new LinkedContext(list, BacktrackDetector.Borrow(), release)); 102 | } 103 | 104 | public static Slinq> Slinq(LinkedHeadTail list, BacktrackDetector bd, bool release) { 105 | return new Slinq>( 106 | skip, 107 | remove, 108 | dispose, 109 | new LinkedContext(list, bd, release)); 110 | } 111 | 112 | #endregion 113 | 114 | #region Instance 115 | 116 | private readonly LinkedHeadTail list; 117 | private readonly bool release; 118 | private Linked runner; 119 | 120 | #pragma warning disable 0414 121 | private BacktrackDetector bd; 122 | #pragma warning restore 0414 123 | 124 | private LinkedContext(LinkedHeadTail list, BacktrackDetector bd, bool release) { 125 | this.list = list; 126 | this.runner = list.head; 127 | this.release = release; 128 | 129 | this.bd = bd; 130 | } 131 | 132 | #endregion 133 | 134 | #region Delegates 135 | 136 | private static readonly Mutator> skip = Skip; 137 | private static readonly Mutator> remove = Remove; 138 | private static readonly Mutator> dispose = Dispose; 139 | 140 | private static void Skip(ref LinkedContext context, out Option next) { 141 | context.bd.DetectBacktrack(); 142 | 143 | if (context.runner == null) { 144 | next = new Option(); 145 | context.bd.Release(); 146 | if (context.release) { 147 | context.list.DisposeInBackground(); 148 | } 149 | } else { 150 | next = new Option(context.runner.value); 151 | context.runner = context.runner.next; 152 | } 153 | } 154 | 155 | private static void Remove(ref LinkedContext context, out Option next) { 156 | throw new NotSupportedException(); 157 | } 158 | 159 | private static void Dispose(ref LinkedContext context, out Option next) { 160 | next = new Option(); 161 | context.bd.Release(); 162 | if (context.release) { 163 | context.list.DisposeInBackground(); 164 | } 165 | } 166 | 167 | #endregion 168 | 169 | } 170 | 171 | #endregion 172 | 173 | } 174 | -------------------------------------------------------------------------------- /Assets/Smooth/Foundations/Slinq/Context/ChainedOrPooled/PredicateContext.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Smooth.Algebraics; 3 | using Smooth.Delegates; 4 | 5 | namespace Smooth.Slinq.Context { 6 | 7 | #region No parameter 8 | 9 | public struct PredicateContext { 10 | 11 | #region Slinqs 12 | 13 | public static Slinq> TakeWhile(Slinq slinq, DelegateFunc predicate) { 14 | return new Slinq>( 15 | takeWhileSkip, 16 | takeWhileRemove, 17 | dispose, 18 | new PredicateContext(slinq, predicate)); 19 | } 20 | 21 | public static Slinq> Where(Slinq slinq, DelegateFunc predicate) { 22 | return new Slinq>( 23 | whereSkip, 24 | whereRemove, 25 | dispose, 26 | new PredicateContext(slinq, predicate)); 27 | } 28 | 29 | #endregion 30 | 31 | #region Context 32 | 33 | private bool needsMove; 34 | private Slinq chained; 35 | private readonly DelegateFunc predicate; 36 | 37 | #pragma warning disable 0414 38 | private BacktrackDetector bd; 39 | #pragma warning restore 0414 40 | 41 | private PredicateContext(Slinq chained, DelegateFunc predicate) { 42 | this.needsMove = false; 43 | this.chained = chained; 44 | this.predicate = predicate; 45 | 46 | this.bd = BacktrackDetector.Borrow(); 47 | } 48 | 49 | #endregion 50 | 51 | #region Dispose 52 | 53 | private static readonly Mutator> dispose = Dispose; 54 | 55 | private static void Dispose(ref PredicateContext context, out Option next) { 56 | next = new Option(); 57 | context.bd.Release(); 58 | context.chained.dispose(ref context.chained.context, out context.chained.current); 59 | } 60 | 61 | #endregion 62 | 63 | #region TakeWhile 64 | 65 | private static readonly Mutator> takeWhileSkip = TakeWhileSkip; 66 | private static readonly Mutator> takeWhileRemove = TakeWhileRemove; 67 | 68 | private static void TakeWhileSkip(ref PredicateContext context, out Option next) { 69 | context.bd.DetectBacktrack(); 70 | 71 | if (context.needsMove) { 72 | context.chained.skip(ref context.chained.context, out context.chained.current); 73 | } else { 74 | context.needsMove = true; 75 | } 76 | 77 | if (!context.chained.current.isSome) { 78 | next = context.chained.current; 79 | context.bd.Release(); 80 | } else if (context.predicate(context.chained.current.value)) { 81 | next = context.chained.current; 82 | } else { 83 | next = new Option(); 84 | context.bd.Release(); 85 | context.chained.dispose(ref context.chained.context, out context.chained.current); 86 | } 87 | } 88 | 89 | private static void TakeWhileRemove(ref PredicateContext context, out Option next) { 90 | context.bd.DetectBacktrack(); 91 | 92 | context.needsMove = false; 93 | context.chained.remove(ref context.chained.context, out context.chained.current); 94 | TakeWhileSkip(ref context, out next); 95 | } 96 | 97 | #endregion 98 | 99 | #region Where 100 | 101 | private static readonly Mutator> whereSkip = WhereSkip; 102 | private static readonly Mutator> whereRemove = WhereRemove; 103 | 104 | private static void WhereSkip(ref PredicateContext context, out Option next) { 105 | context.bd.DetectBacktrack(); 106 | 107 | if (context.needsMove) { 108 | context.chained.skip(ref context.chained.context, out context.chained.current); 109 | } else { 110 | context.needsMove = true; 111 | } 112 | 113 | while (context.chained.current.isSome && !context.predicate(context.chained.current.value)) { 114 | context.chained.skip(ref context.chained.context, out context.chained.current); 115 | } 116 | 117 | next = context.chained.current; 118 | 119 | if (!next.isSome) { 120 | context.bd.Release(); 121 | } 122 | } 123 | 124 | private static void WhereRemove(ref PredicateContext context, out Option next) { 125 | context.bd.DetectBacktrack(); 126 | 127 | context.needsMove = false; 128 | context.chained.remove(ref context.chained.context, out context.chained.current); 129 | WhereSkip(ref context, out next); 130 | } 131 | 132 | #endregion 133 | 134 | } 135 | 136 | #endregion 137 | 138 | #region With parameter 139 | 140 | public struct PredicateContext { 141 | 142 | #region Slinqs 143 | 144 | public static Slinq> TakeWhile(Slinq slinq, DelegateFunc predicate, P parameter) { 145 | return new Slinq>( 146 | takeWhileSkip, 147 | takeWhileRemove, 148 | dispose, 149 | new PredicateContext(slinq, predicate, parameter)); 150 | } 151 | 152 | public static Slinq> Where(Slinq slinq, DelegateFunc predicate, P parameter) { 153 | return new Slinq>( 154 | whereSkip, 155 | whereRemove, 156 | dispose, 157 | new PredicateContext(slinq, predicate, parameter)); 158 | } 159 | 160 | #endregion 161 | 162 | #region Context 163 | 164 | private bool needsMove; 165 | private Slinq chained; 166 | private readonly DelegateFunc predicate; 167 | private readonly P parameter; 168 | 169 | #pragma warning disable 0414 170 | private BacktrackDetector bd; 171 | #pragma warning restore 0414 172 | 173 | private PredicateContext(Slinq chained, DelegateFunc predicate, P parameter) { 174 | this.needsMove = false; 175 | this.chained = chained; 176 | this.predicate = predicate; 177 | this.parameter = parameter; 178 | 179 | this.bd = BacktrackDetector.Borrow(); 180 | } 181 | 182 | #endregion 183 | 184 | #region Dispose 185 | 186 | private static readonly Mutator> dispose = Dispose; 187 | 188 | private static void Dispose(ref PredicateContext context, out Option next) { 189 | next = new Option(); 190 | context.bd.Release(); 191 | context.chained.dispose(ref context.chained.context, out context.chained.current); 192 | } 193 | 194 | #endregion 195 | 196 | #region TakeWhile 197 | 198 | private static readonly Mutator> takeWhileSkip = TakeWhileSkip; 199 | private static readonly Mutator> takeWhileRemove = TakeWhileRemove; 200 | 201 | private static void TakeWhileSkip(ref PredicateContext context, out Option next) { 202 | context.bd.DetectBacktrack(); 203 | 204 | if (context.needsMove) { 205 | context.chained.skip(ref context.chained.context, out context.chained.current); 206 | } else { 207 | context.needsMove = true; 208 | } 209 | 210 | if (!context.chained.current.isSome) { 211 | next = context.chained.current; 212 | context.bd.Release(); 213 | } else if (context.predicate(context.chained.current.value, context.parameter)) { 214 | next = context.chained.current; 215 | } else { 216 | next = new Option(); 217 | context.bd.Release(); 218 | context.chained.dispose(ref context.chained.context, out context.chained.current); 219 | } 220 | } 221 | 222 | private static void TakeWhileRemove(ref PredicateContext context, out Option next) { 223 | context.bd.DetectBacktrack(); 224 | 225 | context.needsMove = false; 226 | context.chained.remove(ref context.chained.context, out context.chained.current); 227 | TakeWhileSkip(ref context, out next); 228 | } 229 | 230 | #endregion 231 | 232 | #region Where 233 | 234 | private static readonly Mutator> whereSkip = WhereSkip; 235 | private static readonly Mutator> whereRemove = WhereRemove; 236 | 237 | private static void WhereSkip(ref PredicateContext context, out Option next) { 238 | context.bd.DetectBacktrack(); 239 | 240 | if (context.needsMove) { 241 | context.chained.skip(ref context.chained.context, out context.chained.current); 242 | } else { 243 | context.needsMove = true; 244 | } 245 | 246 | while (context.chained.current.isSome && !context.predicate(context.chained.current.value, context.parameter)) { 247 | context.chained.skip(ref context.chained.context, out context.chained.current); 248 | } 249 | 250 | next = context.chained.current; 251 | 252 | if (!next.isSome) { 253 | context.bd.Release(); 254 | } 255 | } 256 | 257 | private static void WhereRemove(ref PredicateContext context, out Option next) { 258 | context.bd.DetectBacktrack(); 259 | 260 | context.needsMove = false; 261 | context.chained.remove(ref context.chained.context, out context.chained.current); 262 | WhereSkip(ref context, out next); 263 | } 264 | 265 | #endregion 266 | 267 | } 268 | 269 | #endregion 270 | 271 | } -------------------------------------------------------------------------------- /Assets/Smooth/Foundations/Slinq/Context/ChainedOrPooled/SelectContext.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Smooth.Algebraics; 3 | using Smooth.Delegates; 4 | 5 | namespace Smooth.Slinq.Context { 6 | 7 | #region No parameter 8 | 9 | public struct SelectContext { 10 | 11 | #region Slinqs 12 | 13 | public static Slinq> Select(Slinq slinq, DelegateFunc selector) { 14 | return new Slinq>( 15 | skip, 16 | remove, 17 | dispose, 18 | new SelectContext(slinq, selector)); 19 | } 20 | 21 | #endregion 22 | 23 | #region Context 24 | 25 | private bool needsMove; 26 | private Slinq chained; 27 | private readonly DelegateFunc selector; 28 | 29 | #pragma warning disable 0414 30 | private BacktrackDetector bd; 31 | #pragma warning restore 0414 32 | 33 | private SelectContext(Slinq chained, DelegateFunc selector) { 34 | this.needsMove = false; 35 | this.chained = chained; 36 | this.selector = selector; 37 | 38 | this.bd = BacktrackDetector.Borrow(); 39 | } 40 | 41 | #endregion 42 | 43 | #region Delegates 44 | 45 | private static readonly Mutator> skip = Skip; 46 | private static readonly Mutator> remove = Remove; 47 | private static readonly Mutator> dispose = Dispose; 48 | 49 | private static void Skip(ref SelectContext context, out Option next) { 50 | context.bd.DetectBacktrack(); 51 | 52 | if (context.needsMove) { 53 | context.chained.skip(ref context.chained.context, out context.chained.current); 54 | } else { 55 | context.needsMove = true; 56 | } 57 | 58 | next = context.chained.current.isSome ? new Option(context.selector(context.chained.current.value)): new Option(); 59 | 60 | if (!next.isSome) { 61 | context.bd.Release(); 62 | } 63 | } 64 | 65 | private static void Remove(ref SelectContext context, out Option next) { 66 | context.bd.DetectBacktrack(); 67 | 68 | context.needsMove = false; 69 | context.chained.remove(ref context.chained.context, out context.chained.current); 70 | Skip(ref context, out next); 71 | } 72 | 73 | private static void Dispose(ref SelectContext context, out Option next) { 74 | next = new Option(); 75 | context.bd.Release(); 76 | context.chained.dispose(ref context.chained.context, out context.chained.current); 77 | } 78 | 79 | #endregion 80 | 81 | } 82 | 83 | #endregion 84 | 85 | #region With parameter 86 | 87 | public struct SelectContext { 88 | 89 | #region Slinqs 90 | 91 | public static Slinq> Select(Slinq slinq, DelegateFunc selector, P parameter) { 92 | return new Slinq>( 93 | skip, 94 | remove, 95 | dispose, 96 | new SelectContext(slinq, selector, parameter)); 97 | } 98 | 99 | #endregion 100 | 101 | #region Context 102 | 103 | private bool needsMove; 104 | private Slinq chained; 105 | private readonly DelegateFunc selector; 106 | private readonly P parameter; 107 | 108 | #pragma warning disable 0414 109 | private BacktrackDetector bd; 110 | #pragma warning restore 0414 111 | 112 | private SelectContext(Slinq chained, DelegateFunc selector, P parameter) { 113 | this.needsMove = false; 114 | this.chained = chained; 115 | this.selector = selector; 116 | this.parameter = parameter; 117 | 118 | this.bd = BacktrackDetector.Borrow(); 119 | } 120 | 121 | #endregion 122 | 123 | #region Delegates 124 | 125 | private static readonly Mutator> skip = Skip; 126 | private static readonly Mutator> remove = Remove; 127 | private static readonly Mutator> dispose = Dispose; 128 | 129 | private static void Skip(ref SelectContext context, out Option next) { 130 | context.bd.DetectBacktrack(); 131 | 132 | if (context.needsMove) { 133 | context.chained.skip(ref context.chained.context, out context.chained.current); 134 | } else { 135 | context.needsMove = true; 136 | } 137 | 138 | next = context.chained.current.isSome ? new Option(context.selector(context.chained.current.value, context.parameter)): new Option(); 139 | 140 | if (!next.isSome) { 141 | context.bd.Release(); 142 | } 143 | } 144 | 145 | private static void Remove(ref SelectContext context, out Option next) { 146 | context.bd.DetectBacktrack(); 147 | 148 | context.needsMove = false; 149 | context.chained.remove(ref context.chained.context, out context.chained.current); 150 | Skip(ref context, out next); 151 | } 152 | 153 | private static void Dispose(ref SelectContext context, out Option next) { 154 | next = new Option(); 155 | context.bd.Release(); 156 | context.chained.dispose(ref context.chained.context, out context.chained.current); 157 | } 158 | 159 | #endregion 160 | 161 | } 162 | 163 | #endregion 164 | 165 | } 166 | -------------------------------------------------------------------------------- /Assets/Smooth/Foundations/Slinq/Context/ChainedOrPooled/SelectOptionContext.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Smooth.Algebraics; 3 | using Smooth.Delegates; 4 | 5 | namespace Smooth.Slinq.Context { 6 | 7 | #region No parameter 8 | 9 | public struct SelectOptionContext { 10 | 11 | #region Slinqs 12 | 13 | public static Slinq> SelectMany(Slinq slinq, DelegateFunc> selector) { 14 | return new Slinq>( 15 | skip, 16 | remove, 17 | dispose, 18 | new SelectOptionContext(slinq, selector)); 19 | } 20 | 21 | #endregion 22 | 23 | #region Context 24 | 25 | private bool needsMove; 26 | private Slinq chained; 27 | private readonly DelegateFunc> selector; 28 | 29 | #pragma warning disable 0414 30 | private BacktrackDetector bd; 31 | #pragma warning restore 0414 32 | 33 | private SelectOptionContext(Slinq chained, DelegateFunc> selector) { 34 | this.needsMove = false; 35 | this.chained = chained; 36 | this.selector = selector; 37 | 38 | this.bd = BacktrackDetector.Borrow(); 39 | } 40 | 41 | #endregion 42 | 43 | #region Delegates 44 | 45 | private static readonly Mutator> skip = Skip; 46 | private static readonly Mutator> remove = Remove; 47 | private static readonly Mutator> dispose = Dispose; 48 | 49 | private static void Skip(ref SelectOptionContext context, out Option next) { 50 | context.bd.DetectBacktrack(); 51 | 52 | if (context.needsMove) { 53 | context.chained.skip(ref context.chained.context, out context.chained.current); 54 | } else { 55 | context.needsMove = true; 56 | } 57 | 58 | if (context.chained.current.isSome) { 59 | var o = context.selector(context.chained.current.value); 60 | while (!o.isSome) { 61 | context.chained.skip(ref context.chained.context, out context.chained.current); 62 | if (context.chained.current.isSome) { 63 | o = context.selector(context.chained.current.value); 64 | } else { 65 | break; 66 | } 67 | } 68 | next = o; 69 | } else { 70 | next = new Option(); 71 | } 72 | 73 | if (!next.isSome) { 74 | context.bd.Release(); 75 | } 76 | } 77 | 78 | private static void Remove(ref SelectOptionContext context, out Option next) { 79 | context.bd.DetectBacktrack(); 80 | 81 | context.needsMove = false; 82 | context.chained.remove(ref context.chained.context, out context.chained.current); 83 | Skip(ref context, out next); 84 | } 85 | 86 | private static void Dispose(ref SelectOptionContext context, out Option next) { 87 | next = new Option(); 88 | context.bd.Release(); 89 | context.chained.dispose(ref context.chained.context, out context.chained.current); 90 | } 91 | 92 | #endregion 93 | 94 | } 95 | 96 | #endregion 97 | 98 | #region With parameter 99 | 100 | public struct SelectOptionContext { 101 | 102 | #region Slinqs 103 | 104 | public static Slinq> SelectMany(Slinq slinq, DelegateFunc> selector, P parameter) { 105 | return new Slinq>( 106 | skip, 107 | remove, 108 | dispose, 109 | new SelectOptionContext(slinq, selector, parameter)); 110 | } 111 | 112 | #endregion 113 | 114 | #region Context 115 | 116 | private bool needsMove; 117 | private Slinq chained; 118 | private readonly DelegateFunc> selector; 119 | private readonly P parameter; 120 | 121 | #pragma warning disable 0414 122 | private BacktrackDetector bd; 123 | #pragma warning restore 0414 124 | 125 | private SelectOptionContext(Slinq chained, DelegateFunc> selector, P parameter) { 126 | this.needsMove = false; 127 | this.chained = chained; 128 | this.selector = selector; 129 | this.parameter = parameter; 130 | 131 | this.bd = BacktrackDetector.Borrow(); 132 | } 133 | 134 | #endregion 135 | 136 | #region Delegates 137 | 138 | private static readonly Mutator> skip = Skip; 139 | private static readonly Mutator> remove = Remove; 140 | private static readonly Mutator> dispose = Dispose; 141 | 142 | private static void Skip(ref SelectOptionContext context, out Option next) { 143 | context.bd.DetectBacktrack(); 144 | 145 | if (context.needsMove) { 146 | context.chained.skip(ref context.chained.context, out context.chained.current); 147 | } else { 148 | context.needsMove = true; 149 | } 150 | 151 | if (context.chained.current.isSome) { 152 | var o = context.selector(context.chained.current.value, context.parameter); 153 | while (!o.isSome) { 154 | context.chained.skip(ref context.chained.context, out context.chained.current); 155 | if (context.chained.current.isSome) { 156 | o = context.selector(context.chained.current.value, context.parameter); 157 | } else { 158 | break; 159 | } 160 | } 161 | next = o; 162 | } else { 163 | next = new Option(); 164 | } 165 | 166 | if (!next.isSome) { 167 | context.bd.Release(); 168 | } 169 | } 170 | 171 | private static void Remove(ref SelectOptionContext context, out Option next) { 172 | context.bd.DetectBacktrack(); 173 | 174 | context.needsMove = false; 175 | context.chained.remove(ref context.chained.context, out context.chained.current); 176 | Skip(ref context, out next); 177 | } 178 | 179 | private static void Dispose(ref SelectOptionContext context, out Option next) { 180 | next = new Option(); 181 | context.bd.Release(); 182 | context.chained.dispose(ref context.chained.context, out context.chained.current); 183 | } 184 | 185 | #endregion 186 | 187 | } 188 | 189 | #endregion 190 | 191 | } 192 | -------------------------------------------------------------------------------- /Assets/Smooth/Foundations/Slinq/Context/ChainedOrPooled/SelectSlinqContext.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Smooth.Algebraics; 3 | using Smooth.Delegates; 4 | 5 | namespace Smooth.Slinq.Context { 6 | 7 | #region No parameter 8 | 9 | public struct SelectSlinqContext { 10 | 11 | #region Slinqs 12 | 13 | public static Slinq> SelectMany(Slinq slinq, DelegateFunc> selector) { 14 | return new Slinq>( 15 | skip, 16 | remove, 17 | dispose, 18 | new SelectSlinqContext(slinq, selector)); 19 | } 20 | 21 | #endregion 22 | 23 | #region Context 24 | 25 | private bool needsMove; 26 | private Slinq chained; 27 | private Slinq selected; 28 | private readonly DelegateFunc> selector; 29 | 30 | #pragma warning disable 0414 31 | private BacktrackDetector bd; 32 | #pragma warning restore 0414 33 | 34 | private SelectSlinqContext(Slinq chained, DelegateFunc> selector) { 35 | this.needsMove = false; 36 | this.chained = chained; 37 | this.selected = chained.current.isSome ? selector(chained.current.value) : new Slinq(); 38 | this.selector = selector; 39 | 40 | this.bd = BacktrackDetector.Borrow(); 41 | } 42 | 43 | #endregion 44 | 45 | #region Delegates 46 | 47 | private static readonly Mutator> skip = Skip; 48 | private static readonly Mutator> remove = Remove; 49 | private static readonly Mutator> dispose = Dispose; 50 | 51 | private static void Skip(ref SelectSlinqContext context, out Option next) { 52 | context.bd.DetectBacktrack(); 53 | 54 | if (context.needsMove) { 55 | context.selected.skip(ref context.selected.context, out context.selected.current); 56 | } else { 57 | context.needsMove = true; 58 | } 59 | 60 | if (!context.selected.current.isSome && context.chained.current.isSome) { 61 | context.chained.skip(ref context.chained.context, out context.chained.current); 62 | while (context.chained.current.isSome) { 63 | context.selected = context.selector(context.chained.current.value); 64 | if (context.selected.current.isSome) { 65 | break; 66 | } else { 67 | context.chained.skip(ref context.chained.context, out context.chained.current); 68 | } 69 | } 70 | } 71 | 72 | next = context.selected.current; 73 | 74 | if (!next.isSome) { 75 | context.bd.Release(); 76 | } 77 | } 78 | 79 | private static void Remove(ref SelectSlinqContext context, out Option next) { 80 | context.bd.DetectBacktrack(); 81 | 82 | context.needsMove = false; 83 | context.selected.remove(ref context.selected.context, out context.selected.current); 84 | Skip(ref context, out next); 85 | } 86 | 87 | private static void Dispose(ref SelectSlinqContext context, out Option next) { 88 | next = new Option(); 89 | context.bd.Release(); 90 | context.chained.dispose(ref context.chained.context, out context.chained.current); 91 | context.selected.dispose(ref context.selected.context, out context.selected.current); 92 | } 93 | 94 | #endregion 95 | 96 | } 97 | 98 | #endregion 99 | 100 | #region With parameter 101 | 102 | public struct SelectSlinqContext { 103 | 104 | #region Slinqs 105 | 106 | public static Slinq> SelectMany(Slinq slinq, DelegateFunc> selector, P parameter) { 107 | return new Slinq>( 108 | skip, 109 | remove, 110 | dispose, 111 | new SelectSlinqContext(slinq, selector, parameter)); 112 | } 113 | 114 | #endregion 115 | 116 | #region Context 117 | 118 | private bool needsMove; 119 | private Slinq chained; 120 | private Slinq selected; 121 | private readonly DelegateFunc> selector; 122 | private readonly P parameter; 123 | 124 | #pragma warning disable 0414 125 | private BacktrackDetector bd; 126 | #pragma warning restore 0414 127 | 128 | private SelectSlinqContext(Slinq chained, DelegateFunc> selector, P parameter) { 129 | this.needsMove = false; 130 | this.chained = chained; 131 | this.selected = chained.current.isSome ? selector(chained.current.value, parameter) : new Slinq(); 132 | this.selector = selector; 133 | this.parameter = parameter; 134 | 135 | this.bd = BacktrackDetector.Borrow(); 136 | } 137 | 138 | #endregion 139 | 140 | #region Delegates 141 | 142 | private static readonly Mutator> skip = Skip; 143 | private static readonly Mutator> remove = Remove; 144 | private static readonly Mutator> dispose = Dispose; 145 | 146 | private static void Skip(ref SelectSlinqContext context, out Option next) { 147 | context.bd.DetectBacktrack(); 148 | 149 | if (context.needsMove) { 150 | context.selected.skip(ref context.selected.context, out context.selected.current); 151 | } else { 152 | context.needsMove = true; 153 | } 154 | 155 | if (!context.selected.current.isSome && context.chained.current.isSome) { 156 | context.chained.skip(ref context.chained.context, out context.chained.current); 157 | while (context.chained.current.isSome) { 158 | context.selected = context.selector(context.chained.current.value, context.parameter); 159 | if (context.selected.current.isSome) { 160 | break; 161 | } else { 162 | context.chained.skip(ref context.chained.context, out context.chained.current); 163 | } 164 | } 165 | } 166 | 167 | next = context.selected.current; 168 | 169 | if (!next.isSome) { 170 | context.bd.Release(); 171 | } 172 | } 173 | 174 | private static void Remove(ref SelectSlinqContext context, out Option next) { 175 | context.bd.DetectBacktrack(); 176 | 177 | context.needsMove = false; 178 | context.selected.remove(ref context.selected.context, out context.selected.current); 179 | Skip(ref context, out next); 180 | } 181 | 182 | private static void Dispose(ref SelectSlinqContext context, out Option next) { 183 | next = new Option(); 184 | context.bd.Release(); 185 | context.chained.dispose(ref context.chained.context, out context.chained.current); 186 | context.selected.dispose(ref context.selected.context, out context.selected.current); 187 | } 188 | 189 | #endregion 190 | 191 | } 192 | 193 | #endregion 194 | 195 | } 196 | -------------------------------------------------------------------------------- /Assets/Smooth/Foundations/Slinq/Context/Mutation/BacktrackDetector.cs: -------------------------------------------------------------------------------- 1 | //#define DETECT_BACKTRACK 2 | 3 | using System; 4 | using System.Collections.Generic; 5 | using System.Diagnostics; 6 | 7 | namespace Smooth.Slinq.Context { 8 | 9 | /// 10 | /// Used to find backtracking Slinq usage. 11 | /// 12 | /// If DETECT_BACKTRACK is defined, backtrack detectors will lock a reference context and test the backtrack state on every Slinq operation. This will severely reduce performance and should only be used for debugging purposes. 13 | /// 14 | /// If DETECT_BACKTRACK is not defined, detection operations will not be compiled into the application. 15 | /// 16 | /// Note: Backtrack detection does not work reliably across multiple threads. If pooled objects are shared or passed between threads, external locking and/or ownership management is the repsonsibility of the user. 17 | /// 18 | public struct BacktrackDetector { 19 | private static readonly BacktrackDetector noDetection = new BacktrackDetector(); 20 | private static readonly Stack contextPool; 21 | 22 | public static readonly bool enabled; 23 | 24 | private class ReferenceContext { 25 | public int borrowId; 26 | public int touchId; 27 | } 28 | 29 | private readonly ReferenceContext context; 30 | private int borrowId; 31 | private int touchId; 32 | 33 | private BacktrackDetector(ReferenceContext context) { 34 | this.context = context; 35 | this.borrowId = context.borrowId; 36 | this.touchId = context.touchId; 37 | } 38 | 39 | public static BacktrackDetector Borrow() { 40 | if (enabled) { 41 | lock (contextPool) { 42 | return new BacktrackDetector(contextPool.Count > 0 ? contextPool.Pop() : new ReferenceContext()); 43 | } 44 | } else { 45 | return noDetection; 46 | } 47 | } 48 | 49 | [Conditional("DETECT_BACKTRACK")] 50 | public void DetectBacktrack() { 51 | lock (context) { 52 | if (context.borrowId == borrowId && context.touchId == touchId) { 53 | context.touchId = ++touchId; 54 | } else { 55 | throw new BacktrackException(); 56 | } 57 | } 58 | } 59 | 60 | [Conditional("DETECT_BACKTRACK")] 61 | public void Release() { 62 | lock (context) { 63 | if (context.borrowId == borrowId && context.touchId == touchId) { 64 | ++context.borrowId; 65 | } else { 66 | throw new BacktrackException(); 67 | } 68 | } 69 | 70 | lock (contextPool) { 71 | contextPool.Push(context); 72 | } 73 | } 74 | 75 | [Conditional("DETECT_BACKTRACK")] 76 | public void TryReleaseShared() { 77 | lock (context) { 78 | if (context.borrowId == borrowId) { 79 | ++context.borrowId; 80 | } else { 81 | return; 82 | } 83 | } 84 | 85 | lock (contextPool) { 86 | contextPool.Push(context); 87 | } 88 | } 89 | 90 | static BacktrackDetector() { 91 | #if DETECT_BACKTRACK 92 | contextPool = new Stack(); 93 | enabled = true; 94 | #else 95 | contextPool = null; 96 | enabled = false; 97 | #endif 98 | if (enabled && UnityEngine.Application.isPlaying) { 99 | UnityEngine.Debug.Log("Smooth.Slinq is running with backtrack detection enabled which will significantly reduce performance and should only be used for debugging purposes."); 100 | } 101 | } 102 | } 103 | } 104 | -------------------------------------------------------------------------------- /Assets/Smooth/Foundations/Slinq/Context/Mutation/BacktrackException.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace Smooth.Slinq.Context { 4 | public class BacktrackException : InvalidOperationException {} 5 | } 6 | -------------------------------------------------------------------------------- /Assets/Smooth/Foundations/Slinq/Context/Mutation/Mutator.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Smooth.Algebraics; 3 | 4 | namespace Smooth.Slinq.Context { 5 | public delegate void Mutator(ref C context, out Option next); 6 | } -------------------------------------------------------------------------------- /Assets/Smooth/Foundations/Slinq/Context/Simple/FuncContext.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Smooth.Algebraics; 3 | using Smooth.Delegates; 4 | 5 | namespace Smooth.Slinq.Context { 6 | public struct FuncContext { 7 | 8 | #region Slinqs 9 | 10 | public static Slinq> Sequence(T seed, DelegateFunc selector) { 11 | return new Slinq>( 12 | skip, 13 | remove, 14 | dispose, 15 | new FuncContext(seed, selector)); 16 | } 17 | 18 | #endregion 19 | 20 | #region Context 21 | 22 | private bool needsMove; 23 | private T acc; 24 | private readonly DelegateFunc selector; 25 | 26 | #pragma warning disable 0414 27 | private BacktrackDetector bd; 28 | #pragma warning restore 0414 29 | 30 | private FuncContext(T seed, DelegateFunc selector) { 31 | this.needsMove = false; 32 | this.acc = seed; 33 | this.selector = selector; 34 | 35 | this.bd = BacktrackDetector.Borrow(); 36 | } 37 | 38 | #endregion 39 | 40 | #region Delegates 41 | 42 | private static readonly Mutator> skip = Skip; 43 | private static readonly Mutator> remove = skip; 44 | private static readonly Mutator> dispose = Dispose; 45 | 46 | private static void Skip(ref FuncContext context, out Option next) { 47 | context.bd.DetectBacktrack(); 48 | 49 | if (context.needsMove) { 50 | context.acc = context.selector(context.acc); 51 | } else { 52 | context.needsMove = true; 53 | } 54 | next = new Option(context.acc); 55 | } 56 | 57 | private static void Remove(ref FuncContext context, out Option next) { 58 | throw new NotSupportedException(); 59 | } 60 | 61 | private static void Dispose(ref FuncContext context, out Option next) { 62 | next = new Option(); 63 | context.bd.Release(); 64 | } 65 | 66 | #endregion 67 | 68 | } 69 | 70 | public struct FuncContext { 71 | 72 | #region Slinqs 73 | 74 | public static Slinq> Sequence(T seed, DelegateFunc selector, P parameter) { 75 | return new Slinq>( 76 | skip, 77 | remove, 78 | dispose, 79 | new FuncContext(seed, selector, parameter)); 80 | } 81 | 82 | #endregion 83 | 84 | #region Context 85 | 86 | private bool needsMove; 87 | private T acc; 88 | private readonly DelegateFunc selector; 89 | private readonly P parameter; 90 | 91 | #pragma warning disable 0414 92 | private BacktrackDetector bd; 93 | #pragma warning restore 0414 94 | 95 | private FuncContext(T seed, DelegateFunc selector, P parameter) { 96 | this.needsMove = false; 97 | this.acc = seed; 98 | this.selector = selector; 99 | this.parameter = parameter; 100 | 101 | this.bd = BacktrackDetector.Borrow(); 102 | } 103 | 104 | #endregion 105 | 106 | #region Delegates 107 | 108 | private static readonly Mutator> skip = Skip; 109 | private static readonly Mutator> remove = skip; 110 | private static readonly Mutator> dispose = Dispose; 111 | 112 | private static void Skip(ref FuncContext context, out Option next) { 113 | context.bd.DetectBacktrack(); 114 | 115 | if (context.needsMove) { 116 | context.acc = context.selector(context.acc, context.parameter); 117 | } else { 118 | context.needsMove = true; 119 | } 120 | next = new Option(context.acc); 121 | } 122 | 123 | private static void Remove(ref FuncContext context, out Option next) { 124 | throw new NotSupportedException(); 125 | } 126 | 127 | private static void Dispose(ref FuncContext context, out Option next) { 128 | next = new Option(); 129 | context.bd.Release(); 130 | } 131 | 132 | #endregion 133 | 134 | } 135 | } 136 | 137 | 138 | -------------------------------------------------------------------------------- /Assets/Smooth/Foundations/Slinq/Context/Simple/FuncOptionContext.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Smooth.Algebraics; 3 | using Smooth.Delegates; 4 | 5 | namespace Smooth.Slinq.Context { 6 | public struct FuncOptionContext { 7 | 8 | #region Slinqs 9 | 10 | public static Slinq> Sequence(T seed, DelegateFunc> selector) { 11 | return new Slinq>( 12 | skip, 13 | remove, 14 | dispose, 15 | new FuncOptionContext(seed, selector)); 16 | } 17 | 18 | #endregion 19 | 20 | #region Context 21 | 22 | private bool needsMove; 23 | private Option acc; 24 | private readonly DelegateFunc> selector; 25 | 26 | #pragma warning disable 0414 27 | private BacktrackDetector bd; 28 | #pragma warning restore 0414 29 | 30 | private FuncOptionContext(T seed, DelegateFunc> selector) { 31 | this.needsMove = false; 32 | this.acc = new Option(seed); 33 | this.selector = selector; 34 | 35 | this.bd = BacktrackDetector.Borrow(); 36 | } 37 | 38 | #endregion 39 | 40 | #region Delegates 41 | 42 | private static readonly Mutator> skip = Skip; 43 | private static readonly Mutator> remove = skip; 44 | private static readonly Mutator> dispose = Dispose; 45 | 46 | private static void Skip(ref FuncOptionContext context, out Option next) { 47 | context.bd.DetectBacktrack(); 48 | 49 | if (context.needsMove) { 50 | context.acc = context.selector(context.acc.value); 51 | } else { 52 | context.needsMove = true; 53 | } 54 | 55 | next = context.acc; 56 | 57 | if (!next.isSome) { 58 | context.bd.Release(); 59 | } 60 | } 61 | 62 | private static void Remove(ref FuncOptionContext context, out Option next) { 63 | throw new NotSupportedException(); 64 | } 65 | 66 | private static void Dispose(ref FuncOptionContext context, out Option next) { 67 | next = new Option(); 68 | context.bd.Release(); 69 | } 70 | 71 | #endregion 72 | 73 | } 74 | 75 | public struct FuncOptionContext { 76 | 77 | #region Slinqs 78 | 79 | public static Slinq> Sequence(T seed, DelegateFunc> selector, P parameter) { 80 | return new Slinq>( 81 | skip, 82 | remove, 83 | dispose, 84 | new FuncOptionContext(seed, selector, parameter)); 85 | } 86 | 87 | #endregion 88 | 89 | #region Context 90 | 91 | private bool needsMove; 92 | private Option acc; 93 | private readonly DelegateFunc> selector; 94 | private readonly P parameter; 95 | 96 | #pragma warning disable 0414 97 | private BacktrackDetector bd; 98 | #pragma warning restore 0414 99 | 100 | private FuncOptionContext(T seed, DelegateFunc> selector, P parameter) { 101 | this.needsMove = false; 102 | this.acc = new Option(seed); 103 | this.selector = selector; 104 | this.parameter = parameter; 105 | 106 | this.bd = BacktrackDetector.Borrow(); 107 | } 108 | 109 | #endregion 110 | 111 | #region Delegates 112 | 113 | private static readonly Mutator> skip = Skip; 114 | private static readonly Mutator> remove = skip; 115 | private static readonly Mutator> dispose = Dispose; 116 | 117 | private static void Skip(ref FuncOptionContext context, out Option next) { 118 | context.bd.DetectBacktrack(); 119 | 120 | if (context.needsMove) { 121 | context.acc = context.selector(context.acc.value, context.parameter); 122 | } else { 123 | context.needsMove = true; 124 | } 125 | 126 | next = context.acc; 127 | 128 | if (!next.isSome) { 129 | context.bd.Release(); 130 | } 131 | } 132 | 133 | private static void Remove(ref FuncOptionContext context, out Option next) { 134 | throw new NotSupportedException(); 135 | } 136 | 137 | private static void Dispose(ref FuncOptionContext context, out Option next) { 138 | next = new Option(); 139 | context.bd.Release(); 140 | } 141 | 142 | #endregion 143 | 144 | } 145 | } 146 | 147 | 148 | -------------------------------------------------------------------------------- /Assets/Smooth/Foundations/Slinq/Context/Simple/IEnumerableContext.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using Smooth.Algebraics; 4 | 5 | namespace Smooth.Slinq.Context { 6 | public struct IEnumerableContext { 7 | 8 | #region Slinqs 9 | 10 | public static Slinq> Slinq(IEnumerable enumerable) { 11 | return new Slinq>( 12 | skip, 13 | remove, 14 | dispose, 15 | new IEnumerableContext(enumerable)); 16 | } 17 | 18 | #endregion 19 | 20 | #region Instance 21 | 22 | private readonly IEnumerator enumerator; 23 | 24 | #pragma warning disable 0414 25 | private BacktrackDetector bd; 26 | #pragma warning restore 0414 27 | 28 | private IEnumerableContext(IEnumerable enumerable) { 29 | this.enumerator = enumerable.GetEnumerator(); 30 | 31 | this.bd = BacktrackDetector.Borrow(); 32 | } 33 | 34 | #endregion 35 | 36 | #region Delegates 37 | 38 | private static readonly Mutator> skip = Skip; 39 | private static readonly Mutator> remove = Remove; 40 | private static readonly Mutator> dispose = Dispose; 41 | 42 | private static void Skip(ref IEnumerableContext context, out Option next) { 43 | context.bd.DetectBacktrack(); 44 | 45 | if (context.enumerator.MoveNext()) { 46 | next = new Option(context.enumerator.Current); 47 | } else { 48 | next = new Option(); 49 | context.bd.Release(); 50 | context.enumerator.Dispose(); 51 | } 52 | } 53 | 54 | private static void Remove(ref IEnumerableContext context, out Option next) { 55 | throw new NotSupportedException(); 56 | } 57 | 58 | private static void Dispose(ref IEnumerableContext context, out Option next) { 59 | next = new Option(); 60 | context.bd.Release(); 61 | context.enumerator.Dispose(); 62 | } 63 | 64 | #endregion 65 | 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /Assets/Smooth/Foundations/Slinq/Context/Simple/IListContext.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using Smooth.Algebraics; 4 | 5 | namespace Smooth.Slinq.Context { 6 | public struct IListContext { 7 | 8 | #region Slinqs 9 | 10 | public static Slinq> Slinq(IList list, int startIndex, int step) { 11 | return new Slinq>( 12 | skip, 13 | remove, 14 | dispose, 15 | new IListContext(list, startIndex, step)); 16 | } 17 | 18 | public static Slinq, IListContext> SlinqWithIndex(IList list, int startIndex, int step) { 19 | return new Slinq, IListContext>( 20 | skipWithIndex, 21 | removeWithIndex, 22 | disposeWithIndex, 23 | new IListContext(list, startIndex, step)); 24 | } 25 | 26 | #endregion 27 | 28 | #region Instance 29 | 30 | private IList list; 31 | private int size; 32 | private int index; 33 | private readonly int step; 34 | 35 | #pragma warning disable 0414 36 | private BacktrackDetector bd; 37 | #pragma warning restore 0414 38 | 39 | private IListContext(IList list, int startIndex, int step) { 40 | this.list = list; 41 | this.size = list.Count; 42 | this.index = startIndex - step; 43 | this.step = step; 44 | 45 | this.bd = BacktrackDetector.Borrow(); 46 | } 47 | 48 | #endregion 49 | 50 | #region Delegates 51 | 52 | #region Values 53 | 54 | private static readonly Mutator> skip = Skip; 55 | private static readonly Mutator> remove = Remove; 56 | private static readonly Mutator> dispose = Dispose; 57 | 58 | private static void Skip(ref IListContext context, out Option next) { 59 | context.bd.DetectBacktrack(); 60 | 61 | var index = context.index + context.step; 62 | 63 | if (0 <= index && index < context.size) { 64 | next = new Option(context.list[index]); 65 | context.index = index; 66 | } else { 67 | next = new Option(); 68 | context.bd.Release(); 69 | } 70 | } 71 | 72 | private static void Remove(ref IListContext context, out Option next) { 73 | context.bd.DetectBacktrack(); 74 | 75 | context.list.RemoveAt(context.index); 76 | 77 | if (context.step == 0) { 78 | next = new Option(); 79 | context.bd.Release(); 80 | } else { 81 | if (context.step > 0) { 82 | --context.index; 83 | } 84 | --context.size; 85 | 86 | Skip(ref context, out next); 87 | } 88 | } 89 | 90 | private static void Dispose(ref IListContext context, out Option next) { 91 | next = new Option(); 92 | context.bd.Release(); 93 | } 94 | 95 | #endregion 96 | 97 | #region Values with index 98 | 99 | private static readonly Mutator, IListContext> skipWithIndex = SkipWithIndex; 100 | private static readonly Mutator, IListContext> removeWithIndex = RemoveWithIndex; 101 | private static readonly Mutator, IListContext> disposeWithIndex = DisposeWithIndex; 102 | 103 | private static void SkipWithIndex(ref IListContext context, out Option> next) { 104 | context.bd.DetectBacktrack(); 105 | 106 | var index = context.index + context.step; 107 | 108 | if (0 <= index && index < context.size) { 109 | next = new Option>(new Tuple(context.list[index], index)); 110 | context.index = index; 111 | } else { 112 | next = new Option>(); 113 | context.bd.Release(); 114 | } 115 | } 116 | 117 | private static void RemoveWithIndex(ref IListContext context, out Option> next) { 118 | context.bd.DetectBacktrack(); 119 | 120 | context.list.RemoveAt(context.index); 121 | 122 | if (context.step == 0) { 123 | next = new Option>(); 124 | context.bd.Release(); 125 | } else { 126 | if (context.step > 0) { 127 | --context.index; 128 | } 129 | --context.size; 130 | 131 | SkipWithIndex(ref context, out next); 132 | } 133 | } 134 | 135 | private static void DisposeWithIndex(ref IListContext context, out Option> next) { 136 | next = new Option>(); 137 | context.bd.Release(); 138 | } 139 | 140 | #endregion 141 | 142 | #endregion 143 | 144 | } 145 | } 146 | -------------------------------------------------------------------------------- /Assets/Smooth/Foundations/Slinq/Context/Simple/LinkedListContext.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using Smooth.Algebraics; 4 | 5 | namespace Smooth.Slinq.Context { 6 | public struct LinkedListContext { 7 | 8 | #region Slinqs 9 | 10 | public static Slinq> Slinq(LinkedListNode node, int step) { 11 | return new Slinq>( 12 | skip, 13 | remove, 14 | dispose, 15 | new LinkedListContext(node, step)); 16 | } 17 | 18 | public static Slinq, LinkedListContext> SlinqNodes(LinkedListNode node, int step) { 19 | return new Slinq, LinkedListContext>( 20 | skipNodes, 21 | removeNodes, 22 | disposeNodes, 23 | new LinkedListContext(node, step)); 24 | } 25 | 26 | #endregion 27 | 28 | #region Instance 29 | 30 | private bool needsMove; 31 | private LinkedListNode node; 32 | private readonly int step; 33 | 34 | #pragma warning disable 0414 35 | private BacktrackDetector bd; 36 | #pragma warning restore 0414 37 | 38 | private LinkedListContext(LinkedListNode node, int step) { 39 | this.needsMove = false; 40 | this.node = node; 41 | this.step = step; 42 | 43 | this.bd = BacktrackDetector.Borrow(); 44 | } 45 | 46 | #endregion 47 | 48 | #region Delegates 49 | 50 | #region Values 51 | 52 | private static readonly Mutator> skip = Skip; 53 | private static readonly Mutator> remove = Remove; 54 | private static readonly Mutator> dispose = Dispose; 55 | 56 | private static void Skip(ref LinkedListContext context, out Option next) { 57 | context.bd.DetectBacktrack(); 58 | 59 | if (context.needsMove) { 60 | var step = context.step; 61 | while (step > 0 && context.node != null) { 62 | context.node = context.node.Next; 63 | --step; 64 | } 65 | while (step < 0 && context.node != null) { 66 | context.node = context.node.Previous; 67 | ++step; 68 | } 69 | } else { 70 | context.needsMove = true; 71 | } 72 | 73 | 74 | if (context.node == null) { 75 | next = new Option(); 76 | context.bd.Release(); 77 | } else { 78 | next = new Option(context.node.Value); 79 | } 80 | } 81 | 82 | private static void Remove(ref LinkedListContext context, out Option next) { 83 | context.bd.DetectBacktrack(); 84 | 85 | if (context.step == 0) { 86 | next = new Option(); 87 | context.node.List.Remove(context.node); 88 | context.bd.Release(); 89 | } else { 90 | var node = context.node; 91 | Skip(ref context, out next); 92 | node.List.Remove(node); 93 | } 94 | } 95 | 96 | private static void Dispose(ref LinkedListContext context, out Option next) { 97 | next = new Option(); 98 | context.bd.Release(); 99 | } 100 | 101 | #endregion 102 | 103 | #region Nodes 104 | 105 | private static readonly Mutator, LinkedListContext> skipNodes = SkipNodes; 106 | private static readonly Mutator, LinkedListContext> removeNodes = RemoveNodes; 107 | private static readonly Mutator, LinkedListContext> disposeNodes = DisposeNodes; 108 | 109 | private static void SkipNodes(ref LinkedListContext context, out Option> next) { 110 | context.bd.DetectBacktrack(); 111 | 112 | if (context.needsMove) { 113 | var step = context.step; 114 | while (step > 0 && context.node != null) { 115 | context.node = context.node.Next; 116 | --step; 117 | } 118 | while (step < 0 && context.node != null) { 119 | context.node = context.node.Previous; 120 | ++step; 121 | } 122 | } else { 123 | context.needsMove = true; 124 | } 125 | 126 | if (context.node == null) { 127 | next = new Option>(); 128 | context.bd.Release(); 129 | } else { 130 | next = new Option>(context.node); 131 | } 132 | } 133 | 134 | private static void RemoveNodes(ref LinkedListContext context, out Option> next) { 135 | context.bd.DetectBacktrack(); 136 | 137 | if (context.step == 0) { 138 | next = new Option>(); 139 | context.node.List.Remove(context.node); 140 | context.bd.Release(); 141 | } else { 142 | var node = context.node; 143 | SkipNodes(ref context, out next); 144 | node.List.Remove(node); 145 | } 146 | } 147 | 148 | private static void DisposeNodes(ref LinkedListContext context, out Option> next) { 149 | next = new Option>(); 150 | context.bd.Release(); 151 | } 152 | 153 | #endregion 154 | 155 | #endregion 156 | 157 | } 158 | } 159 | -------------------------------------------------------------------------------- /Assets/Smooth/Foundations/Slinq/Context/Simple/OptionContext.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Smooth.Algebraics; 3 | 4 | namespace Smooth.Slinq.Context { 5 | public struct OptionContext { 6 | 7 | #region Slinqs 8 | 9 | public static Slinq> Slinq(Option option) { 10 | return new Slinq>( 11 | optionSkip, 12 | remove, 13 | dispose, 14 | new OptionContext(option)); 15 | } 16 | 17 | public static Slinq> Repeat(T value) { 18 | return new Slinq>( 19 | repeatSkip, 20 | remove, 21 | dispose, 22 | new OptionContext(new Option(value))); 23 | } 24 | 25 | #endregion 26 | 27 | #region Context 28 | 29 | private Option option; 30 | 31 | #pragma warning disable 0414 32 | private BacktrackDetector bd; 33 | #pragma warning restore 0414 34 | 35 | private OptionContext(Option option) { 36 | this.option = option; 37 | 38 | this.bd = BacktrackDetector.Borrow(); 39 | } 40 | 41 | #endregion 42 | 43 | #region Delegates 44 | 45 | #region Remove / Dispose 46 | 47 | private static readonly Mutator> remove = Remove; 48 | private static readonly Mutator> dispose = Dispose; 49 | 50 | private static void Remove(ref OptionContext context, out Option next) { 51 | throw new NotSupportedException(); 52 | } 53 | 54 | private static void Dispose(ref OptionContext context, out Option next) { 55 | next = new Option(); 56 | context.bd.Release(); 57 | } 58 | 59 | #endregion 60 | 61 | #region Option 62 | 63 | private static readonly Mutator> optionSkip = OptionSkip; 64 | 65 | private static void OptionSkip(ref OptionContext context, out Option next) { 66 | context.bd.DetectBacktrack(); 67 | 68 | next = context.option; 69 | 70 | if (context.option.isSome) { 71 | context.option = new Option(); 72 | } else { 73 | context.bd.Release(); 74 | } 75 | } 76 | 77 | #endregion 78 | 79 | #region Repeat 80 | 81 | private static readonly Mutator> repeatSkip = RepeatSkip; 82 | 83 | private static void RepeatSkip(ref OptionContext context, out Option next) { 84 | context.bd.DetectBacktrack(); 85 | 86 | next = context.option; 87 | } 88 | 89 | #endregion 90 | 91 | #endregion 92 | 93 | } 94 | } 95 | -------------------------------------------------------------------------------- /Assets/Smooth/Foundations/Slinq/Test/DistinctLinq.cs: -------------------------------------------------------------------------------- 1 | using UnityEngine; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Linq; 5 | using System.Text; 6 | using Smooth.Algebraics; 7 | using Smooth.Delegates; 8 | using Smooth.Slinq; 9 | 10 | #if !UNITY_3_5 11 | namespace Smooth.Slinq.Test { 12 | #endif 13 | 14 | public class DistinctLinq : MonoBehaviour { 15 | private void Update() { 16 | for (int i = 0; i < SlinqTest.loops; ++i) { 17 | SlinqTest.tuples1.Distinct(SlinqTest.eq_1).Count(); 18 | } 19 | } 20 | } 21 | 22 | #if !UNITY_3_5 23 | } 24 | #endif 25 | -------------------------------------------------------------------------------- /Assets/Smooth/Foundations/Slinq/Test/DistinctSlinq.cs: -------------------------------------------------------------------------------- 1 | using UnityEngine; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Linq; 5 | using System.Text; 6 | using Smooth.Algebraics; 7 | using Smooth.Delegates; 8 | using Smooth.Slinq; 9 | 10 | #if !UNITY_3_5 11 | namespace Smooth.Slinq.Test { 12 | #endif 13 | 14 | public class DistinctSlinq : MonoBehaviour { 15 | private void Update() { 16 | for (int i = 0; i < SlinqTest.loops; ++i) { 17 | SlinqTest.tuples1.Slinq().Distinct(SlinqTest.eq_1).Count(); 18 | } 19 | } 20 | } 21 | 22 | #if !UNITY_3_5 23 | } 24 | #endif 25 | -------------------------------------------------------------------------------- /Assets/Smooth/Foundations/Slinq/Test/ExceptLinq.cs: -------------------------------------------------------------------------------- 1 | using UnityEngine; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Linq; 5 | using System.Text; 6 | using Smooth.Algebraics; 7 | using Smooth.Delegates; 8 | using Smooth.Slinq; 9 | 10 | #if !UNITY_3_5 11 | namespace Smooth.Slinq.Test { 12 | #endif 13 | 14 | public class ExceptLinq : MonoBehaviour { 15 | private void Update() { 16 | for (int i = 0; i < SlinqTest.loops; ++i) { 17 | SlinqTest.tuples1.Except(SlinqTest.tuples2, SlinqTest.eq_1).Count(); 18 | } 19 | } 20 | } 21 | 22 | #if !UNITY_3_5 23 | } 24 | #endif 25 | -------------------------------------------------------------------------------- /Assets/Smooth/Foundations/Slinq/Test/ExceptSlinq.cs: -------------------------------------------------------------------------------- 1 | using UnityEngine; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Linq; 5 | using System.Text; 6 | using Smooth.Algebraics; 7 | using Smooth.Delegates; 8 | using Smooth.Slinq; 9 | 10 | #if !UNITY_3_5 11 | namespace Smooth.Slinq.Test { 12 | #endif 13 | 14 | public class ExceptSlinq : MonoBehaviour { 15 | private void Update() { 16 | for (int i = 0; i < SlinqTest.loops; ++i) { 17 | SlinqTest.tuples1.Slinq().Except(SlinqTest.tuples2.Slinq(), SlinqTest.eq_1).Count(); 18 | } 19 | } 20 | } 21 | 22 | #if !UNITY_3_5 23 | } 24 | #endif 25 | -------------------------------------------------------------------------------- /Assets/Smooth/Foundations/Slinq/Test/GroupByLinq.cs: -------------------------------------------------------------------------------- 1 | using UnityEngine; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Linq; 5 | using System.Text; 6 | using Smooth.Algebraics; 7 | using Smooth.Delegates; 8 | using Smooth.Slinq; 9 | 10 | #if !UNITY_3_5 11 | namespace Smooth.Slinq.Test { 12 | #endif 13 | 14 | public class GroupByLinq : MonoBehaviour { 15 | private void Update() { 16 | for (int i = 0; i < SlinqTest.loops; ++i) { 17 | foreach (var grouping in SlinqTest.tuples1.GroupBy(SlinqTest.to_1f)) { grouping.Count(); } 18 | } 19 | } 20 | } 21 | 22 | #if !UNITY_3_5 23 | } 24 | #endif 25 | -------------------------------------------------------------------------------- /Assets/Smooth/Foundations/Slinq/Test/GroupBySlinq.cs: -------------------------------------------------------------------------------- 1 | using UnityEngine; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Linq; 5 | using System.Text; 6 | using Smooth.Algebraics; 7 | using Smooth.Delegates; 8 | using Smooth.Slinq; 9 | 10 | #if !UNITY_3_5 11 | namespace Smooth.Slinq.Test { 12 | #endif 13 | 14 | public class GroupBySlinq : MonoBehaviour { 15 | private void Update() { 16 | for (int i = 0; i < SlinqTest.loops; ++i) { 17 | SlinqTest.tuples1.Slinq().GroupBy(SlinqTest.to_1).ForEach(g => g.values.Count()); 18 | } 19 | } 20 | } 21 | 22 | #if !UNITY_3_5 23 | } 24 | #endif 25 | -------------------------------------------------------------------------------- /Assets/Smooth/Foundations/Slinq/Test/GroupJoinLinq.cs: -------------------------------------------------------------------------------- 1 | using UnityEngine; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Linq; 5 | using System.Text; 6 | using Smooth.Algebraics; 7 | using Smooth.Delegates; 8 | using Smooth.Slinq; 9 | 10 | #if !UNITY_3_5 11 | namespace Smooth.Slinq.Test { 12 | #endif 13 | 14 | public class GroupJoinLinq : MonoBehaviour { 15 | private void Update() { 16 | for (int i = 0; i < SlinqTest.loops; ++i) { 17 | SlinqTest.tuples1.GroupJoin(SlinqTest.tuples2, SlinqTest.to_1f, SlinqTest.to_1f, (a, bs) => bs.Count()).Count(); 18 | } 19 | } 20 | } 21 | 22 | #if !UNITY_3_5 23 | } 24 | #endif 25 | -------------------------------------------------------------------------------- /Assets/Smooth/Foundations/Slinq/Test/GroupJoinSlinq.cs: -------------------------------------------------------------------------------- 1 | using UnityEngine; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Linq; 5 | using System.Text; 6 | using Smooth.Algebraics; 7 | using Smooth.Delegates; 8 | using Smooth.Slinq; 9 | 10 | #if !UNITY_3_5 11 | namespace Smooth.Slinq.Test { 12 | #endif 13 | 14 | public class GroupJoinSlinq : MonoBehaviour { 15 | private void Update() { 16 | for (int i = 0; i < SlinqTest.loops; ++i) { 17 | SlinqTest.tuples1.Slinq().GroupJoin(SlinqTest.tuples2.Slinq(), SlinqTest.to_1, SlinqTest.to_1, (a, bs) => bs.Count()).Count(); 18 | } 19 | } 20 | } 21 | 22 | #if !UNITY_3_5 23 | } 24 | #endif 25 | -------------------------------------------------------------------------------- /Assets/Smooth/Foundations/Slinq/Test/IntersectLinq.cs: -------------------------------------------------------------------------------- 1 | using UnityEngine; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Linq; 5 | using System.Text; 6 | using Smooth.Algebraics; 7 | using Smooth.Delegates; 8 | using Smooth.Slinq; 9 | 10 | #if !UNITY_3_5 11 | namespace Smooth.Slinq.Test { 12 | #endif 13 | 14 | public class IntersectLinq : MonoBehaviour { 15 | private void Update() { 16 | for (int i = 0; i < SlinqTest.loops; ++i) { 17 | SlinqTest.tuples1.Intersect(SlinqTest.tuples2, SlinqTest.eq_1).Count(); 18 | } 19 | } 20 | } 21 | 22 | #if !UNITY_3_5 23 | } 24 | #endif 25 | -------------------------------------------------------------------------------- /Assets/Smooth/Foundations/Slinq/Test/IntersectSlinq.cs: -------------------------------------------------------------------------------- 1 | using UnityEngine; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Linq; 5 | using System.Text; 6 | using Smooth.Algebraics; 7 | using Smooth.Delegates; 8 | using Smooth.Slinq; 9 | 10 | #if !UNITY_3_5 11 | namespace Smooth.Slinq.Test { 12 | #endif 13 | 14 | public class IntersectSlinq : MonoBehaviour { 15 | private void Update() { 16 | for (int i = 0; i < SlinqTest.loops; ++i) { 17 | SlinqTest.tuples1.Slinq().Intersect(SlinqTest.tuples2.Slinq(), SlinqTest.eq_1).Count(); 18 | } 19 | } 20 | } 21 | 22 | #if !UNITY_3_5 23 | } 24 | #endif 25 | -------------------------------------------------------------------------------- /Assets/Smooth/Foundations/Slinq/Test/JoinLinq.cs: -------------------------------------------------------------------------------- 1 | using UnityEngine; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Linq; 5 | using System.Text; 6 | using Smooth.Algebraics; 7 | using Smooth.Delegates; 8 | using Smooth.Slinq; 9 | 10 | #if !UNITY_3_5 11 | namespace Smooth.Slinq.Test { 12 | #endif 13 | 14 | public class JoinLinq : MonoBehaviour { 15 | private void Update() { 16 | for (int i = 0; i < SlinqTest.loops; ++i) { 17 | SlinqTest.tuples1.Join(SlinqTest.tuples2, SlinqTest.to_1f, SlinqTest.to_1f, (a, b) => 0).Count(); 18 | } 19 | } 20 | } 21 | 22 | #if !UNITY_3_5 23 | } 24 | #endif 25 | -------------------------------------------------------------------------------- /Assets/Smooth/Foundations/Slinq/Test/JoinSlinq.cs: -------------------------------------------------------------------------------- 1 | using UnityEngine; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Linq; 5 | using System.Text; 6 | using Smooth.Algebraics; 7 | using Smooth.Delegates; 8 | using Smooth.Slinq; 9 | 10 | #if !UNITY_3_5 11 | namespace Smooth.Slinq.Test { 12 | #endif 13 | 14 | public class JoinSlinq : MonoBehaviour { 15 | private void Update() { 16 | for (int i = 0; i < SlinqTest.loops; ++i) { 17 | SlinqTest.tuples1.Slinq().Join(SlinqTest.tuples2.Slinq(), SlinqTest.to_1, SlinqTest.to_1, (a, b) => 0).Count(); 18 | } 19 | } 20 | } 21 | 22 | #if !UNITY_3_5 23 | } 24 | #endif 25 | -------------------------------------------------------------------------------- /Assets/Smooth/Foundations/Slinq/Test/OrderByLinq.cs: -------------------------------------------------------------------------------- 1 | using UnityEngine; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Linq; 5 | using System.Text; 6 | using Smooth.Algebraics; 7 | using Smooth.Delegates; 8 | using Smooth.Slinq; 9 | 10 | #if !UNITY_3_5 11 | namespace Smooth.Slinq.Test { 12 | #endif 13 | 14 | public class OrderByLinq : MonoBehaviour { 15 | private void Update() { 16 | for (int i = 0; i < SlinqTest.loops; ++i) { 17 | SlinqTest.tuples1.OrderBy(SlinqTest.to_1f).FirstOrDefault(); 18 | } 19 | } 20 | } 21 | 22 | #if !UNITY_3_5 23 | } 24 | #endif 25 | -------------------------------------------------------------------------------- /Assets/Smooth/Foundations/Slinq/Test/OrderBySlinq.cs: -------------------------------------------------------------------------------- 1 | using UnityEngine; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Linq; 5 | using System.Text; 6 | using Smooth.Algebraics; 7 | using Smooth.Delegates; 8 | using Smooth.Slinq; 9 | 10 | #if !UNITY_3_5 11 | namespace Smooth.Slinq.Test { 12 | #endif 13 | 14 | public class OrderBySlinq : MonoBehaviour { 15 | private void Update() { 16 | for (int i = 0; i < SlinqTest.loops; ++i) { 17 | SlinqTest.tuples1.Slinq().OrderBy(SlinqTest.to_1).FirstOrDefault(); 18 | } 19 | } 20 | } 21 | 22 | #if !UNITY_3_5 23 | } 24 | #endif 25 | -------------------------------------------------------------------------------- /Assets/Smooth/Foundations/Slinq/Test/SlinqTest.unity: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pdo400/smooth.foundations/132960d2238f08b333035d9374569cbcc9b1b728/Assets/Smooth/Foundations/Slinq/Test/SlinqTest.unity -------------------------------------------------------------------------------- /Assets/Smooth/Foundations/Slinq/Test/UnionLinq.cs: -------------------------------------------------------------------------------- 1 | using UnityEngine; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Linq; 5 | using System.Text; 6 | using Smooth.Algebraics; 7 | using Smooth.Delegates; 8 | using Smooth.Slinq; 9 | 10 | #if !UNITY_3_5 11 | namespace Smooth.Slinq.Test { 12 | #endif 13 | 14 | public class UnionLinq : MonoBehaviour { 15 | private void Update() { 16 | for (int i = 0; i < SlinqTest.loops; ++i) { 17 | SlinqTest.tuples1.Union(SlinqTest.tuples2, SlinqTest.eq_1).Count(); 18 | } 19 | } 20 | } 21 | 22 | #if !UNITY_3_5 23 | } 24 | #endif 25 | -------------------------------------------------------------------------------- /Assets/Smooth/Foundations/Slinq/Test/UnionSlinq.cs: -------------------------------------------------------------------------------- 1 | using UnityEngine; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Linq; 5 | using System.Text; 6 | using Smooth.Algebraics; 7 | using Smooth.Delegates; 8 | using Smooth.Slinq; 9 | 10 | #if !UNITY_3_5 11 | namespace Smooth.Slinq.Test { 12 | #endif 13 | 14 | public class UnionSlinq : MonoBehaviour { 15 | private void Update() { 16 | for (int i = 0; i < SlinqTest.loops; ++i) { 17 | SlinqTest.tuples1.Slinq().Union(SlinqTest.tuples2.Slinq(), SlinqTest.eq_1).Count(); 18 | } 19 | } 20 | } 21 | 22 | #if !UNITY_3_5 23 | } 24 | #endif 25 | -------------------------------------------------------------------------------- /Assets/Smooth/Foundations/Slinq/Test/WhereTakeSelectAggregateLinq.cs: -------------------------------------------------------------------------------- 1 | using UnityEngine; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Linq; 5 | using System.Text; 6 | using Smooth.Algebraics; 7 | using Smooth.Delegates; 8 | using Smooth.Slinq; 9 | 10 | #if !UNITY_3_5 11 | namespace Smooth.Slinq.Test { 12 | #endif 13 | 14 | public class WhereTakeSelectAggregateLinq : MonoBehaviour { 15 | private void Update() { 16 | for (int i = 0; i < SlinqTest.loops; ++i) { 17 | SlinqTest.tuples1.Where(t => true).Take(int.MaxValue).Select(t => t).Aggregate(0, (acc, t) => 0); 18 | } 19 | } 20 | } 21 | 22 | #if !UNITY_3_5 23 | } 24 | #endif 25 | -------------------------------------------------------------------------------- /Assets/Smooth/Foundations/Slinq/Test/WhereTakeSelectAggregateSlinq.cs: -------------------------------------------------------------------------------- 1 | using UnityEngine; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Linq; 5 | using System.Text; 6 | using Smooth.Algebraics; 7 | using Smooth.Delegates; 8 | using Smooth.Slinq; 9 | 10 | #if !UNITY_3_5 11 | namespace Smooth.Slinq.Test { 12 | #endif 13 | 14 | public class WhereTakeSelectAggregateSlinq : MonoBehaviour { 15 | private void Update() { 16 | for (int i = 0; i < SlinqTest.loops; ++i) { 17 | SlinqTest.tuples1.Slinq().Where(t => true).Take(int.MaxValue).Select(t => t).Aggregate(0, (acc, t) => 0); 18 | } 19 | } 20 | } 21 | 22 | #if !UNITY_3_5 23 | } 24 | #endif 25 | -------------------------------------------------------------------------------- /Assets/Smooth/Foundations/__Foundations-Git-Readme.txt: -------------------------------------------------------------------------------- 1 | The Smooth.Foundations Git URL is: 2 | 3 | https://github.com/pdo400/smooth.foundations.git 4 | 5 | 6 | In order to keep things clean and independent of Unity versions, no project data is hosted in the Smooth.Foundations Git repository. 7 | 8 | This means that certain things must be set up manually when adding the code to a Unity project. (Note: This does not apply to importing a properly built unity package.) 9 | 10 | 11 | The current list: 12 | 13 | 14 | The script execution order of SmoothDisposer should be set to the latest possible value, ie: 32000. 15 | -------------------------------------------------------------------------------- /Assets/Smooth/Foundations/__Foundations-License.txt: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2014 Patrick E. Whitesell 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in 13 | all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | THE SOFTWARE. 22 | -------------------------------------------------------------------------------- /Assets/Smooth/Foundations/__Foundations-Version.txt: -------------------------------------------------------------------------------- 1 | The latest version of Smooth.Foundations as well as online documentation and support for Smooth Games assets is available at: 2 | 3 | https://www.smooth-games.com/ 4 | 5 | 6 | 7 | 8 | ---------------------------------------- 9 | 10 | Version 2.0.2, Released 2014-05-06: 11 | 12 | ---------------------------------------- 13 | 14 | 15 | Factory: Converted out value methods to tuples. 16 | 17 | Slinq: Added SkipAndReturn(), RemoveAndReturn() methods to facilitate chaining. 18 | 19 | Slinq: RemoveAll() methods return a count. 20 | 21 | 22 | 23 | ---------------------------------------- 24 | 25 | Version 2.0, Released 2014-05-05: 26 | 27 | ---------------------------------------- 28 | 29 | 30 | Foundations is available under the MIT License. 31 | 32 | Added Smooth.Slinq and Smooth.Compare. 33 | 34 | Added InspectorKeyValuePair for facilitating inspector based dictionary management. 35 | 36 | Converted API methods of Smooth.Compare that used null values to Option. 37 | 38 | Register KeyCode comparer on AOT platforms. 39 | 40 | 41 | 42 | 43 | ---------------------------------------- 44 | 45 | Version 1.2.1, Released 2014-05-01: 46 | 47 | ---------------------------------------- 48 | 49 | 50 | Disposable is a struct on console platforms. 51 | 52 | Updated documentation. 53 | 54 | 55 | 56 | 57 | ---------------------------------------- 58 | 59 | Version 1.2, Released 2014-04-28: 60 | 61 | ---------------------------------------- 62 | 63 | 64 | Static pools expose an instance property rather than individual pooling methods. 65 | 66 | Added PoolWithInitializer class. 67 | 68 | Added console platforms to JIT check. 69 | 70 | Disposable is a struct on iOS to prevent compute_class_bitmap errors. 71 | 72 | 73 | 74 | 75 | ---------------------------------------- 76 | 77 | Version 1.1, Released 2014-04-25: 78 | 79 | ---------------------------------------- 80 | 81 | 82 | Updated documentation. 83 | 84 | 85 | 86 | 87 | ---------------------------------------- 88 | 89 | Version 1.0, Released 2014-04-25: 90 | 91 | ---------------------------------------- 92 | 93 | 94 | Initial Release. 95 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | smooth.foundations 2 | ================== 3 | 4 | Smooth.Foundations is an MIT licensed code package that provides basic classes for boosting programmer productivity and writing clean, maintainable, allocation-free code in Unity. The code is written in C# and very little is Unity specific; It can also be used on other .Net platforms. 5 | 6 | Smooth.Foundations includes: 7 | 8 | - Smooth.Compare, a replacement for the System.Collections.Generic comparers that helps reduce runtime allocations and prevent JIT exceptions on AOT platforms. 9 | - Smooth.Slinq, a faster, allocation-free replacement for LINQ with increased functionality and a more robust API. 10 | - Algebraic structs like Option, Either, and Tuple. 11 | - Generic pools with a delegate-based API. 12 | - Generic event helpers for creating and maintaining robust, type safe events backed by multicast delegates. 13 | - A disposal API for performing cleanup operations in a background thread during the rendering phase. 14 | - Methods for determining basic information about the runtime platform. 15 | - Other miscellaneous utilities. 16 | --------------------------------------------------------------------------------