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