-
Notifications
You must be signed in to change notification settings - Fork 7
/
ArrayPool[T].cs
128 lines (120 loc) · 6.83 KB
/
ArrayPool[T].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
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
using System;
using System.Collections.Generic;
using System.Runtime.CompilerServices;
using Platform.Disposables;
using Platform.Collections.Stacks;
namespace Platform.Collections.Arrays
{
/// <summary>
/// <para>Represents a set of arrays ready for reuse.</para>
/// <para>Представляет собой набор массивов готовых к повторному использованию.</para>
/// </summary>
/// <typeparam name="T"><para>The array elements type.</para><para>Тип элементов массива.</para></typeparam>
/// <remarks>
/// Original idea from http://geekswithblogs.net/blackrob/archive/2014/12/18/array-pooling-in-csharp.aspx
/// </remarks>
public class ArrayPool<T>
{
// May be use Default class for that later.
/// <summary>
/// <para>
/// The thread instance.
/// </para>
/// <para></para>
/// </summary>
[ThreadStatic]
private static ArrayPool<T> _threadInstance;
/// <summary>
/// <para>
/// Gets the thread instance value.
/// </para>
/// <para></para>
/// </summary>
internal static ArrayPool<T> ThreadInstance => _threadInstance ?? (_threadInstance = new ArrayPool<T>());
private readonly int _maxArraysPerSize;
private readonly Dictionary<long, Stack<T[]>> _pool = new Dictionary<long, Stack<T[]>>(ArrayPool.DefaultSizesAmount);
/// <summary>
/// <para>Initializes a new instance of the ArrayPool class using the specified maximum number of arrays per size.</para>
/// <para>Инициализирует новый экземпляр класса ArrayPool, используя указанное максимальное количество массивов на каждый размер.</para>
/// </summary>
/// <param name="maxArraysPerSize"><para>The maximum number of arrays in the pool per size.</para><para>Максимальное количество массивов в пуле на каждый размер.</para></param>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public ArrayPool(int maxArraysPerSize) => _maxArraysPerSize = maxArraysPerSize;
/// <summary>
/// <para>Initializes a new instance of the ArrayPool class using the default maximum number of arrays per size.</para>
/// <para>Инициализирует новый экземпляр класса ArrayPool, используя максимальное количество массивов на каждый размер по умолчанию.</para>
/// </summary>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public ArrayPool() : this(ArrayPool.DefaultMaxArraysPerSize) { }
/// <summary>
/// <para>Retrieves an array from the pool, which will automatically return to the pool when the container is disposed.</para>
/// <para>Извлекает из пула массив, который автоматически вернётся в пул при высвобождении контейнера.</para>
/// </summary>
/// <param name="size"><para>The allocated array size.</para><para>Размер выделяемого массива.</para></param>
/// <returns>
/// <para>The disposable container containing either a new array or an array from the pool.</para>
/// <para>Высвобождаемый контейнер содержащий либо новый массив, либо массив из пула.</para>
/// </returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public Disposable<T[]> AllocateDisposable(long size) => (Allocate(size), Free);
/// <summary>
/// <para>Replaces the array with another array from the pool with the specified size.</para>
/// <para>Заменяет массив на другой массив из пула с указанным размером.</para>
/// </summary>
/// <param name="source"><para>The source array.</para><para>Исходный массив.</para></param>
/// <param name="size"><para>A new array size.</para><para>Новый размер массива.</para></param>
/// <returns>
/// <para>An array with a new size.</para>
/// <para>Массив с новым размером.</para>
/// </returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public Disposable<T[]> Resize(Disposable<T[]> source, long size)
{
var destination = AllocateDisposable(size);
T[] sourceArray = source;
if (!sourceArray.IsNullOrEmpty())
{
T[] destinationArray = destination;
Array.Copy(sourceArray, destinationArray, size < sourceArray.LongLength ? size : sourceArray.LongLength);
source.Dispose();
}
return destination;
}
/// <summary>
/// <para>Clears the pool.</para>
/// <para>Очищает пул.</para>
/// </summary>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public virtual void Clear() => _pool.Clear();
/// <summary>
/// <para>Retrieves an array with the specified size from the pool.</para>
/// <para>Извлекает из пула массив с указанным размером.</para>
/// </summary>
/// <param name="size"><para>The allocated array size.</para><para>Размер выделяемого массива.</para></param>
/// <returns>
/// <para>An array from the pool or a new array.</para>
/// <para>Массив из пула или новый массив.</para>
/// </returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public virtual T[] Allocate(long size) => size <= 0L ? Array.Empty<T>() : _pool.GetOrDefault(size)?.PopOrDefault() ?? new T[size];
/// <summary>
/// <para>Frees the array to the pool for later reuse.</para>
/// <para>Освобождает массив в пул для последующего повторного использования.</para>
/// </summary>
/// <param name="array"><para>The array to be freed into the pool.</para><para>Массив который нужно освободить в пул.</para></param>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public virtual void Free(T[] array)
{
if (array.IsNullOrEmpty())
{
return;
}
var stack = _pool.GetOrAdd(array.LongLength, size => new Stack<T[]>(_maxArraysPerSize));
if (stack.Count == _maxArraysPerSize) // Stack is full
{
return;
}
stack.Push(array);
}
}
}