Skip to content

Commit cdcf3e1

Browse files
MrBlueaustinv900
andcommitted
Refactor Pooling
Co-Authored-By: Austin Vandersluis <austinv900@nindroidservers.com>
1 parent a9da442 commit cdcf3e1

8 files changed

Lines changed: 373 additions & 79 deletions

File tree

src/Pooling/ArrayPool.cs

Lines changed: 153 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,153 @@
1+
using System;
2+
using System.Collections.Generic;
3+
4+
namespace Oxide.Pooling
5+
{
6+
public sealed class ArrayPool<T> : PoolFactory, IArrayPool<T>
7+
{
8+
#region Settings / Defaults
9+
10+
public const int DEFAULT_ARRAY_MAX_LENGTH = 512;
11+
12+
public const int DEFAULT_ARRAY_MAX_PER_POOL = 50;
13+
14+
public const bool DEFAULT_ARRAY_CLEAN_ON_RETURN = true;
15+
16+
/// <summary>
17+
/// The amount of arrays this pool can store per array length
18+
/// </summary>
19+
public int ArraysPerLength { get; }
20+
21+
/// <summary>
22+
/// Max length of the array this pool can store
23+
/// </summary>
24+
public int ArrayMaxLength { get; }
25+
26+
/// <summary>
27+
/// Empties the array on return
28+
/// </summary>
29+
public bool CleanOnReturn { get; }
30+
31+
#endregion
32+
33+
#region Properties
34+
35+
/// <summary>
36+
/// The shared pool instance
37+
/// </summary>
38+
public static IArrayPool<T> Shared { get; }
39+
40+
/// <summary>
41+
/// Creates a new pool instance with default settings
42+
/// </summary>
43+
public static IArrayPool<T> Default => new ArrayPool<T>(DEFAULT_ARRAY_MAX_PER_POOL, DEFAULT_ARRAY_MAX_LENGTH, DEFAULT_ARRAY_CLEAN_ON_RETURN);
44+
45+
/// <summary>
46+
/// Returns a pool instance that doesn't pool items
47+
/// </summary>
48+
public static IArrayPool<T> NoPool => NullArrayPool<T>.Instance;
49+
50+
/// <summary>
51+
/// Creates a new pool instance with custom settings
52+
/// </summary>
53+
/// <param name="arrayMaxLength">Max length of the array this pool can store</param>
54+
/// <param name="arrayMaxPerPool">The amount of arrays this pool can store per array length</param>
55+
/// <param name="arrayCleanOnReturn">Empties the array on return</param>
56+
/// <returns>The custom array pool</returns>
57+
public static IArrayPool<T> Custom(int arrayMaxLength = DEFAULT_ARRAY_MAX_LENGTH, int arrayMaxPerPool = DEFAULT_ARRAY_MAX_PER_POOL, bool arrayCleanOnReturn = DEFAULT_ARRAY_CLEAN_ON_RETURN)
58+
{
59+
return new ArrayPool<T>(arrayMaxPerPool, arrayMaxLength, arrayCleanOnReturn);
60+
}
61+
62+
public static T[] Empty { get; }
63+
64+
private Stack<T[]>[] Pools { get; }
65+
66+
#endregion
67+
68+
static ArrayPool()
69+
{
70+
Empty = new T[0];
71+
Shared = Default;
72+
}
73+
74+
private ArrayPool(int arraysPerLength = 50, int maxArrayLength = 512, bool cleanOnReturn = true)
75+
{
76+
ArraysPerLength = arraysPerLength <= 0 ? throw new ArgumentOutOfRangeException(nameof(arraysPerLength)) : arraysPerLength;
77+
ArrayMaxLength = maxArrayLength < 1 ? 1 : maxArrayLength;
78+
CleanOnReturn = cleanOnReturn;
79+
80+
Pools = new Stack<T[]>[ArrayMaxLength];
81+
for (int i = 0; i < Pools.Length; i++)
82+
{
83+
Pools[i] = new Stack<T[]>();
84+
}
85+
}
86+
87+
public T[] Take() => Empty;
88+
89+
public T[] Take(int length)
90+
{
91+
if (length <= 0)
92+
{
93+
return Empty;
94+
}
95+
96+
if (length > ArrayMaxLength)
97+
{
98+
return new T[length];
99+
}
100+
101+
Stack<T[]> store = Pools[length - 1];
102+
103+
lock (store)
104+
{
105+
if (store.Count > 0)
106+
{
107+
return store.Pop();
108+
}
109+
}
110+
111+
return new T[length];
112+
}
113+
114+
public void Return(T[] item)
115+
{
116+
if (item == null || item.Length == 0 || item.Length > ArrayMaxLength)
117+
{
118+
return;
119+
}
120+
121+
if (CleanOnReturn)
122+
{
123+
Array.Clear(item, 0, item.Length);
124+
}
125+
126+
Stack<T[]> store = Pools[item.Length - 1];
127+
128+
lock (store)
129+
{
130+
if (store.Count < ArraysPerLength)
131+
{
132+
store.Push(item);
133+
}
134+
}
135+
}
136+
137+
protected override void OnPurge()
138+
{
139+
for (int i = 0; i < Pools.Length; i++)
140+
{
141+
Stack<T[]> store = Pools[i];
142+
lock (store)
143+
{
144+
while (store.Count > 0)
145+
{
146+
T[] array = store.Pop();
147+
Array.Clear(array, 0, array.Length);
148+
}
149+
}
150+
}
151+
}
152+
}
153+
}
Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
namespace Oxide.Pooling
22
{
3-
/// <inheritdoc cref="IPoolProvider"/>
3+
/// <inheritdoc cref="IPool{T[]}"/>
44
/// <typeparam name="T">The item type this pool manages</typeparam>
5-
public interface IArrayPoolProvider<out T> : IPoolProvider<T[]>
5+
public interface IArrayPool<T> : IPool<T[]>
66
{
77
/// <summary>
88
/// Takes a single <see cref="T"/> array from this pool
Lines changed: 8 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,25 +1,21 @@
11
namespace Oxide.Pooling
22
{
33
/// <summary>
4-
/// A interface used for managing pooled items
4+
/// Used for pooling items
55
/// </summary>
6-
public interface IPoolProvider
7-
{
8-
/// <summary>
9-
/// Returns a item to the pool
10-
/// </summary>
11-
/// <param name="item">The item to return</param>
12-
void Return(object item);
13-
}
14-
15-
/// <inheritdoc cref="IPoolProvider"/>
166
/// <typeparam name="T">The item type this pool manages</typeparam>
17-
public interface IPoolProvider<out T> : IPoolProvider
7+
public interface IPool<T>
188
{
199
/// <summary>
2010
/// Takes a single <see cref="T"/> from this pool
2111
/// </summary>
2212
/// <returns><see cref="T"/></returns>
2313
T Take();
14+
15+
/// <summary>
16+
/// Returns a item to the pool
17+
/// </summary>
18+
/// <param name="item">The item to return</param>
19+
void Return(T item);
2420
}
2521
}

src/Pooling/IPoolFactory.cs

Lines changed: 0 additions & 33 deletions
This file was deleted.

src/Pooling/NullArrayPool.cs

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
namespace Oxide.Pooling
2+
{
3+
internal class NullArrayPool<T> : IArrayPool<T>
4+
{
5+
public static IArrayPool<T> Instance { get; } = new NullArrayPool<T>();
6+
7+
protected T[] Empty { get; }
8+
9+
private NullArrayPool()
10+
{
11+
Empty = [];
12+
}
13+
14+
public void Return(T[] item) { }
15+
16+
public T[] Take(int length) => new T[length];
17+
18+
public T[] Take() => Empty;
19+
}
20+
}

src/Pooling/NullPool.cs

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
namespace Oxide.Pooling
2+
{
3+
internal class NullPool<T> : IPool<T> where T : new()
4+
{
5+
public static IPool<T> Instance { get; } = new NullPool<T>();
6+
7+
public T Take() => new();
8+
9+
public void Return(T item) { }
10+
}
11+
}

0 commit comments

Comments
 (0)