com.wallstop-studios.unity-helpers 2.0.0-rc45 → 2.0.0-rc47
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/Runtime/Core/DataStructure/CyclicBuffer.cs +1 -3
- package/Runtime/Core/DataStructure/KDTree.cs +10 -8
- package/Runtime/Core/DataStructure/QuadTree.cs +16 -8
- package/Runtime/Core/DataStructure/RTree.cs +18 -8
- package/Runtime/Core/DataStructure/StringWrapper.cs +4 -4
- package/Runtime/Core/DataStructure/TimedCache.cs +20 -5
- package/Runtime/Core/Extension/EnumExtensions.cs +37 -0
- package/Runtime/Core/Extension/EnumExtensions.cs.meta +3 -0
- package/Runtime/Core/Extension/IListExtensions.cs +17 -0
- package/Runtime/Utils/RuntimeSingleton.cs +13 -5
- package/Tests/Runtime/Extensions/EnumExtensionTests.cs +128 -0
- package/Tests/Runtime/Extensions/EnumExtensionTests.cs.meta +3 -0
- package/Tests/Runtime/Extensions/IListExtensionTests.cs +28 -0
- package/package.json +1 -1
|
@@ -12,7 +12,6 @@
|
|
|
12
12
|
{
|
|
13
13
|
public int Capacity { get; private set; }
|
|
14
14
|
public int Count { get; private set; }
|
|
15
|
-
public bool IsReadOnly => false;
|
|
16
15
|
|
|
17
16
|
private readonly List<T> _buffer;
|
|
18
17
|
private int _position;
|
|
@@ -52,7 +51,7 @@
|
|
|
52
51
|
{
|
|
53
52
|
for (int i = 0; i < Count; ++i)
|
|
54
53
|
{
|
|
55
|
-
// No need for
|
|
54
|
+
// No need for bound check, we're safe
|
|
56
55
|
yield return _buffer[AdjustedIndexFor(i)];
|
|
57
56
|
}
|
|
58
57
|
}
|
|
@@ -87,7 +86,6 @@
|
|
|
87
86
|
|
|
88
87
|
public void Clear()
|
|
89
88
|
{
|
|
90
|
-
/* Simply reset state */
|
|
91
89
|
Count = 0;
|
|
92
90
|
_position = 0;
|
|
93
91
|
_buffer.Clear();
|
|
@@ -272,19 +272,21 @@
|
|
|
272
272
|
}
|
|
273
273
|
}
|
|
274
274
|
|
|
275
|
-
|
|
275
|
+
foreach (T element in nearestNeighborsSet)
|
|
276
|
+
{
|
|
277
|
+
nearestNeighbors.Add(element);
|
|
278
|
+
}
|
|
276
279
|
if (count < nearestNeighbors.Count)
|
|
277
280
|
{
|
|
281
|
+
Vector2 localPosition = position;
|
|
278
282
|
nearestNeighbors.Sort(NearestComparison);
|
|
279
283
|
nearestNeighbors.RemoveRange(count, nearestNeighbors.Count - count);
|
|
280
|
-
}
|
|
281
284
|
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
);
|
|
285
|
+
int NearestComparison(T lhs, T rhs) =>
|
|
286
|
+
(_elementTransformer(lhs) - localPosition).sqrMagnitude.CompareTo(
|
|
287
|
+
(_elementTransformer(rhs) - localPosition).sqrMagnitude
|
|
288
|
+
);
|
|
289
|
+
}
|
|
288
290
|
}
|
|
289
291
|
}
|
|
290
292
|
}
|
|
@@ -231,11 +231,15 @@
|
|
|
231
231
|
HashSet<T> nearestNeighborsSet = nearestNeighborBuffer ?? new HashSet<T>(count);
|
|
232
232
|
nearestNeighborsSet.Clear();
|
|
233
233
|
|
|
234
|
+
Comparison<QuadTreeNode<T>> comparison = Comparison;
|
|
234
235
|
while (!current.isTerminal)
|
|
235
236
|
{
|
|
236
237
|
childrenCopy.Clear();
|
|
237
|
-
|
|
238
|
-
|
|
238
|
+
foreach (QuadTreeNode<T> child in current.children)
|
|
239
|
+
{
|
|
240
|
+
childrenCopy.Add(child);
|
|
241
|
+
}
|
|
242
|
+
childrenCopy.Sort(comparison);
|
|
239
243
|
for (int i = childrenCopy.Count - 1; 0 <= i; --i)
|
|
240
244
|
{
|
|
241
245
|
stack.Push(childrenCopy[i]);
|
|
@@ -256,11 +260,20 @@
|
|
|
256
260
|
}
|
|
257
261
|
}
|
|
258
262
|
|
|
259
|
-
|
|
263
|
+
foreach (T element in nearestNeighborsSet)
|
|
264
|
+
{
|
|
265
|
+
nearestNeighbors.Add(element);
|
|
266
|
+
}
|
|
260
267
|
if (count < nearestNeighbors.Count)
|
|
261
268
|
{
|
|
269
|
+
Vector2 localPosition = position;
|
|
262
270
|
nearestNeighbors.Sort(NearestComparison);
|
|
263
271
|
nearestNeighbors.RemoveRange(count, nearestNeighbors.Count - count);
|
|
272
|
+
|
|
273
|
+
int NearestComparison(T lhs, T rhs) =>
|
|
274
|
+
(_elementTransformer(lhs) - localPosition).sqrMagnitude.CompareTo(
|
|
275
|
+
(_elementTransformer(rhs) - localPosition).sqrMagnitude
|
|
276
|
+
);
|
|
264
277
|
}
|
|
265
278
|
|
|
266
279
|
return;
|
|
@@ -269,11 +282,6 @@
|
|
|
269
282
|
((Vector2)lhs.boundary.center - position).sqrMagnitude.CompareTo(
|
|
270
283
|
((Vector2)rhs.boundary.center - position).sqrMagnitude
|
|
271
284
|
);
|
|
272
|
-
|
|
273
|
-
int NearestComparison(T lhs, T rhs) =>
|
|
274
|
-
(_elementTransformer(lhs) - position).sqrMagnitude.CompareTo(
|
|
275
|
-
(_elementTransformer(rhs) - position).sqrMagnitude
|
|
276
|
-
);
|
|
277
285
|
}
|
|
278
286
|
}
|
|
279
287
|
}
|
|
@@ -288,11 +288,15 @@
|
|
|
288
288
|
HashSet<T> nearestNeighborsSet = nearestNeighborsBuffer ?? new HashSet<T>(count);
|
|
289
289
|
nearestNeighborsSet.Clear();
|
|
290
290
|
|
|
291
|
+
Comparison<RTreeNode<T>> comparison = Comparison;
|
|
291
292
|
while (!current.isTerminal)
|
|
292
293
|
{
|
|
293
294
|
childrenCopy.Clear();
|
|
294
|
-
|
|
295
|
-
|
|
295
|
+
foreach (RTreeNode<T> child in current.children)
|
|
296
|
+
{
|
|
297
|
+
childrenCopy.Add(child);
|
|
298
|
+
}
|
|
299
|
+
childrenCopy.Sort(comparison);
|
|
296
300
|
for (int i = childrenCopy.Count - 1; 0 <= i; --i)
|
|
297
301
|
{
|
|
298
302
|
stack.Push(childrenCopy[i]);
|
|
@@ -313,11 +317,22 @@
|
|
|
313
317
|
}
|
|
314
318
|
}
|
|
315
319
|
|
|
316
|
-
|
|
320
|
+
foreach (T element in nearestNeighborsSet)
|
|
321
|
+
{
|
|
322
|
+
nearestNeighbors.Add(element);
|
|
323
|
+
}
|
|
317
324
|
if (count < nearestNeighbors.Count)
|
|
318
325
|
{
|
|
326
|
+
Vector2 localPosition = position;
|
|
319
327
|
nearestNeighbors.Sort(NearestComparison);
|
|
320
328
|
nearestNeighbors.RemoveRange(count, nearestNeighbors.Count - count);
|
|
329
|
+
|
|
330
|
+
int NearestComparison(T lhs, T rhs) =>
|
|
331
|
+
(
|
|
332
|
+
(Vector2)_elementTransformer(lhs).center - localPosition
|
|
333
|
+
).sqrMagnitude.CompareTo(
|
|
334
|
+
((Vector2)_elementTransformer(rhs).center - localPosition).sqrMagnitude
|
|
335
|
+
);
|
|
321
336
|
}
|
|
322
337
|
|
|
323
338
|
return;
|
|
@@ -326,11 +341,6 @@
|
|
|
326
341
|
((Vector2)lhs.boundary.center - position).sqrMagnitude.CompareTo(
|
|
327
342
|
((Vector2)rhs.boundary.center - position).sqrMagnitude
|
|
328
343
|
);
|
|
329
|
-
|
|
330
|
-
int NearestComparison(T lhs, T rhs) =>
|
|
331
|
-
((Vector2)_elementTransformer(lhs).center - position).sqrMagnitude.CompareTo(
|
|
332
|
-
((Vector2)_elementTransformer(rhs).center - position).sqrMagnitude
|
|
333
|
-
);
|
|
334
344
|
}
|
|
335
345
|
}
|
|
336
346
|
}
|
|
@@ -19,7 +19,7 @@
|
|
|
19
19
|
private StringWrapper(string value)
|
|
20
20
|
{
|
|
21
21
|
this.value = value;
|
|
22
|
-
_hashCode = value
|
|
22
|
+
_hashCode = value.GetHashCode();
|
|
23
23
|
}
|
|
24
24
|
|
|
25
25
|
public static StringWrapper Get(string value)
|
|
@@ -27,9 +27,9 @@
|
|
|
27
27
|
return Cache.GetOrAdd(value, key => new StringWrapper(key));
|
|
28
28
|
}
|
|
29
29
|
|
|
30
|
-
public static
|
|
30
|
+
public static bool Remove(string value)
|
|
31
31
|
{
|
|
32
|
-
|
|
32
|
+
return Cache.TryRemove(value, out _);
|
|
33
33
|
}
|
|
34
34
|
|
|
35
35
|
public bool Equals(StringWrapper other)
|
|
@@ -49,7 +49,7 @@
|
|
|
49
49
|
return false;
|
|
50
50
|
}
|
|
51
51
|
|
|
52
|
-
return string.Equals(value, other.value);
|
|
52
|
+
return string.Equals(value, other.value, StringComparison.Ordinal);
|
|
53
53
|
}
|
|
54
54
|
|
|
55
55
|
public int CompareTo(StringWrapper other)
|
|
@@ -11,10 +11,23 @@
|
|
|
11
11
|
{
|
|
12
12
|
get
|
|
13
13
|
{
|
|
14
|
-
if (!_lastRead.HasValue
|
|
14
|
+
if (!_lastRead.HasValue)
|
|
15
15
|
{
|
|
16
16
|
Reset();
|
|
17
17
|
}
|
|
18
|
+
else if (
|
|
19
|
+
Helpers.HasEnoughTimePassed(
|
|
20
|
+
_lastRead.Value,
|
|
21
|
+
_cacheTtl + (_shouldUseJitter && !_usedJitter ? _jitterAmount : 0f)
|
|
22
|
+
)
|
|
23
|
+
)
|
|
24
|
+
{
|
|
25
|
+
if (_shouldUseJitter)
|
|
26
|
+
{
|
|
27
|
+
_usedJitter = true;
|
|
28
|
+
}
|
|
29
|
+
Reset();
|
|
30
|
+
}
|
|
18
31
|
|
|
19
32
|
return _value;
|
|
20
33
|
}
|
|
@@ -26,6 +39,10 @@
|
|
|
26
39
|
private float? _lastRead;
|
|
27
40
|
private T _value;
|
|
28
41
|
|
|
42
|
+
private bool _usedJitter;
|
|
43
|
+
private readonly bool _shouldUseJitter;
|
|
44
|
+
private readonly float _jitterAmount;
|
|
45
|
+
|
|
29
46
|
public TimedCache(Func<T> valueProducer, float cacheTtl, bool useJitter = false)
|
|
30
47
|
{
|
|
31
48
|
_valueProducer =
|
|
@@ -36,10 +53,8 @@
|
|
|
36
53
|
}
|
|
37
54
|
|
|
38
55
|
_cacheTtl = cacheTtl;
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
_cacheTtl += PRNG.Instance.NextFloat(_cacheTtl);
|
|
42
|
-
}
|
|
56
|
+
_shouldUseJitter = useJitter;
|
|
57
|
+
_jitterAmount = useJitter ? PRNG.Instance.NextFloat(0f, cacheTtl) : 0f;
|
|
43
58
|
}
|
|
44
59
|
|
|
45
60
|
public void Reset()
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
namespace UnityHelpers.Core.Extension
|
|
2
|
+
{
|
|
3
|
+
using System;
|
|
4
|
+
using System.Runtime.CompilerServices;
|
|
5
|
+
|
|
6
|
+
public static class EnumExtensions
|
|
7
|
+
{
|
|
8
|
+
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
9
|
+
public static bool HasFlagNoAlloc<T>(this T value, T flag)
|
|
10
|
+
where T : unmanaged, Enum
|
|
11
|
+
{
|
|
12
|
+
ulong valueUnderlying = GetUInt64(value);
|
|
13
|
+
ulong flagUnderlying = GetUInt64(flag);
|
|
14
|
+
return (valueUnderlying & flagUnderlying) == flagUnderlying;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
18
|
+
private static unsafe ulong GetUInt64<T>(T value)
|
|
19
|
+
where T : unmanaged
|
|
20
|
+
{
|
|
21
|
+
/*
|
|
22
|
+
Works because T is constrained to unmanaged, so it's safe to reinterpret
|
|
23
|
+
All enums are value types and have a fixed size
|
|
24
|
+
*/
|
|
25
|
+
return sizeof(T) switch
|
|
26
|
+
{
|
|
27
|
+
1 => *(byte*)&value,
|
|
28
|
+
2 => *(ushort*)&value,
|
|
29
|
+
4 => *(uint*)&value,
|
|
30
|
+
8 => *(ulong*)&value,
|
|
31
|
+
_ => throw new ArgumentException(
|
|
32
|
+
$"Unsupported enum size: {sizeof(T)} for type {typeof(T)}"
|
|
33
|
+
),
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
}
|
|
@@ -85,5 +85,22 @@
|
|
|
85
85
|
list[index] = last;
|
|
86
86
|
list.RemoveAt(lastIndex);
|
|
87
87
|
}
|
|
88
|
+
|
|
89
|
+
public static void InsertionSort<T, TComparer>(this IList<T> array, TComparer comparer)
|
|
90
|
+
where TComparer : struct, IComparer<T>
|
|
91
|
+
{
|
|
92
|
+
int arrayCount = array.Count;
|
|
93
|
+
for (int i = 1; i < arrayCount; ++i)
|
|
94
|
+
{
|
|
95
|
+
T key = array[i];
|
|
96
|
+
int j = i - 1;
|
|
97
|
+
while (j >= 0 && comparer.Compare(array[j], key) > 0)
|
|
98
|
+
{
|
|
99
|
+
array[j + 1] = array[j];
|
|
100
|
+
j--;
|
|
101
|
+
}
|
|
102
|
+
array[j + 1] = key;
|
|
103
|
+
}
|
|
104
|
+
}
|
|
88
105
|
}
|
|
89
106
|
}
|
|
@@ -45,12 +45,20 @@
|
|
|
45
45
|
|
|
46
46
|
protected virtual void Start()
|
|
47
47
|
{
|
|
48
|
-
if (_instance
|
|
48
|
+
if (_instance == null || _instance == this)
|
|
49
49
|
{
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
50
|
+
return;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
this.LogError($"Double singleton detected, {_instance.name} conflicts with {name}.");
|
|
54
|
+
gameObject.Destroy();
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
protected virtual void OnDestroy()
|
|
58
|
+
{
|
|
59
|
+
if (_instance == this)
|
|
60
|
+
{
|
|
61
|
+
_instance = null;
|
|
54
62
|
}
|
|
55
63
|
}
|
|
56
64
|
}
|
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
namespace UnityHelpers.Tests.Extensions
|
|
2
|
+
{
|
|
3
|
+
using Core.Extension;
|
|
4
|
+
using NUnit.Framework;
|
|
5
|
+
using UnityEngine.TestTools.Constraints;
|
|
6
|
+
using Is = NUnit.Framework.Is;
|
|
7
|
+
|
|
8
|
+
public sealed class EnumExtensionTests
|
|
9
|
+
{
|
|
10
|
+
private enum TestEnum
|
|
11
|
+
{
|
|
12
|
+
None = 0,
|
|
13
|
+
First = 1 << 0,
|
|
14
|
+
Second = 1 << 1,
|
|
15
|
+
Third = 1 << 2,
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
private enum TinyTestEnum : byte
|
|
19
|
+
{
|
|
20
|
+
None = 0,
|
|
21
|
+
First = 1 << 0,
|
|
22
|
+
Second = 1 << 1,
|
|
23
|
+
Third = 1 << 2,
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
private enum SmallTestEnum : short
|
|
27
|
+
{
|
|
28
|
+
None = 0,
|
|
29
|
+
First = 1 << 0,
|
|
30
|
+
Second = 1 << 1,
|
|
31
|
+
Third = 1 << 2,
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
private enum BigTestEnum : long
|
|
35
|
+
{
|
|
36
|
+
None = 0,
|
|
37
|
+
First = 1 << 0,
|
|
38
|
+
Second = 1 << 1,
|
|
39
|
+
Third = 1 << 2,
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
[Test]
|
|
43
|
+
public void HasFlagNoAlloc()
|
|
44
|
+
{
|
|
45
|
+
Assert.IsTrue(TestEnum.First.HasFlagNoAlloc(TestEnum.First));
|
|
46
|
+
Assert.IsFalse(TestEnum.First.HasFlagNoAlloc(TestEnum.Second));
|
|
47
|
+
Assert.IsTrue((TestEnum.First | TestEnum.Second).HasFlagNoAlloc(TestEnum.First));
|
|
48
|
+
Assert.IsTrue((TestEnum.First | TestEnum.Second).HasFlagNoAlloc(TestEnum.Second));
|
|
49
|
+
Assert.IsFalse((TestEnum.First | TestEnum.Second).HasFlagNoAlloc(TestEnum.Third));
|
|
50
|
+
Assert.IsFalse(TestEnum.First.HasFlagNoAlloc((TestEnum.First | TestEnum.Second)));
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
[Test]
|
|
54
|
+
public void HasFlagNoAllocTiny()
|
|
55
|
+
{
|
|
56
|
+
Assert.IsTrue(TinyTestEnum.First.HasFlagNoAlloc(TinyTestEnum.First));
|
|
57
|
+
Assert.IsFalse(TinyTestEnum.First.HasFlagNoAlloc(TinyTestEnum.Second));
|
|
58
|
+
Assert.IsTrue(
|
|
59
|
+
(TinyTestEnum.First | TinyTestEnum.Second).HasFlagNoAlloc(TinyTestEnum.First)
|
|
60
|
+
);
|
|
61
|
+
Assert.IsTrue(
|
|
62
|
+
(TinyTestEnum.First | TinyTestEnum.Second).HasFlagNoAlloc(TinyTestEnum.Second)
|
|
63
|
+
);
|
|
64
|
+
Assert.IsFalse(
|
|
65
|
+
(TinyTestEnum.First | TinyTestEnum.Second).HasFlagNoAlloc(TinyTestEnum.Third)
|
|
66
|
+
);
|
|
67
|
+
Assert.IsFalse(
|
|
68
|
+
TinyTestEnum.First.HasFlagNoAlloc((TinyTestEnum.First | TinyTestEnum.Second))
|
|
69
|
+
);
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
[Test]
|
|
73
|
+
public void HasFlagNoAllocSmall()
|
|
74
|
+
{
|
|
75
|
+
Assert.IsTrue(SmallTestEnum.First.HasFlagNoAlloc(SmallTestEnum.First));
|
|
76
|
+
Assert.IsFalse(SmallTestEnum.First.HasFlagNoAlloc(SmallTestEnum.Second));
|
|
77
|
+
Assert.IsTrue(
|
|
78
|
+
(SmallTestEnum.First | SmallTestEnum.Second).HasFlagNoAlloc(SmallTestEnum.First)
|
|
79
|
+
);
|
|
80
|
+
Assert.IsTrue(
|
|
81
|
+
(SmallTestEnum.First | SmallTestEnum.Second).HasFlagNoAlloc(SmallTestEnum.Second)
|
|
82
|
+
);
|
|
83
|
+
Assert.IsFalse(
|
|
84
|
+
(SmallTestEnum.First | SmallTestEnum.Second).HasFlagNoAlloc(SmallTestEnum.Third)
|
|
85
|
+
);
|
|
86
|
+
Assert.IsFalse(
|
|
87
|
+
SmallTestEnum.First.HasFlagNoAlloc((SmallTestEnum.First | SmallTestEnum.Second))
|
|
88
|
+
);
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
[Test]
|
|
92
|
+
public void HasFlagNoAllocBig()
|
|
93
|
+
{
|
|
94
|
+
Assert.IsTrue(BigTestEnum.First.HasFlagNoAlloc(BigTestEnum.First));
|
|
95
|
+
Assert.IsFalse(BigTestEnum.First.HasFlagNoAlloc(BigTestEnum.Second));
|
|
96
|
+
Assert.IsTrue(
|
|
97
|
+
(BigTestEnum.First | BigTestEnum.Second).HasFlagNoAlloc(BigTestEnum.First)
|
|
98
|
+
);
|
|
99
|
+
Assert.IsTrue(
|
|
100
|
+
(BigTestEnum.First | BigTestEnum.Second).HasFlagNoAlloc(BigTestEnum.Second)
|
|
101
|
+
);
|
|
102
|
+
Assert.IsFalse(
|
|
103
|
+
(BigTestEnum.First | BigTestEnum.Second).HasFlagNoAlloc(BigTestEnum.Third)
|
|
104
|
+
);
|
|
105
|
+
Assert.IsFalse(
|
|
106
|
+
BigTestEnum.First.HasFlagNoAlloc((BigTestEnum.First | BigTestEnum.Second))
|
|
107
|
+
);
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
[Test]
|
|
111
|
+
public void HasFlagsNoAllocDoesNotAlloc()
|
|
112
|
+
{
|
|
113
|
+
Assert.That(
|
|
114
|
+
() =>
|
|
115
|
+
{
|
|
116
|
+
TestEnum.First.HasFlagNoAlloc(TestEnum.First);
|
|
117
|
+
TinyTestEnum.First.HasFlagNoAlloc(TinyTestEnum.First);
|
|
118
|
+
BigTestEnum.First.HasFlagNoAlloc(BigTestEnum.First);
|
|
119
|
+
|
|
120
|
+
TestEnum.First.HasFlagNoAlloc(TestEnum.Second);
|
|
121
|
+
TinyTestEnum.First.HasFlagNoAlloc(TinyTestEnum.Second);
|
|
122
|
+
BigTestEnum.First.HasFlagNoAlloc(BigTestEnum.Second);
|
|
123
|
+
},
|
|
124
|
+
Is.Not.AllocatingGCMemory()
|
|
125
|
+
);
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
}
|
|
@@ -1,12 +1,21 @@
|
|
|
1
1
|
namespace UnityHelpers.Tests.Extensions
|
|
2
2
|
{
|
|
3
3
|
using System;
|
|
4
|
+
using System.Collections.Generic;
|
|
4
5
|
using System.Linq;
|
|
5
6
|
using Core.Extension;
|
|
7
|
+
using Core.Random;
|
|
6
8
|
using NUnit.Framework;
|
|
7
9
|
|
|
8
10
|
public sealed class IListExtensionTests
|
|
9
11
|
{
|
|
12
|
+
private const int NumTries = 1_000;
|
|
13
|
+
|
|
14
|
+
private readonly struct IntComparer : IComparer<int>
|
|
15
|
+
{
|
|
16
|
+
public int Compare(int x, int y) => x.CompareTo(y);
|
|
17
|
+
}
|
|
18
|
+
|
|
10
19
|
[Test]
|
|
11
20
|
public void ShiftLeft()
|
|
12
21
|
{
|
|
@@ -72,5 +81,24 @@
|
|
|
72
81
|
Assert.Throws<ArgumentException>(() => input.Reverse(1, int.MaxValue));
|
|
73
82
|
Assert.Throws<ArgumentException>(() => input.Reverse(1, int.MinValue));
|
|
74
83
|
}
|
|
84
|
+
|
|
85
|
+
[Test]
|
|
86
|
+
public void InsertionSort()
|
|
87
|
+
{
|
|
88
|
+
for (int i = 0; i < NumTries; ++i)
|
|
89
|
+
{
|
|
90
|
+
int[] input = Enumerable
|
|
91
|
+
.Range(0, 100)
|
|
92
|
+
.Select(_ => PRNG.Instance.Next(int.MinValue, int.MaxValue))
|
|
93
|
+
.ToArray();
|
|
94
|
+
int[] conventionalSorted = input.ToArray();
|
|
95
|
+
Array.Sort(conventionalSorted);
|
|
96
|
+
|
|
97
|
+
int[] insertionSorted = input.ToArray();
|
|
98
|
+
insertionSorted.InsertionSort(new IntComparer());
|
|
99
|
+
Assert.That(conventionalSorted, Is.EqualTo(insertionSorted));
|
|
100
|
+
Assert.That(input.OrderBy(x => x), Is.EqualTo(insertionSorted));
|
|
101
|
+
}
|
|
102
|
+
}
|
|
75
103
|
}
|
|
76
104
|
}
|