diff --git a/Recyclable.Collections.Compatibility.List/RecyclableLongList.Compatibility.List.Find.cs b/Recyclable.Collections.Compatibility.List/RecyclableLongList.Compatibility.List.Find.cs index 938b16a..dac6187 100644 --- a/Recyclable.Collections.Compatibility.List/RecyclableLongList.Compatibility.List.Find.cs +++ b/Recyclable.Collections.Compatibility.List/RecyclableLongList.Compatibility.List.Find.cs @@ -63,24 +63,58 @@ namespace Recyclable.Collections public static T? Find(this RecyclableLongList list, Predicate match) { - //int sourceItemsCount = list._count; - //if (sourceItemsCount == 0) - //{ - // return default; - //} + if (list._longCount == 0) + { + return default; + } - //ReadOnlySpan sourceSpan = list._memoryBlock; - //for (var itemIndex = 0; itemIndex < sourceItemsCount; itemIndex++) - //{ - // if (match(sourceSpan[itemIndex])) - // { - // return sourceSpan[itemIndex]; - // } - //} + int blockIndex = 0, + blockSize = list._blockSize, + itemIndex = 0, + lastBlockWithData = list._lastBlockWithData; - //return default; + ReadOnlySpan sourceMemoryBlocksSpan = list._memoryBlocks; + ReadOnlySpan sourceMemoryBlockSpan = sourceMemoryBlocksSpan[0]; + while (blockIndex < lastBlockWithData) + { + if (match(sourceMemoryBlockSpan[itemIndex])) + { + return sourceMemoryBlockSpan[itemIndex]; + } - throw new NotImplementedException(); + if (itemIndex + 1 == blockSize) + { + itemIndex = 0; + blockIndex++; + sourceMemoryBlockSpan = sourceMemoryBlocksSpan[blockIndex]; + + if (blockIndex == lastBlockWithData) + { + break; + } + } + else + { + itemIndex++; + } + } + + if (blockIndex == lastBlockWithData) + { + // We're re-using another variable for better performance + lastBlockWithData = list._nextItemIndex > 0 ? list._nextItemIndex : blockSize; + while (itemIndex < lastBlockWithData) + { + if (match(sourceMemoryBlockSpan[itemIndex])) + { + return sourceMemoryBlockSpan[itemIndex]; + } + + itemIndex++; + } + } + + return default; } public static RecyclableLongList FindAll(this RecyclableLongList list, Predicate match) @@ -317,7 +351,7 @@ namespace Recyclable.Collections lastBlockWithData = (startIndex + count) >> list._blockSizePow2BitShift; ReadOnlySpan sourceMemoryBlocksSpan = list._memoryBlocks; - ReadOnlySpan sourceMemoryBlockSpan = sourceMemoryBlocksSpan[0]; + ReadOnlySpan sourceMemoryBlockSpan = sourceMemoryBlocksSpan[blockIndex]; while (blockIndex < lastBlockWithData) { if (match(sourceMemoryBlockSpan[itemIndex])) @@ -374,7 +408,7 @@ namespace Recyclable.Collections lastBlockWithData = list._lastBlockWithData; ReadOnlySpan sourceMemoryBlocksSpan = list._memoryBlocks; - ReadOnlySpan sourceMemoryBlockSpan = sourceMemoryBlocksSpan[0]; + ReadOnlySpan sourceMemoryBlockSpan = sourceMemoryBlocksSpan[blockIndex]; while (blockIndex < lastBlockWithData) { if (match(sourceMemoryBlockSpan[itemIndex])) @@ -474,23 +508,37 @@ namespace Recyclable.Collections public static T? FindLast(this RecyclableLongList list, Predicate match) { - //if (list._count == 0) - //{ - // return default; - //} + if (list._longCount == 0) + { + return default; + } - //ReadOnlySpan sourceSpan = list._memoryBlock; - //for (var itemIndex = list._count - 1; itemIndex >= 0; itemIndex--) - //{ - // if (match(sourceSpan[itemIndex])) - // { - // return sourceSpan[itemIndex]; - // } - //} + int blockSizeMinus1 = list._blockSizeMinus1, + itemIndex; - //return default; + ReadOnlySpan memoryBlocksSpan = new(list._memoryBlocks); + ReadOnlySpan sourceSpan = memoryBlocksSpan[list._lastBlockWithData]; + for (itemIndex = list._nextItemIndex == 0 ? blockSizeMinus1 : list._nextItemIndex - 1; itemIndex >= 0; itemIndex--) + { + if (match(sourceSpan[itemIndex])) + { + return sourceSpan[itemIndex]; + } + } - throw new NotImplementedException(); + for (var blockIndex = list._lastBlockWithData - 1; blockIndex >= 0; blockIndex--) + { + sourceSpan = memoryBlocksSpan[blockIndex]; + for (itemIndex = blockSizeMinus1; itemIndex >= 0; itemIndex--) + { + if (match(sourceSpan[itemIndex])) + { + return sourceSpan[itemIndex]; + } + } + } + + return default; } public static int FindLastIndex(this RecyclableLongList list, int startIndex, int count, Predicate match) diff --git a/Recyclable.Collections.Compatibility.List/RecyclableLongList.Compatibility.List.cs b/Recyclable.Collections.Compatibility.List/RecyclableLongList.Compatibility.List.cs index aa9e32b..9a68879 100644 --- a/Recyclable.Collections.Compatibility.List/RecyclableLongList.Compatibility.List.cs +++ b/Recyclable.Collections.Compatibility.List/RecyclableLongList.Compatibility.List.cs @@ -334,43 +334,133 @@ namespace Recyclable.Collections public static void ForEach(this RecyclableLongList list, Action action) { - //int sourceItemsCount = list._count; - //if (sourceItemsCount == 0) - //{ - // return; - //} + if (list._longCount == 0) + { + return; + } - //ReadOnlySpan sourceSpan = list._memoryBlock; - //for (var itemIndex = 0; itemIndex < sourceItemsCount; itemIndex++) - //{ - // action(sourceSpan[itemIndex]); - //} + int blockIndex = 0, + blockSize = list._blockSize, + itemIndex = 0, + lastBlockWithData = list._lastBlockWithData; - throw new NotImplementedException(); + ReadOnlySpan sourceMemoryBlocksSpan = list._memoryBlocks; + ReadOnlySpan sourceMemoryBlockSpan = sourceMemoryBlocksSpan[0]; + while (blockIndex < lastBlockWithData) + { + action(sourceMemoryBlockSpan[itemIndex]); + if (itemIndex + 1 == blockSize) + { + itemIndex = 0; + blockIndex++; + sourceMemoryBlockSpan = sourceMemoryBlocksSpan[blockIndex]; + + if (blockIndex == lastBlockWithData) + { + break; + } + } + else + { + itemIndex++; + } + } + + if (blockIndex == lastBlockWithData) + { + // We're re-using another variable for better performance + lastBlockWithData = list._nextItemIndex > 0 ? list._nextItemIndex : blockSize; + while (itemIndex < lastBlockWithData) + { + action(sourceMemoryBlockSpan[itemIndex++]); + } + } } - public static RecyclableList GetRange(this RecyclableLongList list, int index, int count) + public static RecyclableLongList GetRange(this RecyclableLongList list, int startIndex, int count) { - //int sourceItemsCount = index + count <= list._count ? count : list._count - index; - //if (sourceItemsCount <= 0) - //{ - // return new(); - //} + if (list._longCount == 0 || count == 0) + { + return new(); + } - //ReadOnlySpan sourceSpan = list._memoryBlock; - //RecyclableList result = new(sourceItemsCount); - //Span targetSpan = result._memoryBlock; - //int resultItemsCount = 0; - //sourceItemsCount += index; - //for (var itemIndex = index; itemIndex < sourceItemsCount; itemIndex++) - //{ - // targetSpan[resultItemsCount++] = sourceSpan[itemIndex]; - //} + int itemIndex = startIndex & list._blockSizeMinus1, + blockIndex = startIndex >> list._blockSizePow2BitShift, + blockSize = list._blockSize, + lastItemIndex = (startIndex + count) & list._blockSizeMinus1, + lastBlockWithData = (startIndex + count) >> list._blockSizePow2BitShift, + targetBlockIndex = 0, + targetItemIndex = 0; - //result._count = resultItemsCount; - //return result; + RecyclableLongList result = new(minBlockSize: blockSize, initialCapacity: count); + ReadOnlySpan sourceMemoryBlocksSpan = new (list._memoryBlocks), + targetMemoryBlocksSpan = new (result._memoryBlocks); + ReadOnlySpan sourceMemoryBlockSpan = sourceMemoryBlocksSpan[0]; + Span targetMemoryBlockSpan = new(targetMemoryBlocksSpan[0]); + while (blockIndex < lastBlockWithData) + { + targetMemoryBlockSpan[targetItemIndex] = sourceMemoryBlockSpan[itemIndex]; - throw new NotImplementedException(); + if (targetItemIndex + 1 == blockSize) + { + targetItemIndex = 0; + targetBlockIndex++; + if (targetBlockIndex <= lastBlockWithData) + { + targetMemoryBlockSpan = new(targetMemoryBlocksSpan[targetBlockIndex]); + } + } + else + { + targetItemIndex++; + } + + if (itemIndex + 1 == blockSize) + { + itemIndex = 0; + blockIndex++; + sourceMemoryBlockSpan = sourceMemoryBlocksSpan[blockIndex]; + + if (blockIndex == lastBlockWithData) + { + break; + } + } + else + { + itemIndex++; + } + } + + if (blockIndex == lastBlockWithData) + { + // We're re-using another variable for better performance + lastBlockWithData = lastItemIndex > 0 ? lastItemIndex : blockSize; + while (itemIndex < lastBlockWithData) + { + targetMemoryBlockSpan[targetItemIndex] = sourceMemoryBlockSpan[itemIndex]; + itemIndex++; + if (targetItemIndex + 1 == blockSize) + { + targetItemIndex = 0; + targetBlockIndex++; + if (targetBlockIndex <= lastBlockWithData) + { + targetMemoryBlockSpan = new(targetMemoryBlocksSpan[targetBlockIndex]); + } + } + else + { + targetItemIndex++; + } + } + } + + result._lastBlockWithData = lastBlockWithData; + result._longCount = count; + result._nextItemIndex = count & list._blockSizeMinus1; + result._nextItemBlockIndex = targetBlockIndex; + return result; } public static int RemoveAll(this RecyclableLongList list, Predicate match)