com.wallstop-studios.unity-helpers 2.0.0-rc80.6 → 2.0.0-rc80.7

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,
@@ -3,11 +3,9 @@ namespace WallstopStudios.UnityHelpers.Utils
3
3
  using System;
4
4
  using System.Collections.Concurrent;
5
5
  using System.Collections.Generic;
6
- using System.Reflection;
7
6
  using System.Text;
8
7
  using System.Threading;
9
8
  using UnityEngine;
10
- using WallstopStudios.UnityHelpers.Core.Helper;
11
9
 
12
10
  public static class Buffers
13
11
  {
@@ -38,33 +36,42 @@ namespace WallstopStudios.UnityHelpers.Utils
38
36
  public static readonly Stack<T> Stack = new();
39
37
  }
40
38
 
41
- public static class WallstopGenericPool<T>
42
- where T : new()
39
+ #if SINGLE_THREADED
40
+ public sealed class WallstopGenericPool<T> : IDisposable
43
41
  {
44
- public static Action<T> clearAction;
42
+ private readonly Func<T> _producer;
43
+ private readonly Action<T> _onGet;
44
+ private readonly Action<T> _onRelease;
45
+ private readonly Action<T> _onDispose;
45
46
 
46
- private static readonly List<T> _pool = new();
47
- private static readonly Action<T> _onDispose = Release;
47
+ private readonly Stack<T> _pool = new();
48
48
 
49
- static WallstopGenericPool()
49
+ public WallstopGenericPool(
50
+ Func<T> producer,
51
+ Action<T> onGet = null,
52
+ Action<T> onRelease = null,
53
+ Action<T> onDisposal = null
54
+ )
50
55
  {
51
- clearAction = GetClearAction();
56
+ _producer = producer ?? throw new ArgumentNullException(nameof(producer));
57
+ _onGet = onGet;
58
+ _onRelease = onRelease ?? (_ => { });
59
+ _onRelease += _pool.Push;
60
+ _onDispose = onDisposal;
52
61
  }
53
62
 
54
- public static PooledResource<T> Get()
63
+ public PooledResource<T> Get()
55
64
  {
56
- if (_pool.Count == 0)
65
+ if (!_pool.TryPop(out T value))
57
66
  {
58
- return new PooledResource<T>(new T(), _onDispose);
67
+ value = _producer();
59
68
  }
60
69
 
61
- int lastIndex = _pool.Count - 1;
62
- T instance = _pool[lastIndex];
63
- _pool.RemoveAt(lastIndex);
64
- return new PooledResource<T>(instance, _onDispose);
70
+ _onGet?.Invoke(value);
71
+ return new PooledResource<T>(value, _onRelease);
65
72
  }
66
73
 
67
- private static Action<T> GetClearAction()
74
+ public static Action<T> GetClearAction()
68
75
  {
69
76
  try
70
77
  {
@@ -91,13 +98,72 @@ namespace WallstopStudios.UnityHelpers.Utils
91
98
  return null;
92
99
  }
93
100
 
94
- private static void Release(T resource)
101
+ public void Dispose()
95
102
  {
96
- clearAction?.Invoke(resource);
97
- _pool.Add(resource);
103
+ if (_onDispose == null)
104
+ {
105
+ _pool.Clear();
106
+ return;
107
+ }
108
+
109
+ while (_pool.TryPop(out T value))
110
+ {
111
+ _onDispose(value);
112
+ }
98
113
  }
99
114
  }
115
+ #else
116
+ public sealed class WallstopGenericPool<T> : IDisposable
117
+ {
118
+ private readonly Func<T> _producer;
119
+ private readonly Action<T> _onGet;
120
+ private readonly Action<T> _onRelease;
121
+ private readonly Action<T> _onDispose;
122
+
123
+ private readonly ConcurrentStack<T> _pool = new();
124
+
125
+ public WallstopGenericPool(
126
+ Func<T> producer,
127
+ Action<T> onGet = null,
128
+ Action<T> onRelease = null,
129
+ Action<T> onDisposal = null
130
+ )
131
+ {
132
+ _producer = producer ?? throw new ArgumentNullException(nameof(producer));
133
+ _onGet = onGet;
134
+ _onRelease = onRelease ?? (_ => { });
135
+ _onRelease += _pool.Push;
136
+ _onDispose = onDisposal;
137
+ }
100
138
 
139
+ public PooledResource<T> Get()
140
+ {
141
+ if (!_pool.TryPop(out T value))
142
+ {
143
+ value = _producer();
144
+ }
145
+
146
+ _onGet?.Invoke(value);
147
+ return new PooledResource<T>(value, _onRelease);
148
+ }
149
+
150
+ public void Dispose()
151
+ {
152
+ if (_onDispose == null)
153
+ {
154
+ _pool.Clear();
155
+ return;
156
+ }
157
+
158
+ while (_pool.TryPop(out T value))
159
+ {
160
+ _onDispose(value);
161
+ }
162
+ }
163
+ }
164
+ #endif
165
+
166
+ #if SINGLE_THREADED
101
167
  public static class WallstopArrayPool<T>
102
168
  {
103
169
  private static readonly Dictionary<int, List<T[]>> _pool = new();
@@ -150,12 +216,54 @@ namespace WallstopStudios.UnityHelpers.Utils
150
216
  pool.Add(resource);
151
217
  }
152
218
  }
