com.wallstop-studios.unity-helpers 2.0.0-rc80.6 → 2.0.0-rc80.8
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.
|
@@ -1013,6 +1013,33 @@ namespace WallstopStudios.UnityHelpers.Core.Helper
|
|
|
1013
1013
|
}
|
|
1014
1014
|
}
|
|
1015
1015
|
|
|
1016
|
+
public static Action<T> BuildParameterlessInstanceMethodIfExists<T>(string methodName)
|
|
1017
|
+
{
|
|
1018
|
+
try
|
|
1019
|
+
{
|
|
1020
|
+
Type type = typeof(T);
|
|
1021
|
+
foreach (
|
|
1022
|
+
MethodInfo method in type.GetMethods(
|
|
1023
|
+
BindingFlags.Instance | BindingFlags.Public
|
|
1024
|
+
)
|
|
1025
|
+
)
|
|
1026
|
+
{
|
|
1027
|
+
if (
|
|
1028
|
+
string.Equals(method.Name, methodName, StringComparison.Ordinal)
|
|
1029
|
+
&& method.GetParameters().Length == 0
|
|
1030
|
+
)
|
|
1031
|
+
{
|
|
1032
|
+
return (Action<T>)Delegate.CreateDelegate(typeof(Action<T>), method);
|
|
1033
|
+
}
|
|
1034
|
+
}
|
|
1035
|
+
}
|
|
1036
|
+
catch
|
|
1037
|
+
{
|
|
1038
|
+
// Swallow
|
|
1039
|
+
}
|
|
1040
|
+
return null;
|
|
1041
|
+
}
|
|
1042
|
+
|
|
1016
1043
|
public static bool HasAttributeSafe(
|
|
1017
1044
|
ICustomAttributeProvider provider,
|
|
1018
1045
|
Type attributeType,
|
package/Runtime/Utils/Buffers.cs
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
namespace WallstopStudios.UnityHelpers.Utils
|
|
2
2
|
{
|
|
3
3
|
using System;
|
|
4
|
-
using System.Collections.Concurrent;
|
|
5
4
|
using System.Collections.Generic;
|
|
6
|
-
using System.Reflection;
|
|
7
5
|
using System.Text;
|
|
8
|
-
using System.Threading;
|
|
9
6
|
using UnityEngine;
|
|
10
|
-
|
|
7
|
+
#if !SINGLE_THREADED
|
|
8
|
+
using System.Threading;
|
|
9
|
+
using System.Collections.Concurrent;
|
|
10
|
+
#endif
|
|
11
11
|
|
|
12
12
|
public static class Buffers
|
|
13
13
|
{
|
|
@@ -38,66 +38,107 @@ namespace WallstopStudios.UnityHelpers.Utils
|
|
|
38
38
|
public static readonly Stack<T> Stack = new();
|
|
39
39
|
}
|
|
40
40
|
|
|
41
|
-
|
|
42
|
-
|
|
41
|
+
#if SINGLE_THREADED
|
|
42
|
+
public sealed class WallstopGenericPool<T> : IDisposable
|
|
43
43
|
{
|
|
44
|
-
|
|
44
|
+
private readonly Func<T> _producer;
|
|
45
|
+
private readonly Action<T> _onGet;
|
|
46
|
+
private readonly Action<T> _onRelease;
|
|
47
|
+
private readonly Action<T> _onDispose;
|
|
45
48
|
|
|
46
|
-
private
|
|
47
|
-
private static readonly Action<T> _onDispose = Release;
|
|
49
|
+
private readonly Stack<T> _pool = new();
|
|
48
50
|
|
|
49
|
-
|
|
51
|
+
public WallstopGenericPool(
|
|
52
|
+
Func<T> producer,
|
|
53
|
+
Action<T> onGet = null,
|
|
54
|
+
Action<T> onRelease = null,
|
|
55
|
+
Action<T> onDisposal = null
|
|
56
|
+
)
|
|
50
57
|
{
|
|
51
|
-
|
|
58
|
+
_producer = producer ?? throw new ArgumentNullException(nameof(producer));
|
|
59
|
+
_onGet = onGet;
|
|
60
|
+
_onRelease = onRelease ?? (_ => { });
|
|
61
|
+
_onRelease += _pool.Push;
|
|
62
|
+
_onDispose = onDisposal;
|
|
52
63
|
}
|
|
53
64
|
|
|
54
|
-
public
|
|
65
|
+
public PooledResource<T> Get()
|
|
55
66
|
{
|
|
56
|
-
if (_pool.
|
|
67
|
+
if (!_pool.TryPop(out T value))
|
|
57
68
|
{
|
|
58
|
-
|
|
69
|
+
value = _producer();
|
|
59
70
|
}
|
|
60
71
|
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
_pool.RemoveAt(lastIndex);
|
|
64
|
-
return new PooledResource<T>(instance, _onDispose);
|
|
72
|
+
_onGet?.Invoke(value);
|
|
73
|
+
return new PooledResource<T>(value, _onRelease);
|
|
65
74
|
}
|
|
66
75
|
|
|
67
|
-
|
|
76
|
+
public void Dispose()
|
|
68
77
|
{
|
|
69
|
-
|
|
78
|
+
if (_onDispose == null)
|
|
70
79
|
{
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
MethodInfo method in type.GetMethods(
|
|
74
|
-
BindingFlags.Instance | BindingFlags.Public
|
|
75
|
-
)
|
|
76
|
-
)
|
|
77
|
-
{
|
|
78
|
-
if (
|
|
79
|
-
string.Equals(method.Name, "Clear", StringComparison.Ordinal)
|
|
80
|
-
&& method.GetParameters().Length == 0
|
|
81
|
-
)
|
|
82
|
-
{
|
|
83
|
-
return (Action<T>)Delegate.CreateDelegate(typeof(Action<T>), method);
|
|
84
|
-
}
|
|
85
|
-
}
|
|
80
|
+
_pool.Clear();
|
|
81
|
+
return;
|
|
86
82
|
}
|
|
87
|
-
|
|
83
|
+
|
|
84
|
+
while (_pool.TryPop(out T value))
|
|
88
85
|
{
|
|
89
|
-
|
|
86
|
+
_onDispose(value);
|
|
90
87
|
}
|
|
91
|
-
return null;
|
|
92
88
|
}
|
|
89
|
+
}
|
|
90
|
+
#else
|
|
91
|
+
public sealed class WallstopGenericPool<T> : IDisposable
|
|
92
|
+
{
|
|
93
|
+
private readonly Func<T> _producer;
|
|
94
|
+
private readonly Action<T> _onGet;
|
|
95
|
+
private readonly Action<T> _onRelease;
|
|
96
|
+
private readonly Action<T> _onDispose;
|
|
97
|
+
|
|
98
|
+
private readonly ConcurrentStack<T> _pool = new();
|
|
93
99
|
|
|
94
|
-
|
|
100
|
+
public WallstopGenericPool(
|
|
101
|
+
Func<T> producer,
|
|
102
|
+
Action<T> onGet = null,
|
|
103
|
+
Action<T> onRelease = null,
|
|
104
|
+
Action<T> onDisposal = null
|
|
105
|
+
)
|
|
95
106
|
{
|
|
96
|
-
|
|
97
|
-
|
|
107
|
+
_producer = producer ?? throw new ArgumentNullException(nameof(producer));
|
|
108
|
+
_onGet = onGet;
|
|
109
|
+
_onRelease = onRelease ?? (_ => { });
|
|
110
|
+
_onRelease += _pool.Push;
|
|
111
|
+
_onDispose = onDisposal;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
public PooledResource<T> Get()
|
|
115
|
+
{
|
|
116
|
+
if (!_pool.TryPop(out T value))
|
|
117
|
+
{
|
|
118
|
+
value = _producer();
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
_onGet?.Invoke(value);
|
|
122
|
+
return new PooledResource<T>(value, _onRelease);
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
public void Dispose()
|
|
126
|
+
{
|
|
127
|
+
if (_onDispose == null)
|
|
128
|
+
{
|
|
129
|
+
_pool.Clear();
|
|
130
|
+
return;
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
while (_pool.TryPop(out T value))
|
|
134
|
+
{
|
|
135
|
+
_onDispose(value);
|
|
136
|
+
}
|
|
98
137
|
}
|
|
99
138
|
}
|
|
139
|
+
#endif
|
|
100
140
|
|
|
141
|
+
#if SINGLE_THREADED
|
|
101
142
|
public static class WallstopArrayPool<T>
|
|
102
143
|
{
|
|
103
144
|
private static readonly Dictionary<int, List<T[]>> _pool = new();
|
|
@@ -150,12 +191,54 @@ namespace WallstopStudios.UnityHelpers.Utils
|
|
|
150
191
|
pool.Add(resource);
|
|
151
192
|
}
|
|
152
193
|
}
|
|
194
|
+
#else
|
|
195
|
+
public static class WallstopArrayPool<T>
|
|
196
|
+
{
|
|
197
|
+
private static readonly ConcurrentDictionary<int, ConcurrentStack<T[]>> _pool = new();
|
|
198
|
+
private static readonly Action<T[]> _onRelease = Release;
|
|
199
|
+
|
|
200
|
+
public static PooledResource<T[]> Get(int size)
|
|
201
|
+
{
|
|
202
|
+
switch (size)
|
|
203
|
+
{
|
|
204
|
+
case < 0:
|
|
205
|
+
{
|
|
206
|
+
throw new ArgumentOutOfRangeException(
|
|
207
|
+
nameof(size),
|
|
208
|
+
size,
|
|
209
|
+
"Must be non-negative."
|
|
210
|
+
);
|
|
211
|
+
}
|
|
212
|
+
case 0:
|
|
213
|
+
{
|
|
214
|
+
return new PooledResource<T[]>(Array.Empty<T>(), _ => { });
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
ConcurrentStack<T[]> result = _pool.GetOrAdd(size, _ => new ConcurrentStack<T[]>());
|
|
219
|
+
if (!result.TryPop(out T[] array))
|
|
220
|
+
{
|
|
221
|
+
array = new T[size];
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
return new PooledResource<T[]>(array, _onRelease);
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
private static void Release(T[] resource)
|
|
228
|
+
{
|
|
229
|
+
int length = resource.Length;
|
|
230
|
+
Array.Clear(resource, 0, length);
|
|
231
|
+
ConcurrentStack<T[]> result = _pool.GetOrAdd(length, _ => new ConcurrentStack<T[]>());
|
|
232
|
+
result.Push(resource);
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
#endif
|
|
153
236
|
|
|
154
237
|
#if SINGLE_THREADED
|
|
155
238
|
public static class WallstopFastArrayPool<T>
|
|
156
239
|
{
|
|
157
|
-
private static readonly List<
|
|
158
|
-
private static readonly Action<T[]>
|
|
240
|
+
private static readonly List<Stack<T[]>> _pool = new();
|
|
241
|
+
private static readonly Action<T[]> _onRelease = Release;
|
|
159
242
|
|
|
160
243
|
public static PooledResource<T[]> Get(int size)
|
|
161
244
|
{
|
|
@@ -180,36 +263,32 @@ namespace WallstopStudios.UnityHelpers.Utils
|
|
|
180
263
|
_pool.Add(null);
|
|
181
264
|
}
|
|
182
265
|
|
|
183
|
-
|
|
266
|
+
Stack<T[]> pool = _pool[size];
|
|
184
267
|
if (pool == null)
|
|
185
268
|
{
|
|
186
|
-
pool = new
|
|
269
|
+
pool = new Stack<T[]>();
|
|
187
270
|
_pool[size] = pool;
|
|
188
271
|
}
|
|
189
272
|
|
|
190
|
-
if (pool.
|
|
273
|
+
if (!pool.TryPop(out T[] instance))
|
|
191
274
|
{
|
|
192
|
-
|
|
275
|
+
instance = new T[size];
|
|
193
276
|
}
|
|
194
277
|
|
|
195
|
-
|
|
196
|
-
T[] instance = pool[lastIndex];
|
|
197
|
-
pool.RemoveAt(lastIndex);
|
|
198
|
-
return new PooledResource<T[]>(instance, _onDispose);
|
|
278
|
+
return new PooledResource<T[]>(instance, _onRelease);
|
|
199
279
|
}
|
|
200
280
|
|
|
201
281
|
private static void Release(T[] resource)
|
|
202
282
|
{
|
|
203
|
-
_pool[resource.Length].
|
|
283
|
+
_pool[resource.Length].Push(resource);
|
|
204
284
|
}
|
|
205
285
|
}
|
|
206
286
|
#else
|
|
207
|
-
|
|
208
287
|
public static class WallstopFastArrayPool<T>
|
|
209
288
|
{
|
|
210
289
|
private static readonly ReaderWriterLockSlim _lock = new();
|
|
211
290
|
private static readonly List<ConcurrentStack<T[]>> _pool = new();
|
|
212
|
-
private static readonly Action<T[]>
|
|
291
|
+
private static readonly Action<T[]> _onRelease = Release;
|
|
213
292
|
|
|
214
293
|
public static PooledResource<T[]> Get(int size)
|
|
215
294
|
{
|
|
@@ -331,11 +410,12 @@ namespace WallstopStudios.UnityHelpers.Utils
|
|
|
331
410
|
}
|
|
332
411
|
}
|
|
333
412
|
|
|
334
|
-
if (pool.TryPop(out T[] instance))
|
|
413
|
+
if (!pool.TryPop(out T[] instance))
|
|
335
414
|
{
|
|
336
|
-
|
|
415
|
+
instance = new T[size];
|
|
337
416
|
}
|
|
338
|
-
|
|
417
|
+
|
|
418
|
+
return new PooledResource<T[]>(instance, _onRelease);
|
|
339
419
|
}
|
|
340
420
|
|
|
341
421
|
private static void Release(T[] resource)
|
|
@@ -16,12 +16,17 @@ namespace WallstopStudios.UnityHelpers.Tests.Utils
|
|
|
16
16
|
|
|
17
17
|
public sealed class BuffersTests
|
|
18
18
|
{
|
|
19
|
+
private readonly WallstopGenericPool<List<int>> _intPool = new(
|
|
20
|
+
() => new List<int>(),
|
|
21
|
+
onRelease: list => list.Clear()
|
|
22
|
+
);
|
|
23
|
+
|
|
19
24
|
[Test]
|
|
20
25
|
public void GenericPoolListTests()
|
|
21
26
|
{
|
|
22
27
|
{
|
|
23
|
-
using PooledResource<List<int>> firstList =
|
|
24
|
-
using PooledResource<List<int>> secondList =
|
|
28
|
+
using PooledResource<List<int>> firstList = _intPool.Get();
|
|
29
|
+
using PooledResource<List<int>> secondList = _intPool.Get();
|
|
25
30
|
Assert.AreNotEqual(firstList, secondList);
|
|
26
31
|
firstList.resource.Add(1);
|
|
27
32
|
Assert.AreEqual(1, firstList.resource.Count);
|
|
@@ -32,7 +37,7 @@ namespace WallstopStudios.UnityHelpers.Tests.Utils
|
|
|
32
37
|
}
|
|
33
38
|
{
|
|
34
39
|
// Ensure cleared
|
|
35
|
-
using PooledResource<List<int>> firstList =
|
|
40
|
+
using PooledResource<List<int>> firstList = _intPool.Get();
|
|
36
41
|
Assert.AreEqual(0, firstList.resource.Count);
|
|
37
42
|
}
|
|
38
43
|
}
|
|
@@ -654,7 +659,7 @@ namespace WallstopStudios.UnityHelpers.Tests.Utils
|
|
|
654
659
|
[Test]
|
|
655
660
|
public void WallstopGenericPoolGetReturnsValidPooledResource()
|
|
656
661
|
{
|
|
657
|
-
using PooledResource<List<int>> pooled =
|
|
662
|
+
using PooledResource<List<int>> pooled = _intPool.Get();
|
|
658
663
|
|
|
659
664
|
Assert.NotNull(pooled.resource);
|
|
660
665
|
Assert.AreEqual(0, pooled.resource.Count);
|
|
@@ -665,14 +670,14 @@ namespace WallstopStudios.UnityHelpers.Tests.Utils
|
|
|
665
670
|
{
|
|
666
671
|
List<int> firstList;
|
|
667
672
|
|
|
668
|
-
using (PooledResource<List<int>> pooled =
|
|
673
|
+
using (PooledResource<List<int>> pooled = _intPool.Get())
|
|
669
674
|
{
|
|
670
675
|
firstList = pooled.resource;
|
|
671
676
|
firstList.Add(42);
|
|
672
677
|
firstList.Add(100);
|
|
673
678
|
}
|
|
674
679
|
|
|
675
|
-
using PooledResource<List<int>> pooledReused =
|
|
680
|
+
using PooledResource<List<int>> pooledReused = _intPool.Get();
|
|
676
681
|
Assert.AreSame(firstList, pooledReused.resource);
|
|
677
682
|
Assert.AreEqual(0, pooledReused.resource.Count);
|
|
678
683
|
}
|
|
@@ -680,9 +685,8 @@ namespace WallstopStudios.UnityHelpers.Tests.Utils
|
|
|
680
685
|
[Test]
|
|
681
686
|
public void WallstopGenericPoolClearActionWorksWithCustomType()
|
|
682
687
|
{
|
|
683
|
-
using
|
|
684
|
-
|
|
685
|
-
>.Get();
|
|
688
|
+
using WallstopGenericPool<HashSet<string>> pool = new(() => new HashSet<string>());
|
|
689
|
+
using PooledResource<HashSet<string>> pooled = pool.Get();
|
|
686
690
|
|
|
687
691
|
pooled.resource.Add("test1");
|
|
688
692
|
pooled.resource.Add("test2");
|
|
@@ -692,29 +696,30 @@ namespace WallstopStudios.UnityHelpers.Tests.Utils
|
|
|
692
696
|
[Test]
|
|
693
697
|
public void PooledResourceDisposeCallsOnDisposeAction()
|
|
694
698
|
{
|
|
699
|
+
bool clearCalled = false;
|
|
695
700
|
bool disposeCalled = false;
|
|
696
|
-
WallstopGenericPool<List<int>>.clearAction ??= list => list.Clear();
|
|
697
|
-
WallstopGenericPool<List<int>>.clearAction += Callback;
|
|
698
|
-
try
|
|
699
701
|
{
|
|
700
|
-
using
|
|
702
|
+
using WallstopGenericPool<List<int>> pool = new(
|
|
703
|
+
() => new List<int>(),
|
|
704
|
+
onRelease: list =>
|
|
705
|
+
{
|
|
706
|
+
list.Clear();
|
|
707
|
+
clearCalled = true;
|
|
708
|
+
},
|
|
709
|
+
onDisposal: _ => disposeCalled = true
|
|
710
|
+
);
|
|
711
|
+
|
|
712
|
+
using (PooledResource<List<int>> pooled = pool.Get())
|
|
701
713
|
{
|
|
702
714
|
Assert.NotNull(pooled.resource);
|
|
715
|
+
Assert.IsFalse(clearCalled);
|
|
703
716
|
Assert.IsFalse(disposeCalled);
|
|
704
717
|
}
|
|
705
718
|
|
|
706
|
-
Assert.IsTrue(
|
|
707
|
-
}
|
|
708
|
-
finally
|
|
709
|
-
{
|
|
710
|
-
WallstopGenericPool<List<int>>.clearAction -= Callback;
|
|
719
|
+
Assert.IsTrue(clearCalled);
|
|
711
720
|
}
|
|
712
721
|
|
|
713
|
-
|
|
714
|
-
void Callback(List<int> list)
|
|
715
|
-
{
|
|
716
|
-
disposeCalled = true;
|
|
717
|
-
}
|
|
722
|
+
Assert.IsTrue(disposeCalled);
|
|
718
723
|
}
|
|
719
724
|
}
|
|
720
725
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "com.wallstop-studios.unity-helpers",
|
|
3
|
-
"version": "2.0.0-rc80.
|
|
3
|
+
"version": "2.0.0-rc80.8",
|
|
4
4
|
"displayName": "Unity Helpers",
|
|
5
5
|
"description": "Various Unity Helper Library",
|
|
6
6
|
"dependencies": {},
|
|
@@ -35,28 +35,4 @@
|
|
|
35
35
|
"scripts": {
|
|
36
36
|
"test": "echo \"Error: no test specified\" && exit 1"
|
|
37
37
|
}
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
38
|
+
}
|