/
ObjectPool.cs
58 lines (48 loc) · 1.78 KB
/
ObjectPool.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
/*
* Copyright Lamont Granquist (lamont@scriptkiddie.org)
* Dual licensed under the MIT (MIT-LICENSE) license
* and GPLv2 (GPLv2-LICENSE) license or any later version.
*/
#nullable enable
using System;
using System.Collections.Concurrent;
using System.Threading;
namespace MechJebLib.Utils
{
public class ObjectPoolBase
{
// The object pool is global state, and global state is horrible for unit tests, so by setting
// UseGlobal = false the tests will use per-thread object pools, which keeps them from scribbling
// over each other's objectpools. This lets me write tests to check for allocations to make sure
// that the use of the threadpool isn't leaking objects on successive invocations.
internal static bool UseGlobal = true;
}
// TODO: min and max object levels
public class ObjectPool<T> : ObjectPoolBase
{
private readonly Func<T> _newfun;
private readonly Action<T>? _clearfun;
private readonly ConcurrentBag<T> _globalPool = new ConcurrentBag<T>();
private static readonly ThreadLocal<ConcurrentBag<T>> _localPool = new ThreadLocal<ConcurrentBag<T>>(() => new ConcurrentBag<T>());
private ConcurrentBag<T> _pool => UseGlobal ? _globalPool : _localPool.Value;
public ObjectPool(Func<T> newfun)
{
_clearfun = null;
_newfun = newfun;
}
public ObjectPool(Func<T> newfun, Action<T> clearfun)
{
_clearfun = clearfun;
_newfun = newfun;
}
public T Get()
{
return _pool.TryTake(out T item) ? item : _newfun();
}
public void Return(T item)
{
_clearfun?.Invoke(item);
_pool.Add(item);
}
}
}