Benchmarks improved. Contains & IndexOf separated into 2 groups: first 1 000 items & last 1 000 items.

This commit is contained in:
Marek Lemańczyk committed 2023-02-05 22:58:48 +01:00
1 parent 743e88f0e6
commit 59defd435c
4 files changed
+104 -417

No files matched your search

+1 -1
View File
@@ -16,7 +16,7 @@ internal class Program
benchmark.Setup(); benchmark.Setup();
foreach (var _ in Enumerable.Range(1, 1000)) foreach (var _ in Enumerable.Range(1, 1000))
{ {
benchmark.RecyclableList_Contains(); //benchmark.RecyclableList_Contains();
//benchmark.RecyclableArrayList_AddRange_WithCapacity(); //benchmark.RecyclableArrayList_AddRange_WithCapacity();
//benchmark.RecyclableArrayList_Add_WithCapacity(); //benchmark.RecyclableArrayList_Add_WithCapacity();
@@ -112,28 +112,52 @@ namespace Recyclable.Collections.Benchmarks
DoNothing(data.Count); DoNothing(data.Count);
} }
//[Benchmark(Baseline = true)] [Benchmark(Baseline = true)]
public void List_Contains() public void List_Contains_1_000_FirstItems()
{ {
var data = TestObjects; var data = TestObjects;
var list = TestObjectsAsList; var list = TestObjectsAsList;
var dataCount = 100_000; var dataCount = 1_000;
for (var i = 0; i < dataCount; i++) for (var i = 0; i < dataCount; i++)
{ {
DoNothing(list.Contains(data[i])); DoNothing(list.Contains(data[i]));
} }
} }
[Benchmark(Baseline = true)] [Benchmark]
public void List_IndexOf() public void List_Contains_1_000_LastItems()
{ {
var data = TestObjects; var data = TestObjects;
var list = TestObjectsAsList; var list = TestObjectsAsList;
var dataCount = 100_000; var dataCount = 1_000;
for (var i = 0; i < dataCount; i++)
{
DoNothing(list.Contains(data[^(i + 1)]));
}
}
//[Benchmark(Baseline = true)]
public void List_IndexOf_1_000_FirstItems()
{
var data = TestObjects;
var list = TestObjectsAsList;
var dataCount = 1_000;
for (var i = 0; i < dataCount; i++) for (var i = 0; i < dataCount; i++)
{ {
DoNothing(list.IndexOf(data[i])); DoNothing(list.IndexOf(data[i]));
} }
} }
//[Benchmark]
public void List_IndexOf_1_000_LastItems()
{
var data = TestObjects;
var list = TestObjectsAsList;
var dataCount = 1_000;
for (var i = 0; i < dataCount; i++)
{
DoNothing(list.IndexOf(data[^(i + 1)]));
}
}
} }
} }
@@ -78,12 +78,12 @@ namespace Recyclable.Collections.Benchmarks
DoNothing(data.LongCount); DoNothing(data.LongCount);
} }
//[Benchmark] [Benchmark]
public void RecyclableList_Contains() public void RecyclableList_Contains_1_000_FirstItems()
{ {
var data = TestObjects; var data = TestObjects;
var list = TestObjectsAsRecyclableList; var list = TestObjectsAsRecyclableList;
var dataCount = 100_000; var dataCount = 1000;
for (var i = 0; i < dataCount; i++) for (var i = 0; i < dataCount; i++)
{ {
DoNothing(list.Contains(data[i])); DoNothing(list.Contains(data[i]));
@@ -91,15 +91,39 @@ namespace Recyclable.Collections.Benchmarks
} }
[Benchmark] [Benchmark]
public void RecyclableList_IndexOf() public void RecyclableList_Contains_1_000_LastItems()
{ {
var data = TestObjects; var data = TestObjects;
var list = TestObjectsAsRecyclableList; var list = TestObjectsAsRecyclableList;
var dataCount = 100_000; var dataCount = 1_000;
for (var i = 0; i < dataCount; i++)
{
DoNothing(list.Contains(data[^(i + 1)]));
}
}
//[Benchmark]
public void RecyclableList_IndexOf_1_000_FirstItems()
{
var data = TestObjects;
var list = TestObjectsAsRecyclableList;
var dataCount = 1000;
for (var i = 0; i < dataCount; i++) for (var i = 0; i < dataCount; i++)
{ {
DoNothing(list.IndexOf(data[i])); DoNothing(list.IndexOf(data[i]));
} }
} }
//[Benchmark]
public void RecyclableList_IndexOf_1_000_LastItems()
{
var data = TestObjects;
var list = TestObjectsAsRecyclableList;
var dataCount = 1_000;
for (var i = 0; i < dataCount; i++)
{
DoNothing(list.IndexOf(data[^(i + 1)]));
}
}
} }
} }
+44 -405
View File
@@ -515,221 +515,27 @@ namespace Recyclable.Collections
return false; return false;
} }
int blockSize = _blockSize; int itemIndex, blockIndex = 0, lastBlockIndex = _lastBlockIndex, blockSize = _blockSize;
int itemIndex = 0;
int blockIndex = 0;
int lastBlockIndex = _lastBlockIndex;
Span<T[]> memoryBlocksSpan = new(_memoryBlocks); Span<T[]> memoryBlocksSpan = new(_memoryBlocks);
Span<T> blockArraySpan = new(memoryBlocksSpan[blockIndex]); while (blockIndex < lastBlockIndex)
if (item != null)
{ {
while (blockIndex < lastBlockIndex) itemIndex = Array.IndexOf(memoryBlocksSpan[blockIndex], item, 0, blockSize);
if (itemIndex >= 0)
{ {
if (item.Equals(blockArraySpan[itemIndex])) return true;
{
return true;
}
if (itemIndex + 1 < blockSize && item.Equals(blockArraySpan[itemIndex + 1]))
{
return true;
}
if (itemIndex + 2 < blockSize && item.Equals(blockArraySpan[itemIndex + 2]))
{
return true;
}
if (itemIndex + 3 < blockSize && item.Equals(blockArraySpan[itemIndex + 3]))
{
return true;
}
if (itemIndex + 4 < blockSize && item.Equals(blockArraySpan[itemIndex + 4]))
{
return true;
}
if (itemIndex + 5 < blockSize && item.Equals(blockArraySpan[itemIndex + 5]))
{
return true;
}
if (itemIndex + 6 < blockSize && item.Equals(blockArraySpan[itemIndex + 6]))
{
return true;
}
if (itemIndex + 7 < blockSize && item.Equals(blockArraySpan[itemIndex + 7]))
{
return true;
}
itemIndex += 8;
if (itemIndex >= blockSize)
{
blockIndex++;
blockArraySpan = new(memoryBlocksSpan[blockIndex]);
itemIndex = 0;
}
} }
blockArraySpan = new(memoryBlocksSpan[lastBlockIndex]); blockIndex++;
var nextItemIndex = _nextItemIndex;
while (itemIndex < nextItemIndex)
{
if (item.Equals(blockArraySpan[itemIndex]))
{
return true;
}
if (itemIndex + 1 < nextItemIndex && item.Equals(blockArraySpan[itemIndex + 1]))
{
return true;
}
if (itemIndex + 2 < nextItemIndex && item.Equals(blockArraySpan[itemIndex + 2]))
{
return true;
}
if (itemIndex + 3 < nextItemIndex && item.Equals(blockArraySpan[itemIndex + 3]))
{
return true;
}
if (itemIndex + 4 < nextItemIndex && item.Equals(blockArraySpan[itemIndex + 4]))
{
return true;
}
if (itemIndex + 5 < nextItemIndex && item.Equals(blockArraySpan[itemIndex + 5]))
{
return true;
}
if (itemIndex + 6 < nextItemIndex && item.Equals(blockArraySpan[itemIndex + 6]))
{
return true;
}
if (itemIndex + 7 < nextItemIndex && item.Equals(blockArraySpan[itemIndex + 7]))
{
return true;
}
itemIndex += 8;
}
}
else
{
while (blockIndex < lastBlockIndex)
{
if (blockArraySpan[itemIndex] == null)
{
return true;
}
if (itemIndex + 1 < blockSize && blockArraySpan[itemIndex + 1] == null)
{
return true;
}
if (itemIndex + 2 < blockSize && blockArraySpan[itemIndex + 2] == null)
{
return true;
}
if (itemIndex + 3 < blockSize && blockArraySpan[itemIndex + 3] == null)
{
return true;
}
if (itemIndex + 4 < blockSize && blockArraySpan[itemIndex + 4] == null)
{
return true;
}
if (itemIndex + 5 < blockSize && blockArraySpan[itemIndex + 5] == null)
{
return true;
}
if (itemIndex + 6 < blockSize && blockArraySpan[itemIndex + 6] == null)
{
return true;
}
if (itemIndex + 7 < blockSize && blockArraySpan[itemIndex + 7] == null)
{
return true;
}
itemIndex += 8;
if (itemIndex >= blockSize)
{
blockIndex++;
blockArraySpan = new(memoryBlocksSpan[blockIndex]);
itemIndex = 0;
}
}
blockArraySpan = new(memoryBlocksSpan[lastBlockIndex]);
var nextItemIndex = _nextItemIndex;
while (itemIndex < nextItemIndex)
{
if (blockArraySpan[itemIndex] == null)
{
return true;
}
if (itemIndex + 1 < nextItemIndex && blockArraySpan[itemIndex + 1] == null)
{
return true;
}
if (itemIndex + 2 < nextItemIndex && blockArraySpan[itemIndex + 2] == null)
{
return true;
}
if (itemIndex + 3 < nextItemIndex && blockArraySpan[itemIndex + 3] == null)
{
return true;
}
if (itemIndex + 4 < nextItemIndex && blockArraySpan[itemIndex + 4] == null)
{
return true;
}
if (itemIndex + 5 < nextItemIndex && blockArraySpan[itemIndex + 5] == null)
{
return true;
}
if (itemIndex + 6 < nextItemIndex && blockArraySpan[itemIndex + 6] == null)
{
return true;
}
if (itemIndex + 7 < nextItemIndex && blockArraySpan[itemIndex + 7] == null)
{
return true;
}
itemIndex += 8;
}
} }
return false; return Array.IndexOf(memoryBlocksSpan[blockIndex], item, 0, _nextItemIndex) >= 0;
} }
public void CopyTo(T[] array, int arrayIndex) => _memoryBlocks.CopyTo(0, _blockSize, _longCount, array, arrayIndex); public void CopyTo(T[] array, int arrayIndex) => _memoryBlocks.CopyTo(0, _blockSize, _longCount, array, arrayIndex);
public IEnumerator<T> GetEnumerator() => _memoryBlocks.Enumerate(_blockSize, LongCount).GetEnumerator(); public IEnumerator<T> GetEnumerator() => _memoryBlocks.Enumerate(_blockSize, LongCount).GetEnumerator();
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public int IndexOf(T item) public int IndexOf(T item)
{ {
if (_longCount == 0) if (_longCount == 0)
@@ -737,219 +543,52 @@ namespace Recyclable.Collections
return ItemNotFoundIndex; return ItemNotFoundIndex;
} }
int blockSize = _blockSize; int itemIndex, blockIndex = 0, lastBlockIndex = _lastBlockIndex, blockSize = _blockSize;
int itemIndex = 0;
int blockIndex = 0;
int lastBlockIndex = _lastBlockIndex;
Span<T[]> memoryBlocksSpan = new(_memoryBlocks); Span<T[]> memoryBlocksSpan = new(_memoryBlocks);
Span<T> blockArraySpan = new(memoryBlocksSpan[blockIndex]); while (blockIndex < lastBlockIndex)
if (item != null)
{ {
while (blockIndex < lastBlockIndex) itemIndex = Array.IndexOf(memoryBlocksSpan[blockIndex], item, 0, blockSize);
if (itemIndex >= 0)
{ {
if (item.Equals(blockArraySpan[itemIndex])) return (blockIndex * blockSize) + itemIndex;
{
return (blockIndex * blockSize) + itemIndex;
}
if (itemIndex + 1 < blockSize && item.Equals(blockArraySpan[itemIndex + 1]))
{
return (blockIndex * blockSize) + itemIndex + 1;
}
if (itemIndex + 2 < blockSize && item.Equals(blockArraySpan[itemIndex + 2]))
{
return (blockIndex * blockSize) + itemIndex + 2;
}
if (itemIndex + 3 < blockSize && item.Equals(blockArraySpan[itemIndex + 3]))
{
return (blockIndex * blockSize) + itemIndex + 3;
}
if (itemIndex + 4 < blockSize && item.Equals(blockArraySpan[itemIndex + 4]))
{
return (blockIndex * blockSize) + itemIndex + 4;
}
if (itemIndex + 5 < blockSize && item.Equals(blockArraySpan[itemIndex + 5]))
{
return (blockIndex * blockSize) + itemIndex + 5;
}
if (itemIndex + 6 < blockSize && item.Equals(blockArraySpan[itemIndex + 6]))
{
return (blockIndex * blockSize) + itemIndex + 6;
}
if (itemIndex + 7 < blockSize && item.Equals(blockArraySpan[itemIndex + 7]))
{
return (blockIndex * blockSize) + itemIndex + 7;
}
itemIndex += 8;
if (itemIndex >= blockSize)
{
blockIndex++;
blockArraySpan = new(memoryBlocksSpan[blockIndex]);
itemIndex = 0;
}
} }
blockArraySpan = new(memoryBlocksSpan[blockIndex]); blockIndex++;
var nextItemIndex = _nextItemIndex;
while (itemIndex < nextItemIndex)
{
if (item.Equals(blockArraySpan[itemIndex]))
{
return (blockIndex * blockSize) + itemIndex;
}
if (itemIndex + 1 < nextItemIndex && item.Equals(blockArraySpan[itemIndex + 1]))
{
return (blockIndex * blockSize) + itemIndex + 1;
}
if (itemIndex + 2 < nextItemIndex && item.Equals(blockArraySpan[itemIndex + 2]))
{
return (blockIndex * blockSize) + itemIndex + 2;
}
if (itemIndex + 3 < nextItemIndex && item.Equals(blockArraySpan[itemIndex + 3]))
{
return (blockIndex * blockSize) + itemIndex + 3;
}
if (itemIndex + 4 < nextItemIndex && item.Equals(blockArraySpan[itemIndex + 4]))
{
return (blockIndex * blockSize) + itemIndex + 4;
}
if (itemIndex + 5 < nextItemIndex && item.Equals(blockArraySpan[itemIndex + 5]))
{
return (blockIndex * blockSize) + itemIndex + 5;
}
if (itemIndex + 6 < nextItemIndex && item.Equals(blockArraySpan[itemIndex + 6]))
{
return (blockIndex * blockSize) + itemIndex + 6;
}
if (itemIndex + 7 < nextItemIndex && item.Equals(blockArraySpan[itemIndex + 7]))
{
return (blockIndex * blockSize) + itemIndex + 7;
}
itemIndex += 8;
}
}
else
{
while (blockIndex < lastBlockIndex)
{
if (blockArraySpan[itemIndex] == null)
{
return (blockIndex * blockSize) + itemIndex;
}
if (itemIndex + 1 < blockSize && blockArraySpan[itemIndex + 1] == null)
{
return (blockIndex * blockSize) + itemIndex + 1;
}
if (itemIndex + 2 < blockSize && blockArraySpan[itemIndex + 2] == null)
{
return (blockIndex * blockSize) + itemIndex + 2;
}
if (itemIndex + 3 < blockSize && blockArraySpan[itemIndex + 3] == null)
{
return (blockIndex * blockSize) + itemIndex + 3;
}
if (itemIndex + 4 < blockSize && blockArraySpan[itemIndex + 4] == null)
{
return (blockIndex * blockSize) + itemIndex + 4;
}
if (itemIndex + 5 < blockSize && blockArraySpan[itemIndex + 5] == null)
{
return (blockIndex * blockSize) + itemIndex + 5;
}
if (itemIndex + 6 < blockSize && blockArraySpan[itemIndex + 6] == null)
{
return (blockIndex * blockSize) + itemIndex + 6;
}
if (itemIndex + 7 < blockSize && blockArraySpan[itemIndex + 7] == null)
{
return (blockIndex * blockSize) + itemIndex + 7;
}
itemIndex += 8;
if (itemIndex >= blockSize)
{
blockIndex++;
blockArraySpan = new(memoryBlocksSpan[blockIndex]);
itemIndex = 0;
}
}
blockArraySpan = new(memoryBlocksSpan[lastBlockIndex]);
var nextItemIndex = _nextItemIndex;
while (itemIndex < nextItemIndex)
{
if (blockArraySpan[itemIndex] == null)
{
return (blockIndex * blockSize) + itemIndex;
}
if (itemIndex + 1 < nextItemIndex && blockArraySpan[itemIndex + 1] == null)
{
return (blockIndex * blockSize) + itemIndex + 1;
}
if (itemIndex + 2 < nextItemIndex && blockArraySpan[itemIndex + 2] == null)
{
return (blockIndex * blockSize) + itemIndex + 2;
}
if (itemIndex + 3 < nextItemIndex && blockArraySpan[itemIndex + 3] == null)
{
return (blockIndex * blockSize) + itemIndex + 3;
}
if (itemIndex + 4 < nextItemIndex && blockArraySpan[itemIndex + 4] == null)
{
return (blockIndex * blockSize) + itemIndex + 4;
}
if (itemIndex + 5 < nextItemIndex && blockArraySpan[itemIndex + 5] == null)
{
return (blockIndex * blockSize) + itemIndex + 5;
}
if (itemIndex + 6 < nextItemIndex && blockArraySpan[itemIndex + 6] == null)
{
return (blockIndex * blockSize) + itemIndex + 6;
}
if (itemIndex + 7 < nextItemIndex && blockArraySpan[itemIndex + 7] == null)
{
return (blockIndex * blockSize) + itemIndex + 7;
}
itemIndex += 8;
}
} }
return ItemNotFoundIndex; itemIndex = Array.IndexOf(memoryBlocksSpan[blockIndex], item, 0, _nextItemIndex);
return itemIndex >= 0
? (blockIndex * blockSize) + itemIndex
: ItemNotFoundIndex;
} }
public void Insert(int index, T item) => throw new NotSupportedException(); public void Insert(int index, T item) => throw new NotSupportedException();
public long LongIndexOf(T item) => _memoryBlocks.LongIndexOf(_blockSize, item, _equalityComparer); public long LongIndexOf(T item)
{
if (_longCount == 0)
{
return ItemNotFoundIndex;
}
int itemIndex, blockIndex = 0, lastBlockIndex = _lastBlockIndex, blockSize = _blockSize;
Span<T[]> memoryBlocksSpan = new(_memoryBlocks);
while (blockIndex < lastBlockIndex)
{
itemIndex = Array.IndexOf(memoryBlocksSpan[blockIndex], item, 0, blockSize);
if (itemIndex >= 0)
{
return ((long)blockIndex * blockSize) + itemIndex;
}
blockIndex++;
}
itemIndex = Array.IndexOf(memoryBlocksSpan[blockIndex], item, 0, _nextItemIndex);
return itemIndex >= 0
? ((long)blockIndex * blockSize) + itemIndex
: ItemNotFoundIndex;
}
public bool Remove(T item) => throw new NotSupportedException(); public bool Remove(T item) => throw new NotSupportedException();
public void RemoveBlock(int index) public void RemoveBlock(int index)
{ {