Optimize long-list AddRange for stack
This commit is contained in:
1 parent
4274f4dcbc
commit
1aedfb2cbc
2 files changed
+77
-4
No files matched your search
@@ -281,27 +281,62 @@ namespace Recyclable.Collections
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
EnsureCapacity(stack, stack._count + longCount);
|
||||||
|
|
||||||
int blockSize = items._blockSize;
|
int blockSize = items._blockSize;
|
||||||
int fullBlocks = (int)(longCount >> items._blockSizePow2BitShift);
|
int fullBlocks = (int)(longCount >> items._blockSizePow2BitShift);
|
||||||
int lastBlockLength = (int)(longCount & items._blockSizeMinus1);
|
int lastBlockLength = (int)(longCount & items._blockSizeMinus1);
|
||||||
|
|
||||||
|
RecyclableArrayPoolChunk<T> chunk = stack._current;
|
||||||
|
int index = chunk.Index;
|
||||||
|
int chunkLength = chunk.Value.Length;
|
||||||
|
|
||||||
for (int blockIndex = 0; blockIndex < fullBlocks; blockIndex++)
|
for (int blockIndex = 0; blockIndex < fullBlocks; blockIndex++)
|
||||||
{
|
{
|
||||||
T[] block = items._memoryBlocks[blockIndex];
|
T[] block = items._memoryBlocks[blockIndex];
|
||||||
for (int i = 0; i < blockSize; i++)
|
int sourceIndex = 0;
|
||||||
|
while (sourceIndex < blockSize)
|
||||||
{
|
{
|
||||||
stack.Push(block[i]);
|
if (index == chunkLength)
|
||||||
|
{
|
||||||
|
chunk.Index = index;
|
||||||
|
Grow(stack);
|
||||||
|
chunk = stack._current;
|
||||||
|
index = chunk.Index;
|
||||||
|
chunkLength = chunk.Value.Length;
|
||||||
|
}
|
||||||
|
|
||||||
|
int toCopy = Math.Min(chunkLength - index, blockSize - sourceIndex);
|
||||||
|
Array.Copy(block, sourceIndex, chunk.Value, index, toCopy);
|
||||||
|
sourceIndex += toCopy;
|
||||||
|
index += toCopy;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (lastBlockLength > 0)
|
if (lastBlockLength > 0)
|
||||||
{
|
{
|
||||||
T[] block = items._memoryBlocks[fullBlocks];
|
T[] block = items._memoryBlocks[fullBlocks];
|
||||||
for (int i = 0; i < lastBlockLength; i++)
|
int sourceIndex = 0;
|
||||||
|
while (sourceIndex < lastBlockLength)
|
||||||
{
|
{
|
||||||
stack.Push(block[i]);
|
if (index == chunkLength)
|
||||||
|
{
|
||||||
|
chunk.Index = index;
|
||||||
|
Grow(stack);
|
||||||
|
chunk = stack._current;
|
||||||
|
index = chunk.Index;
|
||||||
|
chunkLength = chunk.Value.Length;
|
||||||
|
}
|
||||||
|
|
||||||
|
int toCopy = Math.Min(chunkLength - index, lastBlockLength - sourceIndex);
|
||||||
|
Array.Copy(block, sourceIndex, chunk.Value, index, toCopy);
|
||||||
|
sourceIndex += toCopy;
|
||||||
|
index += toCopy;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
chunk.Index = index;
|
||||||
|
stack._count += longCount;
|
||||||
}
|
}
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.NoInlining | MethodImplOptions.AggressiveOptimization)]
|
[MethodImpl(MethodImplOptions.NoInlining | MethodImplOptions.AggressiveOptimization)]
|
||||||
|
|||||||
@@ -404,5 +404,43 @@ namespace Recyclable.CollectionsTests
|
|||||||
_ = stack.Should().Equal(expected);
|
_ = stack.Should().Equal(expected);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Theory]
|
||||||
|
[MemberData(nameof(RecyclableLongListTestData.ItemsCountTestCases), MemberType = typeof(RecyclableLongListTestData))]
|
||||||
|
public void AddRangeShouldAddLongListItemsInCorrectOrder(int itemsCount)
|
||||||
|
{
|
||||||
|
long[] data = RecyclableLongListTestData.CreateTestData(itemsCount).ToArray();
|
||||||
|
using var source = new RecyclableLongList<long>(data);
|
||||||
|
using var stack = new RecyclableStack<long>();
|
||||||
|
|
||||||
|
stack.AddRange(source);
|
||||||
|
|
||||||
|
List<long> expected = new(itemsCount);
|
||||||
|
expected.AddRange(data);
|
||||||
|
expected.Reverse();
|
||||||
|
|
||||||
|
_ = stack.Count.Should().Be(itemsCount);
|
||||||
|
_ = stack.Should().Equal(expected);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Theory]
|
||||||
|
[MemberData(nameof(RecyclableLongListTestData.ItemsCountTestCases), MemberType = typeof(RecyclableLongListTestData))]
|
||||||
|
public void AddRangeShouldNotOverrideItemsFromLongList(int itemsCount)
|
||||||
|
{
|
||||||
|
long[] data = RecyclableLongListTestData.CreateTestData(itemsCount).ToArray();
|
||||||
|
using var source = new RecyclableLongList<long>(data);
|
||||||
|
using var stack = new RecyclableStack<long>();
|
||||||
|
|
||||||
|
stack.AddRange(source);
|
||||||
|
stack.AddRange(source);
|
||||||
|
|
||||||
|
List<long> expected = new(itemsCount * 2);
|
||||||
|
expected.AddRange(data);
|
||||||
|
expected.AddRange(data);
|
||||||
|
expected.Reverse();
|
||||||
|
|
||||||
|
_ = stack.Count.Should().Be(itemsCount * 2);
|
||||||
|
_ = stack.Should().Equal(expected);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Reference in new issue
Block a user