219
+ #else
220
+ public static class WallstopArrayPool<T>
221
+ {
222
+ private static readonly ConcurrentDictionary<int, ConcurrentStack<T[]>> _pool = new();
223
+ private static readonly Action<T[]> _onRelease = Release;
224
+
225
+ public static PooledResource<T[]> Get(int size)
226
+ {
227
+ switch (size)
228
+ {
229
+ case < 0:
230
+ {
231
+ throw new ArgumentOutOfRangeException(
232
+ nameof(size),
233
+ size,
234
+ "Must be non-negative."
235
+ );
236
+ }
237
+ case 0:
238
+ {
239
+ return new PooledResource<T[]>(Array.Empty<T>(), _ => { });
240
+ }
241
+ }
242
+
243
+ ConcurrentStack<T[]> result = _pool.GetOrAdd(size, _ => new ConcurrentStack<T[]>());
244
+ if (!result.TryPop(out T[] array))
245
+ {
246
+ array = new T[size];
247
+ }
248
+
249
+ return new PooledResource<T[]>(array, _onRelease);
250
+ }
251
+
252
+ private static void Release(T[] resource)
253
+ {
254
+ int length = resource.Length;
255
+ Array.Clear(resource, 0, length);
256
+ ConcurrentStack<T[]> result = _pool.GetOrAdd(length, _ => new ConcurrentStack<T[]>());
257
+ result.Push(resource);
258
+ }
259
+ }
260
+ #endif
153
261
 
154
262
  #if SINGLE_THREADED
155
263
  public static class WallstopFastArrayPool<T>
156
264
  {
157
- private static readonly List<List<T[]>> _pool = new();
158
- private static readonly Action<T[]> _onDispose = Release;
265
+ private static readonly List<Stack<T[]>> _pool = new();
266
+ private static readonly Action<T[]> _onRelease = Release;
159
267
 
160
268
  public static PooledResource<T[]> Get(int size)
161
269
  {
@@ -180,27 +288,24 @@ namespace WallstopStudios.UnityHelpers.Utils
180
288
  _pool.Add(null);
181
289
  }
182
290
 
183
- List<T[]> pool = _pool[size];
291
+ Stack<T[]> pool = _pool[size];
184
292
  if (pool == null)
185
293
  {
186
- pool = new List<T[]>();
294
+ pool = new Stack<T[]>();
187
295
  _pool[size] = pool;
188
296
  }
189
297
 
190
- if (pool.Count == 0)
298
+ if (!pool.TryPop(out T[] instance))
191
299
  {
192
- return new PooledResource<T[]>(new T[size], _onDispose);
300
+ instance = new T[size];
193
301
  }
194
302
 
195
- int lastIndex = pool.Count - 1;
196
- T[] instance = pool[lastIndex];
197
- pool.RemoveAt(lastIndex);
198
- return new PooledResource<T[]>(instance, _onDispose);
303
+ return new PooledResource<T[]>(instance, _onRelease);
199
304
  }
200
305
 
201
306
  private static void Release(T[] resource)
202
307
  {
203
- _pool[resource.Length].Add(resource);
308
+ _pool[resource.Length].Push(resource);
204
309
  }
205
310
  }
206
311
  #else
@@ -209,7 +314,7 @@ namespace WallstopStudios.UnityHelpers.Utils
209
314
  {
210
315
  private static readonly ReaderWriterLockSlim _lock = new();
211
316
  private static readonly List<ConcurrentStack<T[]>> _pool = new();
212
- private static readonly Action<T[]> _onDispose = Release;
317
+ private static readonly Action<T[]> _onRelease = Release;
213
318
 
214
319
  public static PooledResource<T[]> Get(int size)
215
320
  {
@@ -331,11 +436,12 @@ namespace WallstopStudios.UnityHelpers.Utils
331
436
  }
332
437
  }
333
438
 
334
- if (pool.TryPop(out T[] instance))
439
+ if (!pool.TryPop(out T[] instance))
335
440
  {
336
- return new PooledResource<T[]>(instance, _onDispose);
441
+ instance = new T[size];
337
442
  }
338
- return new PooledResource<T[]>(new T[size], _onDispose);
443
+
444
+ return new PooledResource<T[]>(instance, _onRelease);
339
445
  }
340
446
 
341
447
  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 = WallstopGenericPool<List<int>>.Get();
24
- using PooledResource<List<int>> secondList = WallstopGenericPool<List<int>>.Get();
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 = WallstopGenericPool<List<int>>.Get();
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 = WallstopGenericPool<List<int>>.Get();
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 = WallstopGenericPool<List<int>>.Get())
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 = WallstopGenericPool<List<int>>.Get();
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 PooledResource<HashSet<string>> pooled = WallstopGenericPool<
684
- HashSet<string>
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 (PooledResource<List<int>> pooled = WallstopGenericPool<List<int>>.Get())
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(disposeCalled);
707
- }
708
- finally
709
- {
710
- WallstopGenericPool<List<int>>.clearAction -= Callback;
719
+ Assert.IsTrue(clearCalled);
711
720
  }
712
721
 
713
- return;
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.6",
3
+ "version": "2.0.0-rc80.7",
4
4
  "displayName": "Unity Helpers",
5
5
  "description": "Various Unity Helper Library",
6
6
  "dependencies": {},
@@ -58,5 +58,6 @@
58
58
 
59
59
 
60
60
 
61
+
61
62
 
62
63