RecyclableList.AddRange(IEnumerable<T> source) performance improvements. Small source code cleanup.
This commit is contained in:
1 parent
efb393e13f
commit
c211fb6ee4
2 files changed
+40
-23
No files matched your search
@@ -548,7 +548,7 @@ namespace Recyclable.Collections
|
|||||||
}
|
}
|
||||||
|
|
||||||
long capacity = _capacity;
|
long capacity = _capacity;
|
||||||
long oldLongCount = _longCount;
|
long copied = _longCount;
|
||||||
int blockSize = _blockSize;
|
int blockSize = _blockSize;
|
||||||
int targetItemIdx = _nextItemIndex;
|
int targetItemIdx = _nextItemIndex;
|
||||||
int targetBlockIdx = _lastBlockIndex;
|
int targetBlockIdx = _lastBlockIndex;
|
||||||
@@ -557,7 +557,7 @@ namespace Recyclable.Collections
|
|||||||
Span<T> blockArraySpan;
|
Span<T> blockArraySpan;
|
||||||
if (source.TryGetNonEnumeratedCount(out var requiredAdditionalCapacity))
|
if (source.TryGetNonEnumeratedCount(out var requiredAdditionalCapacity))
|
||||||
{
|
{
|
||||||
long requiredCapacity = oldLongCount + requiredAdditionalCapacity;
|
long requiredCapacity = copied + requiredAdditionalCapacity;
|
||||||
if (capacity < requiredCapacity)
|
if (capacity < requiredCapacity)
|
||||||
{
|
{
|
||||||
_ = EnsureCapacity(requiredCapacity);
|
_ = EnsureCapacity(requiredCapacity);
|
||||||
@@ -594,53 +594,68 @@ namespace Recyclable.Collections
|
|||||||
|
|
||||||
if (enumerator.MoveNext())
|
if (enumerator.MoveNext())
|
||||||
{
|
{
|
||||||
long available = capacity - targetItemIdx;
|
long available = capacity - copied,
|
||||||
memoryBlocksSpan = new(_memoryBlocks);
|
initialCount = copied;
|
||||||
|
|
||||||
|
memoryBlocksSpan = new(_memoryBlocks, 0, _memoryBlocks.Length);
|
||||||
var memoryBlocksCount = memoryBlocksSpan.Length;
|
var memoryBlocksCount = memoryBlocksSpan.Length;
|
||||||
while (true)
|
while (true)
|
||||||
{
|
{
|
||||||
if (targetItemIdx + growByCount > capacity)
|
if (copied + growByCount > capacity)
|
||||||
{
|
{
|
||||||
capacity = EnsureCapacity(capacity + growByCount);
|
capacity = EnsureCapacity(capacity + growByCount);
|
||||||
memoryBlocksSpan = new(_memoryBlocks);
|
memoryBlocksCount = _memoryBlocks.Length;
|
||||||
memoryBlocksCount = memoryBlocksSpan.Length;
|
if (blockSize != _blockSize)
|
||||||
available = capacity - targetItemIdx;
|
{
|
||||||
|
blockSize = _blockSize;
|
||||||
}
|
}
|
||||||
|
|
||||||
blockArraySpan = memoryBlocksSpan[targetBlockIdx];
|
memoryBlocksSpan = new(_memoryBlocks, 0, memoryBlocksCount);
|
||||||
for (i = 0; i < available; i++)
|
available = capacity - copied;
|
||||||
|
}
|
||||||
|
|
||||||
|
blockArraySpan = new(memoryBlocksSpan[targetBlockIdx], 0, blockSize);
|
||||||
|
for (i = 1; i <= available; i++)
|
||||||
{
|
{
|
||||||
blockArraySpan[targetItemIdx++] = enumerator.Current;
|
blockArraySpan[targetItemIdx++] = enumerator.Current;
|
||||||
|
|
||||||
if (!enumerator.MoveNext())
|
if (!enumerator.MoveNext())
|
||||||
{
|
{
|
||||||
break;
|
copied += i;
|
||||||
|
if (targetItemIdx < blockSize)
|
||||||
|
{
|
||||||
|
_lastBlockIndex = targetBlockIdx;
|
||||||
|
_nextItemIndex = targetItemIdx;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_lastBlockIndex = targetBlockIdx + 1;
|
||||||
|
_nextItemIndex = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
_longCount += copied - _longCount;
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (targetItemIdx == blockSize)
|
if (targetItemIdx == blockSize)
|
||||||
{
|
{
|
||||||
targetBlockIdx++;
|
targetBlockIdx++;
|
||||||
|
targetItemIdx = 0;
|
||||||
|
|
||||||
if (targetBlockIdx == memoryBlocksCount)
|
if (targetBlockIdx == memoryBlocksCount)
|
||||||
{
|
{
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
targetItemIdx = 0;
|
blockArraySpan = new(memoryBlocksSpan[targetBlockIdx], 0, blockSize);
|
||||||
blockArraySpan = new(memoryBlocksSpan[targetBlockIdx]);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (i < available)
|
copied += available;
|
||||||
{
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
_longCount = targetItemIdx;
|
|
||||||
_lastBlockIndex = targetBlockIdx;
|
|
||||||
_nextItemIndex = targetItemIdx;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Clear()
|
public void Clear()
|
||||||
{
|
{
|
||||||
if (_blockSize >= RecyclableDefaults.MinPooledArrayLength)
|
if (_blockSize >= RecyclableDefaults.MinPooledArrayLength)
|
||||||
|
|||||||
@@ -320,7 +320,8 @@ namespace Recyclable.CollectionsTests
|
|||||||
new object[] { "RecyclableArrayList<int>", _testData.ToRecyclableArrayList() },
|
new object[] { "RecyclableArrayList<int>", _testData.ToRecyclableArrayList() },
|
||||||
new object[] { "RecyclableList<int>", _testData.ToRecyclableList() },
|
new object[] { "RecyclableList<int>", _testData.ToRecyclableList() },
|
||||||
new object[] { "IList<int>", new CustomIList<int>(_testData) },
|
new object[] { "IList<int>", new CustomIList<int>(_testData) },
|
||||||
new object[] { "IEnumerable<int>", _testData },
|
new object[] { "IEnumerable<int> with non-enumerated count", _testData },
|
||||||
|
new object[] { "IEnumerable<int> without non-enumerated count", new EnumerableWithoutCount<int>(_testData) }
|
||||||
};
|
};
|
||||||
|
|
||||||
public static IEnumerable<object[]> AddRangeEmptyCollectionTypes => new[]
|
public static IEnumerable<object[]> AddRangeEmptyCollectionTypes => new[]
|
||||||
@@ -433,7 +434,8 @@ namespace Recyclable.CollectionsTests
|
|||||||
|
|
||||||
// Validate
|
// Validate
|
||||||
var expectedData = testData.Concat(testData).ToArray();
|
var expectedData = testData.Concat(testData).ToArray();
|
||||||
_ = list.Capacity.Should().Be(229376L, "when capacity == 0, then we allocate as much memory as needed, only");
|
_ = list.Capacity.Should().BeGreaterThanOrEqualTo(expectedData.Length)
|
||||||
|
.And.BeLessThan((int)(expectedData.Length * 1.5));
|
||||||
_ = list.Should().HaveCount(expectedData.Length)
|
_ = list.Should().HaveCount(expectedData.Length)
|
||||||
.And.ContainInConsecutiveOrder(expectedData)
|
.And.ContainInConsecutiveOrder(expectedData)
|
||||||
.And.BeEquivalentTo(expectedData);
|
.And.BeEquivalentTo(expectedData);
|
||||||
|
|||||||
Reference in new issue
Block a user