RecyclableLongList.Insert implemented.

This commit is contained in:
mlemanczyk committed 2023-08-05 17:05:29 +02:00
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)
+37 -1
View File
@@ -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]