com.wallstop-studios.unity-helpers 2.0.0-rc24 → 2.0.0-rc25
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 +29 -7
- package/Runtime/Core/Extension/IListExtensions.cs +30 -0
- package/Runtime/Core/Helper/WallMath.cs +28 -0
- package/Tests/Runtime/DataStructures/CyclicBufferTests.cs +80 -5
- package/Tests/Runtime/Helper/WallMathTests.cs +13 -1
- package/package.json +1 -1
|
@@ -4,16 +4,16 @@
|
|
|
4
4
|
using System.Collections;
|
|
5
5
|
using System.Collections.Generic;
|
|
6
6
|
using System.Linq;
|
|
7
|
+
using Extension;
|
|
7
8
|
using Helper;
|
|
8
9
|
|
|
9
10
|
[Serializable]
|
|
10
11
|
public sealed class CyclicBuffer<T> : IReadOnlyList<T>
|
|
11
12
|
{
|
|
13
|
+
public int Capacity { get; private set; }
|
|
12
14
|
public int Count { get; private set; }
|
|
13
15
|
public bool IsReadOnly => false;
|
|
14
16
|
|
|
15
|
-
public readonly int capacity;
|
|
16
|
-
|
|
17
17
|
private readonly List<T> _buffer;
|
|
18
18
|
private int _position;
|
|
19
19
|
|
|
@@ -38,7 +38,7 @@
|
|
|
38
38
|
throw new ArgumentException(nameof(capacity));
|
|
39
39
|
}
|
|
40
40
|
|
|
41
|
-
|
|
41
|
+
Capacity = capacity;
|
|
42
42
|
_position = 0;
|
|
43
43
|
Count = 0;
|
|
44
44
|
_buffer = new List<T>();
|
|
@@ -64,7 +64,7 @@
|
|
|
64
64
|
|
|
65
65
|
public void Add(T item)
|
|
66
66
|
{
|
|
67
|
-
if (
|
|
67
|
+
if (Capacity == 0)
|
|
68
68
|
{
|
|
69
69
|
return;
|
|
70
70
|
}
|
|
@@ -78,8 +78,8 @@
|
|
|
78
78
|
_buffer.Add(item);
|
|
79
79
|
}
|
|
80
80
|
|
|
81
|
-
_position = _position.WrappedIncrement(
|
|
82
|
-
if (Count <
|
|
81
|
+
_position = _position.WrappedIncrement(Capacity);
|
|
82
|
+
if (Count < Capacity)
|
|
83
83
|
{
|
|
84
84
|
++Count;
|
|
85
85
|
}
|
|
@@ -93,6 +93,24 @@
|
|
|
93
93
|
_buffer.Clear();
|
|
94
94
|
}
|
|
95
95
|
|
|
96
|
+
public void Resize(int newCapacity)
|
|
97
|
+
{
|
|
98
|
+
if (newCapacity < 0)
|
|
99
|
+
{
|
|
100
|
+
throw new ArgumentException(nameof(newCapacity));
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
Capacity = newCapacity;
|
|
104
|
+
_buffer.Shift(-_position);
|
|
105
|
+
if (newCapacity < _buffer.Count)
|
|
106
|
+
{
|
|
107
|
+
_buffer.RemoveRange(newCapacity, _buffer.Count - newCapacity);
|
|
108
|
+
_position = 0;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
Count = Math.Min(newCapacity, Count);
|
|
112
|
+
}
|
|
113
|
+
|
|
96
114
|
public bool Contains(T item)
|
|
97
115
|
{
|
|
98
116
|
return _buffer.Contains(item);
|
|
@@ -100,7 +118,11 @@
|
|
|
100
118
|
|
|
101
119
|
private int AdjustedIndexFor(int index)
|
|
102
120
|
{
|
|
103
|
-
long longCapacity =
|
|
121
|
+
long longCapacity = Capacity;
|
|
122
|
+
if (longCapacity == 0L)
|
|
123
|
+
{
|
|
124
|
+
return 0;
|
|
125
|
+
}
|
|
104
126
|
unchecked
|
|
105
127
|
{
|
|
106
128
|
int adjustedIndex = (int)(
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
namespace UnityHelpers.Core.Extension
|
|
2
2
|
{
|
|
3
3
|
using System.Collections.Generic;
|
|
4
|
+
using Helper;
|
|
4
5
|
using Random;
|
|
5
6
|
|
|
6
7
|
public static class IListExtensions
|
|
@@ -26,6 +27,35 @@
|
|
|
26
27
|
}
|
|
27
28
|
}
|
|
28
29
|
|
|
30
|
+
public static void Shift<T>(this IList<T> list, int amount)
|
|
31
|
+
{
|
|
32
|
+
int count = list.Count;
|
|
33
|
+
if (count <= 1)
|
|
34
|
+
{
|
|
35
|
+
return;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
amount = amount.PositiveMod(count);
|
|
39
|
+
if (amount == 0)
|
|
40
|
+
{
|
|
41
|
+
return;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
Reverse(list, 0, count - 1);
|
|
45
|
+
Reverse(list, 0, amount - 1);
|
|
46
|
+
Reverse(list, amount, count - 1);
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
public static void Reverse<T>(this IList<T> list, int start, int end)
|
|
50
|
+
{
|
|
51
|
+
while (start < end)
|
|
52
|
+
{
|
|
53
|
+
(list[start], list[end]) = (list[end], list[start]);
|
|
54
|
+
start++;
|
|
55
|
+
end--;
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
|
|
29
59
|
public static void RemoveAtSwapBack<T>(this IList<T> list, int index)
|
|
30
60
|
{
|
|
31
61
|
if (list.Count <= 1)
|
|
@@ -31,6 +31,34 @@
|
|
|
31
31
|
);
|
|
32
32
|
}
|
|
33
33
|
|
|
34
|
+
public static float PositiveMod(this float value, float max)
|
|
35
|
+
{
|
|
36
|
+
value %= max;
|
|
37
|
+
value += max;
|
|
38
|
+
return value % max;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
public static double PositiveMod(this double value, double max)
|
|
42
|
+
{
|
|
43
|
+
value %= max;
|
|
44
|
+
value += max;
|
|
45
|
+
return value % max;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
public static int PositiveMod(this int value, int max)
|
|
49
|
+
{
|
|
50
|
+
value %= max;
|
|
51
|
+
value += max;
|
|
52
|
+
return value % max;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
public static long PositiveMod(this long value, long max)
|
|
56
|
+
{
|
|
57
|
+
value %= max;
|
|
58
|
+
value += max;
|
|
59
|
+
return value % max;
|
|
60
|
+
}
|
|
61
|
+
|
|
34
62
|
public static int WrappedAdd(this int value, int increment, int max)
|
|
35
63
|
{
|
|
36
64
|
WrappedAdd(ref value, increment, max);
|
|
@@ -32,7 +32,7 @@
|
|
|
32
32
|
{
|
|
33
33
|
int capacity = PRNG.Instance.Next(1, int.MaxValue);
|
|
34
34
|
CyclicBuffer<int> buffer = new(capacity);
|
|
35
|
-
Assert.AreEqual(capacity, buffer.
|
|
35
|
+
Assert.AreEqual(capacity, buffer.Capacity);
|
|
36
36
|
}
|
|
37
37
|
}
|
|
38
38
|
|
|
@@ -74,7 +74,7 @@
|
|
|
74
74
|
if (!expected.SequenceEqual(buffer))
|
|
75
75
|
{
|
|
76
76
|
Assert.Fail(
|
|
77
|
-
$"Failure at iteration {i}, capacity={buffer.
|
|
77
|
+
$"Failure at iteration {i}, capacity={buffer.Capacity}, "
|
|
78
78
|
+ $"capacityMultiplier={CapacityMultiplier}\n"
|
|
79
79
|
+ $"Expected: [{string.Join(",", expected)}], Actual: [{string.Join(",", buffer)}]"
|
|
80
80
|
);
|
|
@@ -168,7 +168,7 @@
|
|
|
168
168
|
if (!expected.SequenceEqual(buffer))
|
|
169
169
|
{
|
|
170
170
|
Assert.Fail(
|
|
171
|
-
$"Failure at iteration {i}, j={j}, capacity={buffer.
|
|
171
|
+
$"Failure at iteration {i}, j={j}, capacity={buffer.Capacity}, "
|
|
172
172
|
+ $"capacityMultiplier={CapacityMultiplier}\n"
|
|
173
173
|
+ $"Expected: [{string.Join(",", expected)}], Actual: [{string.Join(",", buffer)}]"
|
|
174
174
|
);
|
|
@@ -190,14 +190,18 @@
|
|
|
190
190
|
[Test]
|
|
191
191
|
public void ClearOk()
|
|
192
192
|
{
|
|
193
|
+
HashSet<int> seen = new();
|
|
193
194
|
for (int i = 0; i < NumTries; ++i)
|
|
194
195
|
{
|
|
195
196
|
int capacity = PRNG.Instance.Next(100, 1_000);
|
|
196
197
|
CyclicBuffer<int> buffer = new(capacity);
|
|
197
198
|
float fillPercent = PRNG.Instance.NextFloat(0.5f, 1.5f);
|
|
199
|
+
seen.Clear();
|
|
198
200
|
for (int j = 0; j < capacity * fillPercent; ++j)
|
|
199
201
|
{
|
|
200
|
-
|
|
202
|
+
int value = PRNG.Instance.Next();
|
|
203
|
+
seen.Add(value);
|
|
204
|
+
buffer.Add(value);
|
|
201
205
|
}
|
|
202
206
|
|
|
203
207
|
Assert.AreNotEqual(0, buffer.Count);
|
|
@@ -205,8 +209,79 @@
|
|
|
205
209
|
buffer.Clear();
|
|
206
210
|
|
|
207
211
|
Assert.AreEqual(0, buffer.Count);
|
|
208
|
-
Assert.AreEqual(capacity, buffer.
|
|
212
|
+
Assert.AreEqual(capacity, buffer.Capacity);
|
|
209
213
|
Assert.IsTrue(Array.Empty<int>().SequenceEqual(buffer));
|
|
214
|
+
|
|
215
|
+
// Make sure our data is actually cleaned up, none of our input data should be "Contained"
|
|
216
|
+
foreach (int value in seen)
|
|
217
|
+
{
|
|
218
|
+
Assert.IsFalse(buffer.Contains(value));
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
[Test]
|
|
224
|
+
public void ResizeFullOk()
|
|
225
|
+
{
|
|
226
|
+
for (int i = 0; i < NumTries; ++i)
|
|
227
|
+
{
|
|
228
|
+
int capacity = PRNG.Instance.Next(100, 1_000);
|
|
229
|
+
CyclicBuffer<int> buffer = new(capacity);
|
|
230
|
+
float fillPercent = PRNG.Instance.NextFloat(1f, 2f);
|
|
231
|
+
float capacityPercent = PRNG.Instance.NextFloat(0.3f, 0.9f);
|
|
232
|
+
for (int j = 0; j < capacity * fillPercent; ++j)
|
|
233
|
+
{
|
|
234
|
+
int value = PRNG.Instance.Next();
|
|
235
|
+
buffer.Add(value);
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
int[] values = buffer.ToArray();
|
|
239
|
+
|
|
240
|
+
int newCapacity = Math.Max(0, (int)(capacity * capacityPercent));
|
|
241
|
+
buffer.Resize(newCapacity);
|
|
242
|
+
int[] newValues = buffer.ToArray();
|
|
243
|
+
Assert.AreEqual(newCapacity, buffer.Capacity);
|
|
244
|
+
Assert.AreEqual(newCapacity, newValues.Length);
|
|
245
|
+
Assert.That(values.Take(newCapacity), Is.EqualTo(newValues));
|
|
246
|
+
|
|
247
|
+
newCapacity = 0;
|
|
248
|
+
buffer.Resize(newCapacity);
|
|
249
|
+
newValues = buffer.ToArray();
|
|
250
|
+
Assert.AreEqual(newCapacity, buffer.Capacity);
|
|
251
|
+
Assert.AreEqual(newCapacity, newValues.Length);
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
[Test]
|
|
256
|
+
public void ResizePartialOk()
|
|
257
|
+
{
|
|
258
|
+
for (int i = 0; i < NumTries; ++i)
|
|
259
|
+
{
|
|
260
|
+
int capacity = PRNG.Instance.Next(100, 1_000);
|
|
261
|
+
CyclicBuffer<int> buffer = new(capacity);
|
|
262
|
+
float fillPercent = PRNG.Instance.NextFloat(0.3f, 0.9f);
|
|
263
|
+
float capacityPercent = PRNG.Instance.NextFloat(0.3f, 0.9f);
|
|
264
|
+
int filled = (int)(capacity * fillPercent);
|
|
265
|
+
for (int j = 0; j < filled; ++j)
|
|
266
|
+
{
|
|
267
|
+
int value = PRNG.Instance.Next();
|
|
268
|
+
buffer.Add(value);
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
int[] values = buffer.ToArray();
|
|
272
|
+
|
|
273
|
+
int newCapacity = Math.Max(0, (int)(capacity * capacityPercent));
|
|
274
|
+
buffer.Resize(newCapacity);
|
|
275
|
+
int[] newValues = buffer.ToArray();
|
|
276
|
+
Assert.AreEqual(newCapacity, buffer.Capacity);
|
|
277
|
+
Assert.AreEqual(Math.Min(filled, newCapacity), newValues.Length);
|
|
278
|
+
Assert.That(values.Take(newCapacity), Is.EqualTo(newValues));
|
|
279
|
+
|
|
280
|
+
newCapacity = 0;
|
|
281
|
+
buffer.Resize(newCapacity);
|
|
282
|
+
newValues = buffer.ToArray();
|
|
283
|
+
Assert.AreEqual(newCapacity, buffer.Capacity);
|
|
284
|
+
Assert.AreEqual(newCapacity, newValues.Length);
|
|
210
285
|
}
|
|
211
286
|
}
|
|
212
287
|
}
|
|
@@ -44,6 +44,19 @@
|
|
|
44
44
|
}
|
|
45
45
|
}
|
|
46
46
|
|
|
47
|
+
[Test]
|
|
48
|
+
public void PositiveMod()
|
|
49
|
+
{
|
|
50
|
+
Assert.AreEqual(9, (-1).PositiveMod(10));
|
|
51
|
+
Assert.AreEqual(1, 1.PositiveMod(10));
|
|
52
|
+
Assert.AreEqual(9f, (-1f).PositiveMod(10f));
|
|
53
|
+
Assert.AreEqual(1f, 1f.PositiveMod(10f));
|
|
54
|
+
Assert.AreEqual(9.0, (-1.0).PositiveMod(10.0));
|
|
55
|
+
Assert.AreEqual(1.0, 1.0.PositiveMod(10.0));
|
|
56
|
+
Assert.AreEqual(9L, (-1L).PositiveMod(10L));
|
|
57
|
+
Assert.AreEqual(1L, 1L.PositiveMod(10L));
|
|
58
|
+
}
|
|
59
|
+
|
|
47
60
|
[Test]
|
|
48
61
|
public void ApproximatelyExpected()
|
|
49
62
|
{
|
|
@@ -51,7 +64,6 @@
|
|
|
51
64
|
Assert.IsTrue(0f.Approximately(0.5f, 1f));
|
|
52
65
|
Assert.IsFalse(0.001f.Approximately(0f, 0f));
|
|
53
66
|
Assert.IsFalse(100f.Approximately(5f, 2.4f));
|
|
54
|
-
|
|
55
67
|
Assert.IsTrue(0.001f.Approximately(0.0001f));
|
|
56
68
|
}
|
|
57
69
|
|