You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
110 lines
3.5 KiB
110 lines
3.5 KiB
// Needed for NET40 |
|
#if !NET_4_6 |
|
using System; |
|
using System.Threading; |
|
using LinqInternal.Core; |
|
|
|
namespace LinqInternal.Collections.ThreadSafe |
|
{ |
|
internal static class ArrayReservoir<T> |
|
{ |
|
// sizes: |
|
// 0 1 2 3 4 5 6 7 |
|
// 8, 16, 32, 64, 128, 256, 512, 1024 |
|
|
|
private const int _capacityCount = 1 + _maxCapacityLog2 - _minCapacityLog2; |
|
private const int _maxCapacity = 1 << _maxCapacityLog2; |
|
private const int _maxCapacityLog2 = 10; |
|
private const int _minCapacity = 1 << _minCapacityLog2; |
|
private const int _minCapacityLog2 = 3; |
|
private const int _poolSize = 16; |
|
|
|
private static readonly T[] _emptyArray; |
|
private static readonly Pool<T[]>[] _pools; |
|
private static int _done; |
|
|
|
static ArrayReservoir() |
|
{ |
|
if (typeof(T) == typeof(Type)) |
|
{ |
|
_emptyArray = (T[])(object)Type.EmptyTypes; |
|
} |
|
else |
|
{ |
|
_emptyArray = new T[0]; |
|
} |
|
_pools = new Pool<T[]>[_capacityCount]; |
|
for (var index = 0; index < _capacityCount; index++) |
|
{ |
|
var currentIndex = index; |
|
_pools[index] = new Pool<T[]> |
|
( |
|
_poolSize, |
|
item => |
|
{ |
|
var currentCapacity = _minCapacity << currentIndex; |
|
Array.Clear(item, 0, currentCapacity); |
|
} |
|
); |
|
} |
|
Volatile.Write(ref _done, 1); |
|
} |
|
|
|
public static T[] EmptyArray |
|
{ |
|
get { return _emptyArray; } |
|
} |
|
|
|
internal static void DonateArray(T[] donation) |
|
{ |
|
// Assume anything could have been set to null, start no sync operation, this could be running during DomainUnload |
|
if (donation == null || Volatile.Read(ref _done) == 0) |
|
{ |
|
return; |
|
} |
|
var pools = _pools; |
|
if (pools == null) |
|
{ |
|
return; |
|
} |
|
var capacity = donation.Length; |
|
if (capacity == 0 || capacity < _minCapacity || capacity > _maxCapacity) |
|
{ |
|
return; |
|
} |
|
capacity = NumericHelper.PopulationCount(capacity) == 1 ? capacity : NumericHelper.NextPowerOf2(capacity); |
|
var index = NumericHelper.Log2(capacity) - _minCapacityLog2; |
|
var pool = pools[index]; |
|
if (pool == null) |
|
{ |
|
return; |
|
} |
|
pool.Donate(donation); |
|
} |
|
|
|
internal static T[] GetArray(int capacity) |
|
{ |
|
if (capacity == 0) |
|
{ |
|
return _emptyArray; |
|
} |
|
if (capacity < _minCapacity) |
|
{ |
|
capacity = _minCapacity; |
|
} |
|
capacity = NumericHelper.PopulationCount(capacity) == 1 ? capacity : NumericHelper.NextPowerOf2(capacity); |
|
if (capacity <= _maxCapacity && Volatile.Read(ref _done) == 1) |
|
{ |
|
var index = NumericHelper.Log2(capacity) - _minCapacityLog2; |
|
T[] result; |
|
var currentPool = _pools[index]; |
|
if (currentPool.TryGet(out result)) |
|
{ |
|
return result; |
|
} |
|
} |
|
return new T[capacity]; |
|
} |
|
} |
|
} |
|
#endif |