Files
Recyclable.Collections/Recyclable.Collections/RecyclableLongList.cs
T

767 lines
23 KiB
C#

using System.Collections;
using System.Diagnostics.Contracts;
using System.Numerics;
using System.Runtime.CompilerServices;
using Recyclable.Collections.Pools;
[assembly: InternalsVisibleTo("Recyclable.Collections.Benchmarks")]
[assembly: InternalsVisibleTo("Recyclable.CollectionsTests")]
[assembly: InternalsVisibleTo("Recyclable.Collections.Compatibility.List")]
namespace Recyclable.Collections
{
public partial class RecyclableLongList<T> : IList<T>, IReadOnlyList<T>, IDisposable
{
private static readonly bool _defaultIsNull = default(T) == null;
internal static readonly bool _needsClearing = !typeof(T).IsValueType;
internal int _blockSize;
internal byte _blockSizePow2BitShift;
internal int _blockSizeMinus1;
internal long _capacity;
internal int _lastBlockWithData = RecyclableDefaults.ItemNotFoundIndex;
internal long _longCount;
#nullable disable
internal T[][] _memoryBlocks;
#nullable restore
internal int _nextItemBlockIndex;
internal int _nextItemIndex;
internal ulong _version;
public int BlockSize => _blockSize;
public int BlockSizeMinus1 => _blockSizeMinus1;
public byte BlockSizePow2BitShift => _blockSizePow2BitShift;
public long Capacity
{
get => _capacity;
private set
{
_capacity = value;
_version++;
if (_capacity != value)
{
_capacity = Helpers.Resize(this, _blockSize, _blockSizePow2BitShift, checked((long)BitOperations.RoundUpToPowerOf2((ulong)value)));
_version++;
}
}
}
public int Count => checked((int)_longCount);
public bool IsReadOnly => false;
public int LastBlockWithData => _lastBlockWithData;
public long LongCount => _longCount;
public int NextItemBlockIndex => _nextItemBlockIndex;
public int NextItemIndex => _nextItemIndex;
public ulong Version => _version;
public RecyclableLongList(int minBlockSize = RecyclableDefaults.BlockSize, long initialCapacity = RecyclableDefaults.InitialCapacity)
{
if (!BitOperations.IsPow2(minBlockSize))
{
minBlockSize = checked((int)BitOperations.RoundUpToPowerOf2((uint)minBlockSize));
}
_blockSizePow2BitShift = (byte)(31 - BitOperations.LeadingZeroCount((uint)minBlockSize));
_capacity = Helpers.Resize(this, minBlockSize, _blockSizePow2BitShift, checked((long)BitOperations.RoundUpToPowerOf2((ulong)initialCapacity)));
_blockSize = minBlockSize;
_blockSizeMinus1 = minBlockSize - 1;
}
public RecyclableLongList(in T[] source, int minBlockSize = RecyclableDefaults.BlockSize)
{
if (!BitOperations.IsPow2(minBlockSize))
{
minBlockSize = checked((int)BitOperations.RoundUpToPowerOf2((uint)minBlockSize));
}
_blockSizePow2BitShift = (byte)(31 - BitOperations.LeadingZeroCount((uint)minBlockSize));
_capacity = Helpers.Resize(this, minBlockSize, _blockSizePow2BitShift, checked((long)BitOperations.RoundUpToPowerOf2((ulong)source.LongLength)));
_blockSize = minBlockSize;
_blockSizeMinus1 = minBlockSize - 1;
zRecyclableLongListAddRange.AddRange(this, source);
}
public RecyclableLongList(in Array source, int minBlockSize = RecyclableDefaults.BlockSize)
{
if (!BitOperations.IsPow2(minBlockSize))
{
minBlockSize = checked((int)BitOperations.RoundUpToPowerOf2((uint)minBlockSize));
}
_blockSizePow2BitShift = (byte)(31 - BitOperations.LeadingZeroCount((uint)minBlockSize));
_capacity = Helpers.Resize(this, minBlockSize, _blockSizePow2BitShift, checked((long)BitOperations.RoundUpToPowerOf2((ulong)source.LongLength)));
_blockSize = minBlockSize;
_blockSizeMinus1 = minBlockSize - 1;
zRecyclableLongListAddRange.AddRange(this, source);
}
public RecyclableLongList(IReadOnlyList<T> source, int minBlockSize = RecyclableDefaults.BlockSize)
{
if (!BitOperations.IsPow2(minBlockSize))
{
minBlockSize = checked((int)BitOperations.RoundUpToPowerOf2((uint)minBlockSize));
}
_blockSizePow2BitShift = (byte)(31 - BitOperations.LeadingZeroCount((uint)minBlockSize));
_capacity = Helpers.Resize(this, minBlockSize, _blockSizePow2BitShift, checked((long)BitOperations.RoundUpToPowerOf2((ulong)source.Count)));
_blockSize = minBlockSize;
_blockSizeMinus1 = minBlockSize - 1;
zRecyclableLongListAddRange.AddRange(this, source);
}
public RecyclableLongList(ReadOnlySpan<T> source, int minBlockSize = RecyclableDefaults.BlockSize)
{
if (!BitOperations.IsPow2(minBlockSize))
{
minBlockSize = checked((int)BitOperations.RoundUpToPowerOf2((uint)minBlockSize));
}
_blockSizePow2BitShift = (byte)(31 - BitOperations.LeadingZeroCount((uint)minBlockSize));
_capacity = Helpers.Resize(this, minBlockSize, _blockSizePow2BitShift, checked((long)BitOperations.RoundUpToPowerOf2((ulong)source.Length)));
_blockSize = minBlockSize;
_blockSizeMinus1 = minBlockSize - 1;
zRecyclableLongListAddRange.AddRange(this, source);
}
public RecyclableLongList(RecyclableList<T> source, int minBlockSize = RecyclableDefaults.BlockSize)
{
if (!BitOperations.IsPow2(minBlockSize))
{
minBlockSize = checked((int)BitOperations.RoundUpToPowerOf2((uint)minBlockSize));
}
_blockSizePow2BitShift = (byte)(31 - BitOperations.LeadingZeroCount((uint)minBlockSize));
_capacity = Helpers.Resize(this, minBlockSize, _blockSizePow2BitShift, checked((long)BitOperations.RoundUpToPowerOf2((ulong)source.Count)));
_blockSize = minBlockSize;
_blockSizeMinus1 = minBlockSize - 1;
zRecyclableLongListAddRange.AddRange(this, source);
}
public RecyclableLongList(RecyclableLongList<T> source, int minBlockSize = RecyclableDefaults.BlockSize)
{
if (!BitOperations.IsPow2(minBlockSize))
{
minBlockSize = checked((int)BitOperations.RoundUpToPowerOf2((uint)minBlockSize));
}
_blockSizePow2BitShift = (byte)(31 - BitOperations.LeadingZeroCount((uint)minBlockSize));
_capacity = Helpers.Resize(this, minBlockSize, _blockSizePow2BitShift, checked((long)BitOperations.RoundUpToPowerOf2((ulong)source.Count)));
_blockSize = minBlockSize;
_blockSizeMinus1 = minBlockSize - 1;
zRecyclableLongListAddRange.AddRange(this, source);
}
public RecyclableLongList(Span<T> source, int minBlockSize = RecyclableDefaults.BlockSize)
{
if (!BitOperations.IsPow2(minBlockSize))
{
minBlockSize = checked((int)BitOperations.RoundUpToPowerOf2((uint)minBlockSize));
}
_blockSizePow2BitShift = (byte)(31 - BitOperations.LeadingZeroCount((uint)minBlockSize));
_capacity = Helpers.Resize(this, minBlockSize, _blockSizePow2BitShift, checked((long)BitOperations.RoundUpToPowerOf2((ulong)source.Length)));
_blockSize = minBlockSize;
_blockSizeMinus1 = minBlockSize - 1;
zRecyclableLongListAddRange.AddRange(this, source);
}
public RecyclableLongList(List<T> source, int minBlockSize = RecyclableDefaults.BlockSize)
{
if (!BitOperations.IsPow2(minBlockSize))
{
minBlockSize = checked((int)BitOperations.RoundUpToPowerOf2((uint)minBlockSize));
}
_blockSizePow2BitShift = (byte)(31 - BitOperations.LeadingZeroCount((uint)minBlockSize));
_capacity = Helpers.Resize(this, minBlockSize, _blockSizePow2BitShift, checked((long)BitOperations.RoundUpToPowerOf2((ulong)source.Count)));
_blockSize = minBlockSize;
_blockSizeMinus1 = minBlockSize - 1;
zRecyclableLongListAddRange.AddRange(this, source);
}
public RecyclableLongList(ICollection source, int minBlockSize = RecyclableDefaults.BlockSize)
{
if (!BitOperations.IsPow2(minBlockSize))
{
minBlockSize = checked((int)BitOperations.RoundUpToPowerOf2((uint)minBlockSize));
}
_blockSizePow2BitShift = (byte)(31 - BitOperations.LeadingZeroCount((uint)minBlockSize));
_capacity = Helpers.Resize(this, minBlockSize, _blockSizePow2BitShift, checked((long)BitOperations.RoundUpToPowerOf2((ulong)source.Count)));
_blockSize = minBlockSize;
_blockSizeMinus1 = minBlockSize - 1;
zRecyclableLongListAddRange.AddRange(this, source);
}
public RecyclableLongList(ICollection<T> source, int minBlockSize = RecyclableDefaults.BlockSize)
{
if (!BitOperations.IsPow2(minBlockSize))
{
minBlockSize = checked((int)BitOperations.RoundUpToPowerOf2((uint)minBlockSize));
}
_blockSizePow2BitShift = (byte)(31 - BitOperations.LeadingZeroCount((uint)minBlockSize));
_capacity = Helpers.Resize(this, minBlockSize, _blockSizePow2BitShift, checked((long)BitOperations.RoundUpToPowerOf2((ulong)source.Count)));
_blockSize = minBlockSize;
_blockSizeMinus1 = minBlockSize - 1;
zRecyclableLongListAddRange.AddRange(this, source);
}
public RecyclableLongList(IEnumerable source, int minBlockSize = RecyclableDefaults.BlockSize, long initialCapacity = RecyclableDefaults.InitialCapacity)
{
if (!BitOperations.IsPow2(minBlockSize))
{
minBlockSize = checked((int)BitOperations.RoundUpToPowerOf2((uint)minBlockSize));
}
_blockSizePow2BitShift = (byte)(31 - BitOperations.LeadingZeroCount((uint)minBlockSize));
_capacity = Helpers.Resize(this, minBlockSize, _blockSizePow2BitShift, checked((long)BitOperations.RoundUpToPowerOf2((ulong)initialCapacity)));
_blockSize = minBlockSize;
_blockSizeMinus1 = minBlockSize - 1;
zRecyclableLongListAddRange.AddRange(this, source);
}
public RecyclableLongList(IEnumerable<T> source, int minBlockSize = RecyclableDefaults.BlockSize, long initialCapacity = RecyclableDefaults.InitialCapacity)
{
if (!BitOperations.IsPow2(minBlockSize))
{
minBlockSize = checked((int)BitOperations.RoundUpToPowerOf2((uint)minBlockSize));
}
_blockSizePow2BitShift = (byte)(31 - BitOperations.LeadingZeroCount((uint)minBlockSize));
_capacity = Helpers.Resize(this, minBlockSize, _blockSizePow2BitShift, checked((long)BitOperations.RoundUpToPowerOf2((ulong)initialCapacity)));
_blockSize = minBlockSize;
_blockSizeMinus1 = minBlockSize - 1;
zRecyclableLongListAddRange.AddRange(this, source);
}
public T this[long index]
{
get => _memoryBlocks[index >> _blockSizePow2BitShift][index & _blockSizeMinus1];
set
{
new Span<T>(_memoryBlocks[(int)(index >> _blockSizePow2BitShift)])[(int)(index & _blockSizeMinus1)] = value;
_version++;
}
}
public T this[int index]
{
get => _memoryBlocks[index >> _blockSizePow2BitShift][index & _blockSizeMinus1];
set
{
new Span<T>(_memoryBlocks[index >> _blockSizePow2BitShift])[index & _blockSizeMinus1] = value;
_version++;
}
}
public T[][] AsArray => _memoryBlocks;
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void Add(T item)
{
if (_capacity < _longCount + 1)
{
_capacity = Helpers.Resize(this, _blockSize, _blockSizePow2BitShift, checked((long)BitOperations.RoundUpToPowerOf2((ulong)(_longCount + 1))));
}
_memoryBlocks[_nextItemBlockIndex][_nextItemIndex++] = item;
if (_nextItemIndex == _blockSize)
{
if (_nextItemBlockIndex > _lastBlockWithData)
{
_lastBlockWithData++;
}
_nextItemBlockIndex++;
_nextItemIndex = 0;
}
else if (_nextItemIndex == 1 && _nextItemBlockIndex > _lastBlockWithData)
{
_lastBlockWithData++;
}
_longCount++;
_version++;
}
public void Clear()
{
if (_longCount == 0)
{
return;
}
T[][] memoryBlocks = _memoryBlocks;
int toRemoveIdx = 0;
if (_blockSize >= RecyclableDefaults.MinPooledArrayLength)
{
while (toRemoveIdx < memoryBlocks.Length && memoryBlocks[toRemoveIdx] != null)
{
RecyclableArrayPool<T>.ReturnShared(memoryBlocks[toRemoveIdx++], _needsClearing);
}
}
else if (_needsClearing)
{
while (toRemoveIdx < memoryBlocks.Length && memoryBlocks[toRemoveIdx] != null)
{
Array.Clear(memoryBlocks[toRemoveIdx++]);
}
}
Array.Fill(_memoryBlocks, null);
_capacity = 0;
_nextItemBlockIndex = 0;
_nextItemIndex = 0;
_lastBlockWithData = RecyclableDefaults.ItemNotFoundIndex;
_longCount = 0;
_version++;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public bool Contains(T item)
{
if (_longCount == 0)
{
return false;
}
if (_nextItemBlockIndex == 0 || (_nextItemIndex == 0 && _nextItemBlockIndex == 1))
{
return Array.IndexOf(_memoryBlocks[0], item, 0, (int)_longCount) >= 0;
}
ReadOnlySpan<T[]> memoryBlocksSpan = _memoryBlocks;
int lastBlockIndex = _lastBlockWithData;
for (int blockIndex = 0; blockIndex < lastBlockIndex; blockIndex++)
{
if (Array.IndexOf(memoryBlocksSpan[blockIndex], item, 0, _blockSize) >= 0)
{
return true;
}
}
return Array.IndexOf(memoryBlocksSpan[lastBlockIndex], item, 0, _nextItemIndex > 0 ? _nextItemIndex : _blockSize) >= 0;
}
public void CopyTo(T[] array, int arrayIndex) => Helpers.CopyTo(_memoryBlocks, 0, _blockSize, _longCount, array, arrayIndex);
public Enumerator GetEnumerator() => new(this);
IEnumerator IEnumerable.GetEnumerator() => new Enumerator(this);
IEnumerator<T> IEnumerable<T>.GetEnumerator() => new Enumerator(this);
[MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)]
public int IndexOf(T item)
{
if (_lastBlockWithData == 0)
{
return Array.IndexOf(_memoryBlocks[0], item, 0, _longCount < _blockSize ? _nextItemIndex : _blockSize);
}
else if (_longCount == 0)
{
return RecyclableDefaults.ItemNotFoundIndex;
}
int itemIndex = Array.IndexOf(_memoryBlocks[0], item, 0, _blockSize);
if (itemIndex >= 0)
{
return itemIndex;
}
else if (_longCount < RecyclableDefaults.MinItemsCountForParallelization)
{
return (int)IndexOfHelpers.IndexOfSequential(this, item);
}
else
{
if (_longCount > _blockSize)
{
itemIndex = Array.IndexOf(_memoryBlocks[1], item, 0, (int)Math.Min(_blockSize, _longCount - _blockSize));
return itemIndex >= 0 ? _blockSize + itemIndex : checked((int)IndexOfHelpers.IndexOfParallel(this, item));
}
else
{
return RecyclableDefaults.ItemNotFoundIndex;
}
}
}
public int IndexOf(T item, int index)
{
if (index < 0 || index >= _longCount)
{
ThrowHelper.ThrowArgumentOutOfRangeException_Index();
}
Contract.Requires(index >= 0);
Contract.Requires(index < _longCount);
Contract.EndContractBlock();
if (_lastBlockWithData == 0)
{
return Array.IndexOf(_memoryBlocks[0], item, index, (_longCount < _blockSize ? _nextItemIndex : _blockSize) - index);
}
else if (_longCount == 0)
{
return RecyclableDefaults.ItemNotFoundIndex;
}
int firstBlockIndex = index >> _blockSizePow2BitShift;
int firstItemIndex = index & _blockSizeMinus1;
int itemIndex = Array.IndexOf(_memoryBlocks[firstBlockIndex], item, firstItemIndex, (firstBlockIndex == _lastBlockWithData && _nextItemIndex > 0 ? _nextItemIndex : _blockSize) - firstItemIndex);
if (itemIndex >= 0)
{
return (firstBlockIndex << _blockSizePow2BitShift) + itemIndex;
}
else if (_longCount < RecyclableDefaults.MinItemsCountForParallelization && firstBlockIndex + 1 <= _lastBlockWithData)
{
return (int)RecyclableLongList<T>.IndexOfHelpers.IndexOfSequential(this, item, firstBlockIndex + 1);
}
else
{
if (firstBlockIndex + 1 <= _lastBlockWithData)
{
itemIndex = Array.IndexOf(_memoryBlocks[firstBlockIndex + 1], item, 0, (int)Math.Min(firstBlockIndex + 1 == _lastBlockWithData ? _nextItemIndex : _blockSize, _longCount - _blockSize));
return itemIndex >= 0 ? ((firstBlockIndex + 1) << _blockSizePow2BitShift) + itemIndex : checked((int)RecyclableLongList<T>.IndexOfHelpers.IndexOfParallel(this, item, firstBlockIndex + 2));
}
else
{
return RecyclableDefaults.ItemNotFoundIndex;
}
}
}
public int IndexOf(T item, int index, int count)
{
if (index < 0)
{
ThrowHelper.ThrowArgumentOutOfRangeException_Index();
}
if (count + index > _longCount)
{
ThrowHelper.ThrowArgumentOutOfRangeException_Count();
}
Contract.Requires(index >= 0);
Contract.Requires(count + index <= _longCount);
Contract.EndContractBlock();
if (_lastBlockWithData == 0)
{
return Array.IndexOf(_memoryBlocks[0], item, index, count);
}
else if (_longCount == 0 || count == 0)
{
return RecyclableDefaults.ItemNotFoundIndex;
}
int blockSize = _blockSize,
firstBlockIndex = index >> _blockSizePow2BitShift,
firstItemIndex = index & _blockSizeMinus1;
int firstBlockItemsCount = Math.Min(blockSize - firstItemIndex, count);
int itemIndex = Array.IndexOf(_memoryBlocks[firstBlockIndex], item, firstItemIndex, firstBlockItemsCount);
if (itemIndex >= 0)
{
return (firstBlockIndex << _blockSizePow2BitShift) + itemIndex;
}
else if (_longCount < RecyclableDefaults.MinItemsCountForParallelization && firstBlockIndex + 1 <= _lastBlockWithData)
{
return (int)RecyclableLongList<T>.IndexOfHelpers.IndexOfSequential(this, item, firstBlockIndex + 1, count - firstBlockItemsCount);
}
else
{
if (firstBlockIndex + 1 <= _lastBlockWithData)
{
itemIndex = Array.IndexOf(_memoryBlocks[firstBlockIndex + 1], item, 0, (int)MathUtils.Min(blockSize, _longCount - blockSize, count - firstBlockItemsCount));
return itemIndex >= 0 ? ((firstBlockIndex + 1) << _blockSizePow2BitShift) + itemIndex : checked((int)RecyclableLongList<T>.IndexOfHelpers.IndexOfParallel(this, item, firstBlockIndex + 2, count - firstBlockItemsCount - blockSize));
}
else
{
return RecyclableDefaults.ItemNotFoundIndex;
}
}
}
public void Insert(int index, T item)
{
if (index > _longCount || index < 0)
{
Helpers.ThrowIndexOutOfRangeException($"Argument \"{nameof(index)}\" = {index} is out of range. Expected value between 0 and {_longCount}");
}
if (_capacity < ++_longCount)
{
_capacity = Helpers.Resize(this, _blockSize, _blockSizePow2BitShift, checked((long)BitOperations.RoundUpToPowerOf2((ulong)_longCount)));
}
if (index + 1 < _longCount)
{
Helpers.MakeRoomAndSet(this, index, item);
}
else
{
new Span<T>(_memoryBlocks[_nextItemBlockIndex])[_nextItemIndex] = item;
}
if (++_nextItemIndex == _blockSize)
{
if (_nextItemBlockIndex > _lastBlockWithData)
{
_lastBlockWithData++;
}
_nextItemBlockIndex++;
_nextItemIndex = 0;
}
else if (_nextItemIndex == 1 && _nextItemBlockIndex > _lastBlockWithData)
{
_lastBlockWithData++;
}
_version++;
}
public void Insert(long index, T item)
{
if (index > _longCount || index < 0)
{
Helpers.ThrowIndexOutOfRangeException($"Argument \"{nameof(index)}\" = {index} is out of range. Expected value between 0 and {_longCount}");
}
if (_capacity < ++_longCount)
{
_capacity = Helpers.Resize(this, _blockSize, _blockSizePow2BitShift, checked((long)BitOperations.RoundUpToPowerOf2((ulong)_longCount)));
}
if (index + 1 < _longCount)
{
Helpers.MakeRoomAndSet(this, index, item);
}
else
{
new Span<T>(_memoryBlocks[_nextItemBlockIndex])[_nextItemIndex] = item;
}
if (++_nextItemIndex == _blockSize)
{
if (_nextItemBlockIndex > _lastBlockWithData)
{
_lastBlockWithData++;
}
_nextItemBlockIndex++;
_nextItemIndex = 0;
}
else if (_nextItemIndex == 1 && _nextItemBlockIndex > _lastBlockWithData)
{
_lastBlockWithData++;
}
_version++;
}
[MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)]
public long LongIndexOf(T item)
{
if (_lastBlockWithData == 0)
{
return Array.IndexOf(_memoryBlocks[0], item, 0, _longCount < _blockSize ? _nextItemIndex : _blockSize);
}
else if (_longCount == 0)
{
return RecyclableDefaults.ItemNotFoundIndex;
}
int itemIndex = Array.IndexOf(_memoryBlocks[0], item, 0, _longCount < _blockSize ? _nextItemIndex : _blockSize);
if (itemIndex >= 0)
{
return itemIndex;
}
else if (_longCount < RecyclableDefaults.MinItemsCountForParallelization)
{
return IndexOfHelpers.IndexOfSequential(this, item);
}
else
{
if (_longCount > _blockSize)
{
itemIndex = Array.IndexOf(_memoryBlocks[1], item, 0, (int)Math.Min(_blockSize, _longCount - _blockSize));
return itemIndex >= 0 ? _blockSize + itemIndex : IndexOfHelpers.IndexOfParallel(this, item);
}
else
{
return RecyclableDefaults.ItemNotFoundIndex;
}
}
}
[MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)]
public bool Remove(T item)
{
long index;
if ((index = LongIndexOf(item)) >= 0)
{
if (index < --_longCount)
{
Helpers.CopyFollowingItems(this, index);
}
if (_nextItemIndex > 0)
{
_nextItemIndex--;
}
else
{
_nextItemIndex = _blockSizeMinus1;
_nextItemBlockIndex--;
}
if (_nextItemIndex == 0)
{
_lastBlockWithData--;
}
if (_needsClearing)
{
#nullable disable
new Span<T>(_memoryBlocks[_nextItemBlockIndex])[_nextItemIndex] = default;
#nullable restore
}
_version++;
return true;
}
return false;
}
[MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)]
public void RemoveAt(int index)
{
if (index >= _longCount || index < 0)
{
Helpers.ThrowIndexOutOfRangeException($"Argument \"{nameof(index)}\" = {index} is out of range. Expected value between 0 and {_longCount - 1}");
}
if (index < --_longCount)
{
Helpers.CopyFollowingItems(this, index);
}
if (_nextItemIndex > 0)
{
_nextItemIndex--;
}
else
{
_nextItemIndex = _blockSizeMinus1;
_nextItemBlockIndex--;
}
if (_nextItemIndex == 0)
{
_lastBlockWithData--;
}
if (_needsClearing)
{
#nullable disable
new Span<T>(_memoryBlocks[_nextItemBlockIndex])[_nextItemIndex] = default;
#nullable restore
}
_version++;
}
[MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)]
public void RemoveAt(long index)
{
if (index >= _longCount || index < 0)
{
Helpers.ThrowIndexOutOfRangeException($"Argument \"{nameof(index)}\" = {index} is out of range. Expected value between 0 and {_longCount - 1}");
}
if (index < --_longCount)
{
Helpers.CopyFollowingItems(this, index);
}
if (_nextItemIndex > 0)
{
_nextItemIndex--;
}
else
{
_nextItemIndex = _blockSizeMinus1;
_nextItemBlockIndex--;
}
if (_nextItemIndex == 0)
{
_lastBlockWithData--;
}
if (_needsClearing)
{
#nullable disable
new Span<T>(_memoryBlocks[_nextItemBlockIndex])[_nextItemIndex] = default;
#nullable restore
}
_version++;
}
public void RemoveBlock(int index)
{
if (_blockSize >= RecyclableDefaults.MinPooledArrayLength)
{
RecyclableArrayPool<T>.ReturnShared(_memoryBlocks[index], _needsClearing);
}
_memoryBlocks[index] = null;
_capacity -= _blockSize;
if (_nextItemBlockIndex == index)
{
_nextItemIndex = 0;
}
else if (_nextItemBlockIndex > index)
{
_nextItemBlockIndex--;
}
_lastBlockWithData--;
_version++;
}
public void Dispose()
{
_version++;
if (_capacity > 0)
{
Clear();
if (_memoryBlocks.Length >= RecyclableDefaults.MinPooledArrayLength)
{
// If anything, it has been already cleared by .Clear(), Remove() or RemoveAt() methods, as the list was modified / disposed.
RecyclableArrayPool<T[]>.ReturnShared(_memoryBlocks, false);
}
}
GC.SuppressFinalize(this);
}
}
}