RecyclableLongList.Insert implemented.
This commit is contained in:
1 parent
8714b5b977
commit
a80db94533
3 files changed
+80
-3
No files matched your search
@@ -90,6 +90,38 @@ namespace Recyclable.Collections
|
||||
}
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)]
|
||||
public static void MakeRoomAndSet(RecyclableLongList<T> list, long startingItemIndex, T item)
|
||||
{
|
||||
T[] currentBlock;
|
||||
T[][] memoryBlocks = list._memoryBlocks;
|
||||
int blockSizeMinus1 = list._blockSizeMinus1,
|
||||
targetItemIndex = (int)(startingItemIndex & blockSizeMinus1),
|
||||
targetBlockIndex = (int)(startingItemIndex >> list._blockSizePow2BitShift) + (targetItemIndex != 0 ? 1 : 0),
|
||||
lastTakenBlockIndex = list._lastBlockWithData;
|
||||
|
||||
if (list._nextItemIndex == 0)
|
||||
{
|
||||
new Span<T>(memoryBlocks[lastTakenBlockIndex + 1])[0] = memoryBlocks[lastTakenBlockIndex][blockSizeMinus1];
|
||||
}
|
||||
|
||||
int currentBlockIndex = lastTakenBlockIndex;
|
||||
while (currentBlockIndex > targetBlockIndex)
|
||||
{
|
||||
new Span<T>(currentBlock = memoryBlocks[currentBlockIndex--], 0, blockSizeMinus1)
|
||||
.CopyTo(new Span<T>(currentBlock, 1, blockSizeMinus1));
|
||||
new Span<T>(currentBlock)[0] = memoryBlocks[currentBlockIndex][blockSizeMinus1];
|
||||
}
|
||||
|
||||
if (lastTakenBlockIndex >= 0)
|
||||
{
|
||||
new Span<T>(currentBlock = memoryBlocks[targetBlockIndex], targetItemIndex, blockSizeMinus1 - targetItemIndex)
|
||||
.CopyTo(new Span<T>(currentBlock, targetItemIndex + 1, blockSizeMinus1 - targetItemIndex));
|
||||
}
|
||||
|
||||
new Span<T>(memoryBlocks[targetBlockIndex])[targetItemIndex] = item;
|
||||
}
|
||||
|
||||
public static void CopyTo(T[][] sourceMemoryBlocks, long startingIndex, int blockSize, long itemsCount, T[] destinationArray, int destinationArrayIndex)
|
||||
{
|
||||
if (itemsCount <= 0)
|
||||
|
||||
@@ -835,7 +835,43 @@ namespace Recyclable.Collections
|
||||
}
|
||||
}
|
||||
|
||||
public void Insert(int index, T item) => throw new NotSupportedException();
|
||||
public void Insert(int index, T item)
|
||||
{
|
||||
if (index > _longCount++ || index < 0)
|
||||
{
|
||||
_longCount--;
|
||||
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 (_longCount > 1)
|
||||
{
|
||||
Helpers.MakeRoomAndSet(this, index, item);
|
||||
}
|
||||
else
|
||||
{
|
||||
new Span<T>(_memoryBlocks[0])[0] = item;
|
||||
}
|
||||
|
||||
if (_nextItemIndex < _blockSizeMinus1)
|
||||
{
|
||||
if (++_nextItemIndex == 1)
|
||||
{
|
||||
_lastBlockWithData++;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
_nextItemIndex = 0;
|
||||
_nextItemBlockIndex++;
|
||||
}
|
||||
|
||||
_version++;
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)]
|
||||
public long LongIndexOf(T item)
|
||||
|
||||
@@ -513,10 +513,19 @@ namespace Recyclable.CollectionsTests
|
||||
public void InsertAtTheBeginningShouldMoveItems(string testCase, IEnumerable<long> testData, long itemsCount, int targetBlockSize)
|
||||
{
|
||||
// Prepare
|
||||
using var list = new RecyclableLongList<long>(testData, minBlockSize: targetBlockSize);
|
||||
using var list = new RecyclableLongList<long>();
|
||||
|
||||
// Act
|
||||
_ = Assert.Throws<NotSupportedException>(() => list.Insert(0, -1));
|
||||
foreach (var item in testData)
|
||||
{
|
||||
list.Insert(0, item);
|
||||
_ = list.Count.Should().Be((int)item);
|
||||
}
|
||||
|
||||
// Validate
|
||||
_ = list.Capacity.Should().BeGreaterThanOrEqualTo((int)itemsCount);
|
||||
_ = list.Count.Should().Be((int)itemsCount);
|
||||
_ = list.Should().ContainInConsecutiveOrder(testData.Reverse());
|
||||
}
|
||||
|
||||
[Theory]
|
||||
|
||||
Reference in new issue
Block a user