com.wallstop-studios.unity-helpers 2.0.0-rc79.3 → 2.0.0-rc79.4

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.
@@ -1,6 +1,8 @@
1
1
  namespace WallstopStudios.UnityHelpers.Utils
2
2
  {
3
+ using System;
3
4
  using System.Collections.Generic;
5
+ using System.Reflection;
4
6
  using System.Text;
5
7
  using UnityEngine;
6
8
 
@@ -27,11 +29,125 @@ namespace WallstopStudios.UnityHelpers.Utils
27
29
 
28
30
  public static class Buffers<T>
29
31
  {
30
- public static readonly T[] Array = new T[Buffers.BufferSize];
31
32
  public static readonly List<T> List = new();
32
33
  public static readonly HashSet<T> HashSet = new();
33
34
  public static readonly Queue<T> Queue = new();
34
35
  public static readonly Stack<T> Stack = new();
35
- public static readonly LinkedList<T> LinkedList = new();
36
+ }
37
+
38
+ public static class GenericPool<T>
39
+ where T : new()
40
+ {
41
+ private static readonly List<T> _pool = new();
42
+ private static readonly Action<T> _clearAction = GetClearAction();
43
+ private static readonly Action<T> _onDispose = Release;
44
+
45
+ public static PooledResource<T> Get()
46
+ {
47
+ if (_pool.Count == 0)
48
+ {
49
+ return new PooledResource<T>(new T(), _onDispose);
50
+ }
51
+
52
+ int lastIndex = _pool.Count - 1;
53
+ T instance = _pool[lastIndex];
54
+ _pool.RemoveAt(lastIndex);
55
+ return new PooledResource<T>(instance, _onDispose);
56
+ }
57
+
58
+ private static Action<T> GetClearAction()
59
+ {
60
+ Type type = typeof(T);
61
+ foreach (
62
+ MethodInfo method in type.GetMethods(BindingFlags.Instance | BindingFlags.Public)
63
+ )
64
+ {
65
+ if (
66
+ string.Equals(method.Name, "Clear", StringComparison.Ordinal)
67
+ && method.GetParameters().Length == 0
68
+ )
69
+ {
70
+ return (Action<T>)Delegate.CreateDelegate(typeof(Action<T>), method);
71
+ }
72
+ }
73
+
74
+ return _ => { };
75
+ }
76
+
77
+ private static void Release(T resource)
78
+ {
79
+ _clearAction.Invoke(resource);
80
+ _pool.Add(resource);
81
+ }
82
+ }
83
+
84
+ public static class ArrayPool<T>
85
+ {
86
+ private static readonly Dictionary<int, List<T[]>> _pool = new();
87
+ private static readonly Action<T[]> _onDispose = Release;
88
+
89
+ public static PooledResource<T[]> Get(int size)
90
+ {
91
+ switch (size)
92
+ {
93
+ case < 0:
94
+ {
95
+ throw new ArgumentOutOfRangeException(
96
+ nameof(size),
97
+ size,
98
+ "Must be non-negative."
99
+ );
100
+ }
101
+ case 0:
102
+ {
103
+ return new PooledResource<T[]>(Array.Empty<T>(), _ => { });
104
+ }
105
+ }
106
+
107
+ if (!_pool.TryGetValue(size, out List<T[]> pool))
108
+ {
109
+ pool = new List<T[]>();
110
+ _pool[size] = pool;
111
+ }
112
+
113
+ if (pool.Count == 0)
114
+ {
115
+ return new PooledResource<T[]>(new T[size], _onDispose);
116
+ }
117
+
118
+ int lastIndex = pool.Count - 1;
119
+ T[] instance = pool[lastIndex];
120
+ pool.RemoveAt(lastIndex);
121
+ return new PooledResource<T[]>(instance, _onDispose);
122
+ }
123
+
124
+ private static void Release(T[] resource)
125
+ {
126
+ int length = resource.Length;
127
+ Array.Clear(resource, 0, length);
128
+ if (!_pool.TryGetValue(length, out List<T[]> pool))
129
+ {
130
+ pool = new List<T[]>();
131
+ _pool[resource.Length] = pool;
132
+ }
133
+ pool.Add(resource);
134
+ }
135
+ }
136
+
137
+ public readonly struct PooledResource<T> : IDisposable
138
+ {
139
+ public readonly T resource;
140
+ private readonly Action<T> _onDispose;
141
+
142
+ internal PooledResource(T resource, Action<T> onDispose)
143
+ {
144
+ this.resource = resource;
145
+ _onDispose = onDispose ?? throw new ArgumentNullException(nameof(onDispose));
146
+ }
147
+
148
+ public void Dispose()
149
+ {
150
+ _onDispose(resource);
151
+ }
36
152
  }
37
153
  }
@@ -0,0 +1,55 @@
1
+ namespace WallstopStudios.UnityHelpers.Tests.Utils
2
+ {
3
+ using System.Collections.Generic;
4
+ using NUnit.Framework;
5
+ using WallstopStudios.UnityHelpers.Core.Random;
6
+ using WallstopStudios.UnityHelpers.Utils;
7
+
8
+ public sealed class BuffersTests
9
+ {
10
+ [Test]
11
+ public void GenericPoolListTests()
12
+ {
13
+ {
14
+ using PooledResource<List<int>> firstList = GenericPool<List<int>>.Get();
15
+ using PooledResource<List<int>> secondList = GenericPool<List<int>>.Get();
16
+ Assert.AreNotEqual(firstList, secondList);
17
+ firstList.resource.Add(1);
18
+ Assert.AreEqual(1, firstList.resource.Count);
19
+ Assert.AreEqual(0, secondList.resource.Count);
20
+ secondList.resource.Add(2);
21
+ Assert.AreEqual(1, firstList.resource.Count);
22
+ Assert.AreEqual(1, secondList.resource.Count);
23
+ }
24
+ {
25
+ // Ensure cleared
26
+ using PooledResource<List<int>> firstList = GenericPool<List<int>>.Get();
27
+ Assert.AreEqual(0, firstList.resource.Count);
28
+ }
29
+ }
30
+
31
+ [Test]
32
+ public void ArrayPoolSizeTests()
33
+ {
34
+ for (int i = 0; i < 100; ++i)
35
+ {
36
+ using PooledResource<int[]> resource = ArrayPool<int>.Get(i);
37
+ Assert.AreEqual(i, resource.resource.Length);
38
+ for (int j = 0; j < i; ++j)
39
+ {
40
+ resource.resource[j] = PRNG.Instance.Next();
41
+ }
42
+ }
43
+
44
+ for (int i = 0; i < 100; ++i)
45
+ {
46
+ using PooledResource<int[]> resource = ArrayPool<int>.Get(i);
47
+ Assert.AreEqual(i, resource.resource.Length);
48
+ for (int j = 0; j < i; ++j)
49
+ {
50
+ Assert.AreEqual(0, resource.resource[j]);
51
+ }
52
+ }
53
+ }
54
+ }
55
+ }
@@ -0,0 +1,3 @@
1
+ fileFormatVersion: 2
2
+ guid: ebd1e08428b148a88cdc89327b9ba8f0
3
+ timeCreated: 1757790054
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "com.wallstop-studios.unity-helpers",
3
- "version": "2.0.0-rc79.3",
3
+ "version": "2.0.0-rc79.4",
4
4
  "displayName": "Unity Helpers",
5
5
  "description": "Various Unity Helper Library",
6
6
  "dependencies": {},
@@ -47,3 +47,4 @@
47
47
 
48
48
 
49
49
 
50
+