Additional RecyclableList.IndexOf() & RecyclableLongList.IndexOf() variants moved from Recyclable.Collections.Compatibility.List package. Tests extended.
This commit is contained in:
1 parent
15a282de9f
commit
90ae27ce5d
7 files changed
+576
-8
No files matched your search
@@ -31,5 +31,14 @@ namespace Recyclable.Collections
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
public static long Min(long number1, long number2, long number3) =>
|
||||
number1 <= number2
|
||||
? number1 <= number3
|
||||
? number1
|
||||
: number3
|
||||
: number2 <= number3
|
||||
? number2
|
||||
: number3;
|
||||
}
|
||||
}
|
||||
@@ -244,6 +244,16 @@ namespace Recyclable.Collections
|
||||
? Array.IndexOf(_memoryBlock, itemToFind, 0, _count)
|
||||
: RecyclableDefaults.ItemNotFoundIndex;
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public int IndexOf(T item, int index) => _count != 0
|
||||
? Array.IndexOf(_memoryBlock, item, index, _count - index)
|
||||
: RecyclableDefaults.ItemNotFoundIndex;
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public int IndexOf(T item, int index, int count) => _count != 0
|
||||
? Array.IndexOf(_memoryBlock, item, index, count)
|
||||
: RecyclableDefaults.ItemNotFoundIndex;
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)]
|
||||
public void Insert(int index, T item)
|
||||
{
|
||||
|
||||
@@ -193,7 +193,7 @@ namespace Recyclable.Collections
|
||||
#endif
|
||||
|
||||
[MethodImpl(MethodImplOptions.NoInlining | MethodImplOptions.AggressiveOptimization)]
|
||||
public static long IndexOfParallel(RecyclableLongList<T> list, T item)
|
||||
public static long IndexOfParallel(RecyclableLongList<T> list, T item)
|
||||
{
|
||||
// & WAS SLOWER
|
||||
//long itemsCount = Array.IndexOf(list._memoryBlocks[0], item, 0, (int)Math.Min(list._blockSize, list._longCount));
|
||||
@@ -294,6 +294,183 @@ namespace Recyclable.Collections
|
||||
return RecyclableDefaults.ItemNotFoundIndexLong;
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.NoInlining | MethodImplOptions.AggressiveOptimization)]
|
||||
public static long IndexOfParallel(RecyclableLongList<T> list, T item, int firstBlockIndex)
|
||||
{
|
||||
IndexOfSynchronizationContext context = IndexOfSynchronizationContextPool.GetWithOneParticipant();
|
||||
|
||||
int blockIndex = firstBlockIndex,
|
||||
lastBlockWithData = list._lastBlockWithData,
|
||||
lastFullBlockWithData = lastBlockWithData - BlocksForEachTask;
|
||||
|
||||
while (blockIndex < lastFullBlockWithData)
|
||||
{
|
||||
// At this point itemIndex is limited to blockSize range - int.
|
||||
|
||||
// & WAS SLOWER
|
||||
// _ = ThreadPool.QueueUserWorkItem<object?>((_) =>
|
||||
// Task.Factory.StartNew(() =>
|
||||
context.AddParticipant();
|
||||
var startingBlock = blockIndex;
|
||||
_ = Task.Run(() => IndexOfInConsecutiveBlocks(context, list, startingBlock, item));
|
||||
|
||||
// & WAS SLOWER
|
||||
// ScheduleIndexOfTask(context, list, blockIndex, item);
|
||||
if (context._isItemFound)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
blockIndex += BlocksForEachTask;
|
||||
}
|
||||
|
||||
if (!context._isItemFound)
|
||||
{
|
||||
while (blockIndex < lastBlockWithData)
|
||||
{
|
||||
// & WAS SLOWER
|
||||
// _ = ThreadPool.QueueUserWorkItem<object?>((_) =>
|
||||
// Task.Factory.StartNew(() =>
|
||||
var startingBlock = blockIndex;
|
||||
context.AddParticipant();
|
||||
_ = Task.Run(() => IndexOfIn1Block(context, list, startingBlock, item));
|
||||
|
||||
// & WAS SLOWER
|
||||
// ScheduleIndexOfTaskSingle(context, list, blockIndex, item);
|
||||
if (context._isItemFound)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
blockIndex++;
|
||||
}
|
||||
}
|
||||
|
||||
if (!context._isItemFound)
|
||||
{
|
||||
int itemIndex = list._nextItemIndex != 0
|
||||
? Array.IndexOf(list._memoryBlocks[lastBlockWithData], item, 0, list._nextItemIndex)
|
||||
: Array.IndexOf(list._memoryBlocks[lastBlockWithData], item, 0, list._blockSize);
|
||||
|
||||
if (!context._isItemFound && itemIndex >= 0)
|
||||
{
|
||||
ExchangeFoundItemIndexIfLower(context, lastBlockWithData, ((long)lastBlockWithData << list._blockSizePow2BitShift) + itemIndex);
|
||||
}
|
||||
}
|
||||
|
||||
context.SignalAndWait();
|
||||
if (context.Exception == null)
|
||||
{
|
||||
try
|
||||
{
|
||||
return context.FoundItemIndex;
|
||||
}
|
||||
finally
|
||||
{
|
||||
context.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
context.Exception.CaptureAndReThrow();
|
||||
}
|
||||
finally
|
||||
{
|
||||
context.Dispose();
|
||||
}
|
||||
|
||||
return RecyclableDefaults.ItemNotFoundIndexLong;
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.NoInlining | MethodImplOptions.AggressiveOptimization)]
|
||||
public static long IndexOfParallel(RecyclableLongList<T> list, T item, int firstBlockIndex, long count)
|
||||
{
|
||||
IndexOfSynchronizationContext context = IndexOfSynchronizationContextPool.GetWithOneParticipant();
|
||||
|
||||
int blockIndex = firstBlockIndex,
|
||||
lastBlockWithData = (int)Math.Min((count >> list._blockSizePow2BitShift) + firstBlockIndex + ((count & list._blockSizeMinus1) > 0 ? 1 : 0) - 1, list._lastBlockWithData),
|
||||
lastFullBlockWithData = lastBlockWithData - BlocksForEachTask;
|
||||
|
||||
while (blockIndex < lastFullBlockWithData)
|
||||
{
|
||||
// At this point itemIndex is limited to blockSize range - int.
|
||||
|
||||
// & WAS SLOWER
|
||||
// _ = ThreadPool.QueueUserWorkItem<object?>((_) =>
|
||||
// Task.Factory.StartNew(() =>
|
||||
context.AddParticipant();
|
||||
var startingBlock = blockIndex;
|
||||
_ = Task.Run(() => IndexOfInConsecutiveBlocks(context, list, startingBlock, item));
|
||||
|
||||
// & WAS SLOWER
|
||||
// ScheduleIndexOfTask(context, list, blockIndex, item);
|
||||
if (context._isItemFound)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
blockIndex += BlocksForEachTask;
|
||||
}
|
||||
|
||||
if (!context._isItemFound)
|
||||
{
|
||||
count -= (blockIndex - firstBlockIndex) << list._blockSizePow2BitShift;
|
||||
while (blockIndex < lastBlockWithData)
|
||||
{
|
||||
// & WAS SLOWER
|
||||
// _ = ThreadPool.QueueUserWorkItem<object?>((_) =>
|
||||
// Task.Factory.StartNew(() =>
|
||||
var startingBlock = blockIndex;
|
||||
context.AddParticipant();
|
||||
_ = Task.Run(() => IndexOfIn1Block(context, list, startingBlock, item));
|
||||
|
||||
// & WAS SLOWER
|
||||
// ScheduleIndexOfTaskSingle(context, list, blockIndex, item);
|
||||
if (context._isItemFound)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
blockIndex++;
|
||||
count -= list._blockSize;
|
||||
}
|
||||
}
|
||||
|
||||
if (!context._isItemFound && count > 0)
|
||||
{
|
||||
int itemIndex = Array.IndexOf(list._memoryBlocks[lastBlockWithData], item, 0, (int)count);
|
||||
if (!context._isItemFound && itemIndex >= 0)
|
||||
{
|
||||
ExchangeFoundItemIndexIfLower(context, lastBlockWithData, ((long)lastBlockWithData << list._blockSizePow2BitShift) + itemIndex);
|
||||
}
|
||||
}
|
||||
|
||||
context.SignalAndWait();
|
||||
if (context.Exception == null)
|
||||
{
|
||||
try
|
||||
{
|
||||
return context.FoundItemIndex;
|
||||
}
|
||||
finally
|
||||
{
|
||||
context.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
context.Exception.CaptureAndReThrow();
|
||||
}
|
||||
finally
|
||||
{
|
||||
context.Dispose();
|
||||
}
|
||||
|
||||
return RecyclableDefaults.ItemNotFoundIndexLong;
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.NoInlining | MethodImplOptions.AggressiveOptimization)]
|
||||
public static long IndexOfSequential(RecyclableLongList<T> list, in T item) //, in T[][] memoryBlocks, int lastBlockIndex, int blockSize, int nextItemIndex)
|
||||
{
|
||||
@@ -344,6 +521,119 @@ namespace Recyclable.Collections
|
||||
|
||||
return itemIndex >= 0 ? itemIndex + ((long)list._lastBlockWithData << list._blockSizePow2BitShift) : RecyclableDefaults.ItemNotFoundIndexLong;
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.NoInlining | MethodImplOptions.AggressiveOptimization)]
|
||||
public static long IndexOfSequential(RecyclableLongList<T> list, in T item, int firstBlockIndex, long count)
|
||||
{
|
||||
int blockIndex,
|
||||
blockSize = list._blockSize,
|
||||
itemIndex,
|
||||
lastBlockWithData = (int)Math.Min((count >> list._blockSizePow2BitShift) + firstBlockIndex + ((count & list._blockSizeMinus1) > 0 ? 1 : 0) - 1, list._lastBlockWithData);
|
||||
|
||||
byte blockSizePow2BitShift = list._blockSizePow2BitShift;
|
||||
|
||||
ReadOnlySpan<T[]> memoryBlocksSpan = new(list._memoryBlocks, 0, lastBlockWithData + 1);
|
||||
for (blockIndex = firstBlockIndex; blockIndex < lastBlockWithData && count > blockSize; blockIndex += 4)
|
||||
{
|
||||
|
||||
itemIndex = Array.IndexOf(memoryBlocksSpan[blockIndex], item, 0, blockSize);
|
||||
if (itemIndex >= 0)
|
||||
{
|
||||
return itemIndex + ((long)blockIndex << blockSizePow2BitShift);
|
||||
}
|
||||
|
||||
count -= blockSize;
|
||||
if (blockIndex + 1 < lastBlockWithData && count > blockSize)
|
||||
{
|
||||
itemIndex = Array.IndexOf(memoryBlocksSpan[blockIndex + 1], item, 0, blockSize);
|
||||
if (itemIndex >= 0)
|
||||
{
|
||||
return itemIndex + ((long)(blockIndex + 1) << blockSizePow2BitShift);
|
||||
}
|
||||
|
||||
count -= blockSize;
|
||||
if (blockIndex + 2 < lastBlockWithData && count > blockSize)
|
||||
{
|
||||
itemIndex = Array.IndexOf(memoryBlocksSpan[blockIndex + 2], item, 0, blockSize);
|
||||
if (itemIndex >= 0)
|
||||
{
|
||||
return itemIndex + ((long)(blockIndex + 2) << blockSizePow2BitShift);
|
||||
}
|
||||
|
||||
count -= blockSize;
|
||||
if (blockIndex + 3 < lastBlockWithData && count > blockSize)
|
||||
{
|
||||
itemIndex = Array.IndexOf(memoryBlocksSpan[blockIndex + 3], item, 0, blockSize);
|
||||
if (itemIndex >= 0)
|
||||
{
|
||||
return itemIndex + ((long)(blockIndex + 3) << blockSizePow2BitShift);
|
||||
}
|
||||
|
||||
count -= blockSize;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
itemIndex = Array.IndexOf(memoryBlocksSpan[lastBlockWithData], item, 0, (int)count);
|
||||
|
||||
return itemIndex >= 0 ? itemIndex + ((long)lastBlockWithData << blockSizePow2BitShift) : RecyclableDefaults.ItemNotFoundIndexLong;
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.NoInlining | MethodImplOptions.AggressiveOptimization)]
|
||||
public static long IndexOfSequential(RecyclableLongList<T> list, in T item, int firstBlockIndex)
|
||||
{
|
||||
int blockIndex,
|
||||
blockSize = list._blockSize,
|
||||
itemIndex,
|
||||
lastBlockWithData = list._lastBlockWithData;
|
||||
|
||||
byte blockSizePow2BitShift = list._blockSizePow2BitShift;
|
||||
|
||||
ReadOnlySpan<T[]> memoryBlocksSpan = new(list._memoryBlocks, 0, lastBlockWithData + 1);
|
||||
for (blockIndex = firstBlockIndex; blockIndex < lastBlockWithData; blockIndex += 4)
|
||||
{
|
||||
|
||||
itemIndex = Array.IndexOf(memoryBlocksSpan[blockIndex], item, 0, blockSize);
|
||||
if (itemIndex >= 0)
|
||||
{
|
||||
return itemIndex + ((long)blockIndex << blockSizePow2BitShift);
|
||||
}
|
||||
|
||||
if (blockIndex + 1 < lastBlockWithData)
|
||||
{
|
||||
itemIndex = Array.IndexOf(memoryBlocksSpan[blockIndex + 1], item, 0, blockSize);
|
||||
if (itemIndex >= 0)
|
||||
{
|
||||
return itemIndex + ((long)(blockIndex + 1) << blockSizePow2BitShift);
|
||||
}
|
||||
|
||||
if (blockIndex + 2 < lastBlockWithData)
|
||||
{
|
||||
itemIndex = Array.IndexOf(memoryBlocksSpan[blockIndex + 2], item, 0, blockSize);
|
||||
if (itemIndex >= 0)
|
||||
{
|
||||
return itemIndex + ((long)(blockIndex + 2) << blockSizePow2BitShift);
|
||||
}
|
||||
|
||||
if (blockIndex + 3 < lastBlockWithData)
|
||||
{
|
||||
itemIndex = Array.IndexOf(memoryBlocksSpan[blockIndex + 3], item, 0, blockSize);
|
||||
if (itemIndex >= 0)
|
||||
{
|
||||
return itemIndex + ((long)(blockIndex + 3) << blockSizePow2BitShift);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
itemIndex = list._nextItemIndex != 0
|
||||
? Array.IndexOf(memoryBlocksSpan[lastBlockWithData], item, 0, list._nextItemIndex)
|
||||
: Array.IndexOf(memoryBlocksSpan[lastBlockWithData], item, 0, list._blockSize);
|
||||
|
||||
return itemIndex >= 0 ? itemIndex + ((long)lastBlockWithData << blockSizePow2BitShift) : RecyclableDefaults.ItemNotFoundIndexLong;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -374,7 +374,7 @@ namespace Recyclable.Collections
|
||||
return RecyclableDefaults.ItemNotFoundIndex;
|
||||
}
|
||||
|
||||
int itemIndex = Array.IndexOf(_memoryBlocks[0], item, 0, _longCount < _blockSize ? _nextItemIndex : _blockSize);
|
||||
int itemIndex = Array.IndexOf(_memoryBlocks[0], item, 0, _blockSize);
|
||||
if (itemIndex >= 0)
|
||||
{
|
||||
return itemIndex;
|
||||
@@ -397,6 +397,81 @@ namespace Recyclable.Collections
|
||||
}
|
||||
}
|
||||
|
||||
public int IndexOf(T item, int index)
|
||||
{
|
||||
if (_lastBlockWithData == 0)
|
||||
{
|
||||
return Array.IndexOf(_memoryBlocks[0], item, index, _longCount < _blockSize ? _nextItemIndex : _blockSize);
|
||||
}
|
||||
else if (_longCount == 0)
|
||||
{
|
||||
return RecyclableDefaults.ItemNotFoundIndex;
|
||||
}
|
||||
|
||||
int firstBlockIndex = index >> _blockSizePow2BitShift;
|
||||
int firstItemIndex = index & _blockSizeMinus1;
|
||||
int itemIndex = Array.IndexOf(_memoryBlocks[firstBlockIndex], item, firstItemIndex, (firstBlockIndex == _lastBlockWithData ? _nextItemIndex : _blockSize) - firstItemIndex);
|
||||
if (itemIndex >= 0)
|
||||
{
|
||||
return (firstBlockIndex << _blockSizePow2BitShift) + itemIndex;
|
||||
}
|
||||
else if (_longCount < RecyclableDefaults.MinItemsCountForParallelization)
|
||||
{
|
||||
return (int)RecyclableLongList<T>.IndexOfHelpers.IndexOfSequential(this, item, firstBlockIndex + 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (firstBlockIndex + 1 <= _lastBlockWithData)
|
||||
{
|
||||
itemIndex = Array.IndexOf(_memoryBlocks[firstBlockIndex + 1], item, 0, (int)Math.Min(firstBlockIndex + 1 == _lastBlockWithData ? _nextItemIndex : _blockSize, _longCount - _blockSize));
|
||||
return itemIndex >= 0 ? ((firstBlockIndex + 1) << _blockSizePow2BitShift) + itemIndex : checked((int)RecyclableLongList<T>.IndexOfHelpers.IndexOfParallel(this, item, firstBlockIndex + 2));
|
||||
}
|
||||
else
|
||||
{
|
||||
return RecyclableDefaults.ItemNotFoundIndex;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public int IndexOf(T item, int index, int count)
|
||||
{
|
||||
if (_lastBlockWithData == 0)
|
||||
{
|
||||
return Array.IndexOf(_memoryBlocks[0], item, index, count);
|
||||
}
|
||||
else if (_longCount == 0 || count == 0)
|
||||
{
|
||||
return RecyclableDefaults.ItemNotFoundIndex;
|
||||
}
|
||||
|
||||
int blockSize = _blockSize,
|
||||
firstBlockIndex = index >> _blockSizePow2BitShift,
|
||||
firstItemIndex = index & _blockSizeMinus1;
|
||||
|
||||
int firstBlockItemsCount = Math.Min(blockSize - firstItemIndex, count);
|
||||
int itemIndex = Array.IndexOf(_memoryBlocks[firstBlockIndex], item, firstItemIndex, firstBlockItemsCount);
|
||||
if (itemIndex >= 0)
|
||||
{
|
||||
return (firstBlockIndex << _blockSizePow2BitShift) + itemIndex;
|
||||
}
|
||||
else if (_longCount < RecyclableDefaults.MinItemsCountForParallelization)
|
||||
{
|
||||
return (int)RecyclableLongList<T>.IndexOfHelpers.IndexOfSequential(this, item, firstBlockIndex + 1, count - firstBlockItemsCount);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (_longCount > blockSize)
|
||||
{
|
||||
itemIndex = Array.IndexOf(_memoryBlocks[firstBlockIndex + 1], item, 0, (int)MathUtils.Min(blockSize, _longCount - blockSize, count - firstBlockItemsCount));
|
||||
return itemIndex >= 0 ? ((firstBlockIndex + 1) << _blockSizePow2BitShift) + itemIndex : checked((int)RecyclableLongList<T>.IndexOfHelpers.IndexOfParallel(this, item, firstBlockIndex + 2, count - firstBlockItemsCount - blockSize));
|
||||
}
|
||||
else
|
||||
{
|
||||
return RecyclableDefaults.ItemNotFoundIndex;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void Insert(int index, T item)
|
||||
{
|
||||
if (index > _longCount || index < 0)
|
||||
|
||||
@@ -1,14 +1,24 @@
|
||||
namespace Recyclable.Collections
|
||||
#pragma warning disable IDE0022, CA2208
|
||||
|
||||
namespace Recyclable.Collections
|
||||
{
|
||||
internal static class ThrowHelper
|
||||
{
|
||||
/// <summary>
|
||||
/// This is a helper method to throw <see cref="ArgumentOutOfRangeException"/> with the given message.
|
||||
/// </summary>
|
||||
/// <exception cref="ArgumentOutOfRangeException">Always</exception>
|
||||
public static void ThrowArgumentException(string argumentName) => throw new ArgumentException("Parameter has invalid value. ", argumentName);
|
||||
public static void ThrowArgumentException(string argumentName, Exception? innerException) => throw new ArgumentException("Parameter has invalid value. ", argumentName, innerException);
|
||||
public static void ThrowArgumentException(string argumentName, string message) => throw new ArgumentException(message, argumentName);
|
||||
public static void ThrowArgumentException(string argumentName, string message, Exception? innerException) => throw new ArgumentException(message, argumentName, innerException);
|
||||
public static void ThrowArgumentException_Index() => throw new ArgumentException("Parameter has invalid value", "index");
|
||||
public static void ThrowArgumentException_Index(Exception? innerException) => throw new ArgumentException("Parameter has invalid value", "index", innerException);
|
||||
public static void ThrowArgumentException_Count() => throw new ArgumentException("Parameter has invalid value", "count");
|
||||
public static void ThrowArgumentException_Count(Exception? innerException) => throw new ArgumentException("Parameter has invalid value", "count", innerException);
|
||||
public static void ThrowArgumentOutOfRangeException(string argumentName) => throw new ArgumentOutOfRangeException(argumentName);
|
||||
public static void ThrowArgumentOutOfRangeException(string argumentName, Exception? innerException) => throw new ArgumentOutOfRangeException($"Argument {argumentName} is out of range", innerException);
|
||||
public static void ThrowArgumentOutOfRangeException(string argumentName, string message) => throw new ArgumentOutOfRangeException(argumentName, message);
|
||||
public static void ThrowWrongReturnedArraySizeException(int returnedLength, int blockSize) => throw new InvalidOperationException($"The array size {returnedLength} doesn't match the size {blockSize} of the pool buffer and cannot be returned to this pool.");
|
||||
public static void ThrowArgumentOutOfRangeException_Index() => throw new ArgumentOutOfRangeException("index", "Parameter `index` has invalid value. It must be within the no. of elements in the collection");
|
||||
public static void ThrowArgumentOutOfRangeException_Count() => throw new ArgumentOutOfRangeException("index", "Parameter `count` has invalid value. Combined with index, it must be within the no. of elements in the collection");
|
||||
public static void ThrowArgumentOutOfRangeException_Index(Exception? innerException) => throw new ArgumentOutOfRangeException("Parameter `index` has invalid value. It must be within the no. of elements in the collection", innerException);
|
||||
public static void ThrowArgumentOutOfRangeException_Count() => throw new ArgumentOutOfRangeException("count", "Parameter `count` has invalid value. Combined with index, it must be within the no. of elements in the collection");
|
||||
public static void ThrowArgumentOutOfRangeException_Count(Exception? innerException) => throw new ArgumentOutOfRangeException("Parameter `count` has invalid value. Combined with index, it must be within the no. of elements in the collection", innerException);
|
||||
}
|
||||
}
|
||||
@@ -671,6 +671,46 @@ namespace Recyclable.CollectionsTests
|
||||
}
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[MemberData(nameof(RecyclableLongListTestData.SourceDataWithItemIndexVariants), MemberType = typeof(RecyclableLongListTestData))]
|
||||
public void IndexOfShouldReturnCorrectIndexesWhenConstrainedCount(string testCase, IEnumerable<long> testData, int itemsCount, in long[] itemIndexes)
|
||||
{
|
||||
// Prepare
|
||||
using var list = new RecyclableList<long>(testData, itemsCount);
|
||||
var expectedData = testData.ToList();
|
||||
|
||||
foreach (var itemIndex in itemIndexes)
|
||||
{
|
||||
var expected = expectedData.IndexOf(expectedData[(int)itemIndex], (int)itemIndex, (int)(itemsCount - itemIndex));
|
||||
|
||||
// Act
|
||||
var actual = list.IndexOf(expectedData[(int)itemIndex], (int)itemIndex, (int)(itemsCount - itemIndex));
|
||||
|
||||
// Validate
|
||||
_ = actual.Should().Be((int)itemIndex).And.Be(expected);
|
||||
}
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[MemberData(nameof(RecyclableLongListTestData.SourceDataWithItemIndexVariants), MemberType = typeof(RecyclableLongListTestData))]
|
||||
public void IndexOfShouldReturnCorrectIndexesWhenConstrainedIndex(string testCase, IEnumerable<long> testData, int itemsCount, in long[] itemIndexes)
|
||||
{
|
||||
// Prepare
|
||||
using var list = new RecyclableList<long>(testData, itemsCount);
|
||||
var expectedData = testData.ToList();
|
||||
|
||||
foreach (var itemIndex in itemIndexes)
|
||||
{
|
||||
var expected = expectedData.IndexOf(expectedData[(int)itemIndex], (int)itemIndex);
|
||||
|
||||
// Act
|
||||
var actual = list.IndexOf(expectedData[(int)itemIndex], (int)itemIndex);
|
||||
|
||||
// Validate
|
||||
_ = actual.Should().Be((int)itemIndex).And.Be(expected);
|
||||
}
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[MemberData(nameof(RecyclableLongListTestData.SourceDataWithItemIndexVariants), MemberType = typeof(RecyclableLongListTestData))]
|
||||
public void InitializeSortClearAddRangeRemoveShouldSucceed(string testCase, IEnumerable<long> testData, int itemsCount, in long[] itemIndexes)
|
||||
|
||||
@@ -648,6 +648,91 @@ namespace Recyclable.CollectionsTests
|
||||
}
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[MemberData(nameof(RecyclableLongListTestData.SourceDataWithBlockSizeWithItemIndexVariants), MemberType = typeof(RecyclableLongListTestData))]
|
||||
public void IndexOfParallelShouldReturnCorrectIndexes(string testCase, IEnumerable<long> unusedTestData, long itemsCount, int targetBlockSize, in long[] itemIndexes)
|
||||
{
|
||||
const long ItemsCount = RecyclableDefaults.MinItemsCountForParallelization * 3;
|
||||
|
||||
var testData = RecyclableLongListTestData.CreateTestData(ItemsCount).ToArray();
|
||||
// Prepare
|
||||
using var list = new RecyclableLongList<long>(testData, minBlockSize: targetBlockSize, initialCapacity: ItemsCount);
|
||||
|
||||
// Act & Validate
|
||||
foreach (long itemIndex in itemIndexes)
|
||||
{
|
||||
var actual = list.IndexOf(testData[itemIndex]);
|
||||
_ = actual.Should().Be((int)itemIndex);
|
||||
}
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[MemberData(nameof(RecyclableLongListTestData.SourceDataWithBlockSizeWithItemIndexWithRangeVariants), MemberType = typeof(RecyclableLongListTestData))]
|
||||
public void IndexOfParallelShouldReturnCorrectIndexesWhenConstrainedCount(string testCase, IEnumerable<long> unusedTestData, int itemsCount, int minBlockSize, in (long ItemIndex, long RangedItemsCount)[] itemRanges)
|
||||
{
|
||||
const long ItemsCount = RecyclableDefaults.MinItemsCountForParallelization * 3;
|
||||
|
||||
var testData = RecyclableLongListTestData.CreateTestData(ItemsCount).ToArray();
|
||||
// Prepare
|
||||
using var list = new RecyclableLongList<long>(testData, minBlockSize: minBlockSize, initialCapacity: ItemsCount);
|
||||
|
||||
// Act & Validate
|
||||
foreach (var (itemIndex, rangedItemsCount) in itemRanges)
|
||||
{
|
||||
TestWith(list, (int)itemIndex, (int)rangedItemsCount);
|
||||
TestWith(list, (int)(itemIndex - 1), 3);
|
||||
TestWith(list, (int)(itemIndex - 1), (int)(itemIndex + 1));
|
||||
TestWith(list, (int)Math.Max(0, itemIndex - RecyclableDefaults.MinItemsCountForParallelization), (int)Math.Min(ItemsCount - itemIndex + RecyclableDefaults.MinItemsCountForParallelization, itemIndex + RecyclableDefaults.MinItemsCountForParallelization));
|
||||
}
|
||||
|
||||
static void TestWith(RecyclableLongList<long> list, int index, int count)
|
||||
{
|
||||
index = Math.Max(0, index);
|
||||
count = Math.Min(count, list.Count - index);
|
||||
_ = list.IndexOf(list[index], index, count).Should().Be(count > 0 ? index : -1);
|
||||
_ = list.IndexOf(list[index], Math.Max(0, index - 1), 3).Should().Be(index);
|
||||
_ = list.IndexOf(list[Math.Max(0, index + count - 1)], index, count).Should().Be(count > 0 ? Math.Max(0, index + count - 1) : -1);
|
||||
_ = list.IndexOf(0, index, count).Should().Be(-1);
|
||||
|
||||
if (index > 0)
|
||||
{
|
||||
_ = list.IndexOf(list[index - 1], index, count).Should().Be(-1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[MemberData(nameof(RecyclableLongListTestData.SourceDataWithBlockSizeWithItemIndexVariants), MemberType = typeof(RecyclableLongListTestData))]
|
||||
public void IndexOfParallelShouldReturnCorrectIndexesWhenConstrainedIndex(string testCase, IEnumerable<long> unusedTestData, long itemsCount, int targetBlockSize, in long[] itemIndexes)
|
||||
{
|
||||
const long ItemsCount = RecyclableDefaults.MinItemsCountForParallelization * 3;
|
||||
|
||||
var testData = RecyclableLongListTestData.CreateTestData(ItemsCount).ToArray();
|
||||
// Prepare
|
||||
using var list = new RecyclableLongList<long>(testData, minBlockSize: targetBlockSize, initialCapacity: ItemsCount);
|
||||
|
||||
// Act & Validate
|
||||
foreach(var itemIndex in itemIndexes)
|
||||
{
|
||||
TestWith(list, (int)Math.Max(itemIndex - 1, 0));
|
||||
TestWith(list, (int)Math.Max(0, itemIndex - RecyclableDefaults.MinItemsCountForParallelization));
|
||||
}
|
||||
|
||||
static void TestWith(RecyclableLongList<long> list, int index)
|
||||
{
|
||||
var count = list.Count - 1;
|
||||
_ = list.IndexOf(list[index], index).Should().Be(index);
|
||||
_ = list.IndexOf(list[count], index).Should().Be(count);
|
||||
_ = list.IndexOf(-1, index).Should().Be(-1);
|
||||
_ = list.IndexOf(0, index).Should().Be(-1);
|
||||
|
||||
if (index > 0)
|
||||
{
|
||||
_ = list.IndexOf(list[index - 1], index).Should().Be(-1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void IndexOfShouldNotFindAnythingWhenListEmpty()
|
||||
{
|
||||
@@ -688,6 +773,55 @@ namespace Recyclable.CollectionsTests
|
||||
}
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[MemberData(nameof(RecyclableLongListTestData.SourceDataWithBlockSizeWithItemIndexWithRangeVariants), MemberType = typeof(RecyclableLongListTestData))]
|
||||
public void IndexOfShouldReturnCorrectIndexesWhenConstrainedCount(string testCase, IEnumerable<long> testData, int itemsCount, int minBlockSize, in (long ItemIndex, long RangedItemsCount)[] itemRanges)
|
||||
{
|
||||
// Prepare
|
||||
using var list = new RecyclableLongList<long>(testData, minBlockSize: minBlockSize, itemsCount);
|
||||
var expectedData = testData.ToList();
|
||||
|
||||
// Act & Validate
|
||||
foreach (var (itemIndex, rangedItemsCount) in itemRanges)
|
||||
{
|
||||
TestWith(list, expectedData, itemIndex, rangedItemsCount, expectedData[(int)itemIndex]);
|
||||
TestWith(list, expectedData, itemIndex, (int)(itemsCount - itemIndex), expectedData[(int)itemIndex]);
|
||||
TestWith(list, expectedData, itemIndex, rangedItemsCount, expectedData[(int)Math.Max(0, itemIndex + rangedItemsCount - 1)]);
|
||||
}
|
||||
|
||||
static void TestWith(RecyclableLongList<long> list, List<long> expectedData, long itemIndex, long rangedItemsCount, long item)
|
||||
{
|
||||
var expected = expectedData.IndexOf(item, (int)itemIndex, (int)rangedItemsCount);
|
||||
var actual = list.IndexOf(item, (int)itemIndex, (int)rangedItemsCount);
|
||||
|
||||
_ = actual.Should().Be(expected);
|
||||
}
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[MemberData(nameof(RecyclableLongListTestData.SourceDataWithItemIndexVariants), MemberType = typeof(RecyclableLongListTestData))]
|
||||
public void IndexOfShouldReturnCorrectIndexesWhenConstrainedIndex(string testCase, IEnumerable<long> testData, int itemsCount, in long[] itemIndexes)
|
||||
{
|
||||
// Prepare
|
||||
using var list = new RecyclableLongList<long>(testData, initialCapacity: itemsCount);
|
||||
var expectedData = testData.ToList();
|
||||
|
||||
foreach (var itemIndex in itemIndexes)
|
||||
{
|
||||
TestWith(list, expectedData[(int)itemIndex], itemIndex);
|
||||
TestWith(list, expectedData[itemsCount - 1], itemIndex);
|
||||
}
|
||||
|
||||
void TestWith(RecyclableLongList<long> list, long item, long itemIndex)
|
||||
{
|
||||
var expected = expectedData.IndexOf(item, (int)itemIndex);
|
||||
// Act
|
||||
var actual = list.IndexOf(item, (int)itemIndex);
|
||||
// Validate
|
||||
_ = actual.Should().Be(expected);
|
||||
}
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[MemberData(nameof(RecyclableLongListTestData.SourceDataWithBlockSizeWithItemIndexVariants), MemberType = typeof(RecyclableLongListTestData))]
|
||||
public void InitializeSortClearAddRangeRemoveShouldSucceed(string testCase, IEnumerable<long> testData, long itemsCount, int targetBlockSize, in long[] itemIndexes)
|
||||
|
||||
Reference in new issue
Block a user