From 2012f51b6e1b3b67be5bc243684b7752bf6bea24 Mon Sep 17 00:00:00 2001 From: mlemanczyk Date: Wed, 1 Nov 2023 21:49:17 +0100 Subject: [PATCH] RecyclableLongList.ConvertAll implemented. --- .../ConvertAll.cs | 16 ++--- .../Program.cs | 4 +- ...eCollectionsCompatibilityListBenchmarks.cs | 7 +- ...ecyclableLongListCompatibilityListTests.cs | 2 +- .../RecyclableLongList.Compatibility.List.cs | 64 ++++++++++++++----- 5 files changed, 63 insertions(+), 30 deletions(-) diff --git a/Recyclable.Collections.Compatibility.List.Benchmarks/ConvertAll.cs b/Recyclable.Collections.Compatibility.List.Benchmarks/ConvertAll.cs index 26780bb..3d488da 100644 --- a/Recyclable.Collections.Compatibility.List.Benchmarks/ConvertAll.cs +++ b/Recyclable.Collections.Compatibility.List.Benchmarks/ConvertAll.cs @@ -40,13 +40,13 @@ namespace Recyclable.Collections.Compatibility.List.Benchmarks DoNothing.With(converted); } - // public void RecyclableLongList_ConvertAll() - // { - // var data = TestObjects; - // var list = TestObjectsAsRecyclableLongList; - // var dataCount = TestObjectCountForSlowMethods; - // using RecyclableList converted = list.ConvertAll(static (item) => (long)item); - // DoNothing(converted); - // } + public void RecyclableLongList_ConvertAll() + { + var data = TestObjects; + var list = TestObjectsAsRecyclableLongList; + var dataCount = TestObjectCountForSlowMethods; + using RecyclableLongList converted = list.ConvertAll(static (item) => (long)item); + DoNothing.With(converted); + } } } diff --git a/Recyclable.Collections.Compatibility.List.Benchmarks/Program.cs b/Recyclable.Collections.Compatibility.List.Benchmarks/Program.cs index 2e9d0d9..df9cce8 100644 --- a/Recyclable.Collections.Compatibility.List.Benchmarks/Program.cs +++ b/Recyclable.Collections.Compatibility.List.Benchmarks/Program.cs @@ -13,10 +13,10 @@ namespace Recyclable.Collections.Compatibility.List.Benchmarks BenchmarkRunner.Run(new[] { //typeof(BinarySearchBenchmarks), - typeof(BinarySearchBenchmarksBestAndWorstCasesWhenConstrainedRange), + //typeof(BinarySearchBenchmarksBestAndWorstCasesWhenConstrainedRange), //typeof(BinarySearchValueLowerThanFirstItemBenchmarks), //typeof(BinarySearchValueHigherThanFirstItemBenchmarks), - //typeof(ConvertAllBenchmarks), + typeof(ConvertAllBenchmarks), //typeof(ExistsBenchmarks), //typeof(FindBenchmarks), //typeof(FindAllBenchmarks), diff --git a/Recyclable.Collections.Compatibility.List.Benchmarks/RecyclableCollectionsCompatibilityListBenchmarks.cs b/Recyclable.Collections.Compatibility.List.Benchmarks/RecyclableCollectionsCompatibilityListBenchmarks.cs index cbab056..3cd3c81 100644 --- a/Recyclable.Collections.Compatibility.List.Benchmarks/RecyclableCollectionsCompatibilityListBenchmarks.cs +++ b/Recyclable.Collections.Compatibility.List.Benchmarks/RecyclableCollectionsCompatibilityListBenchmarks.cs @@ -6,13 +6,14 @@ namespace Recyclable.Collections.Compatibility.List.Benchmarks public partial class RecyclableCollectionsCompatibilityListBenchmarks : DataDrivenBenchmarksBase { - [Params(CollectionsBenchmarksSource.Array)] + [Params(CollectionsBenchmarksSource.List)] public override CollectionsBenchmarksSource BaseDataType { get => base.BaseDataType; set => base.BaseDataType = value; } [Params( + CollectionsBenchmarksSource.Array, //CollectionsBenchmarksSource.List, - //CollectionsBenchmarksSource.PooledList, - //CollectionsBenchmarksSource.RecyclableList, + CollectionsBenchmarksSource.PooledList, + CollectionsBenchmarksSource.RecyclableList, CollectionsBenchmarksSource.RecyclableLongList )] public override CollectionsBenchmarksSource DataType { get => base.DataType; set => base.DataType = value; } diff --git a/Recyclable.Collections.Compatibility.List.Tests/RecyclableLongListCompatibilityListTests.cs b/Recyclable.Collections.Compatibility.List.Tests/RecyclableLongListCompatibilityListTests.cs index c2b8056..1b7307e 100644 --- a/Recyclable.Collections.Compatibility.List.Tests/RecyclableLongListCompatibilityListTests.cs +++ b/Recyclable.Collections.Compatibility.List.Tests/RecyclableLongListCompatibilityListTests.cs @@ -217,7 +217,7 @@ namespace Recyclable.CollectionsTests [Theory] [MemberData(nameof(RecyclableLongListTestData.SourceDataWithBlockSizeWithItemIndexVariants), MemberType = typeof(RecyclableLongListTestData))] - public void ConvertAllShouldConvertAllItems(string testCase, IEnumerable testData, int minBlockSize, int itemsCount) + public void ConvertAllShouldConvertAllItems(string testCase, IEnumerable testData, int itemsCount, int minBlockSize, in long[] itemIndexes) { // Prepare using var list = new RecyclableLongList(testData, minBlockSize, initialCapacity: itemsCount); diff --git a/Recyclable.Collections.Compatibility.List/RecyclableLongList.Compatibility.List.cs b/Recyclable.Collections.Compatibility.List/RecyclableLongList.Compatibility.List.cs index a46eb14..8cab766 100644 --- a/Recyclable.Collections.Compatibility.List/RecyclableLongList.Compatibility.List.cs +++ b/Recyclable.Collections.Compatibility.List/RecyclableLongList.Compatibility.List.cs @@ -209,26 +209,58 @@ namespace Recyclable.Collections return checked((int)~low); } - public static RecyclableList ConvertAll(this RecyclableLongList list, Converter converter) + public static RecyclableLongList ConvertAll(this RecyclableLongList list, Converter converter) { - //int itemsCount = list._count; - //if (itemsCount == 0) - //{ - // return new(); - //} + if (list._longCount == 0) + { + return new(); + } - //RecyclableList result = new(itemsCount); - //TOutput[] resultSpan = result._memoryBlock; - //ReadOnlySpan sourceSpan = list._memoryBlock; - //for (int bufferIndex = 0; bufferIndex < itemsCount; bufferIndex++) - //{ - // resultSpan[bufferIndex] = converter(sourceSpan[bufferIndex]); - //} + int blockIndex = 0, + blockSize = list._blockSize; + RecyclableLongList result = new(blockSize, list._longCount); + ReadOnlySpan resultMemoryBlocksSpan = result._memoryBlocks; + Span resultMemoryBlockSpan = resultMemoryBlocksSpan[0]; + ReadOnlySpan sourceMemoryBlocksSpan = list._memoryBlocks; + ReadOnlySpan sourceMemoryBlockSpan = sourceMemoryBlocksSpan[0]; + var itemIndex = 0; + int lastBlockWithData = list._lastBlockWithData; + while (blockIndex < lastBlockWithData) + { + resultMemoryBlockSpan[itemIndex] = converter(sourceMemoryBlockSpan[itemIndex]); + if (itemIndex + 1 == blockSize) + { + itemIndex = 0; + blockIndex++; + sourceMemoryBlockSpan = sourceMemoryBlocksSpan[blockIndex]; + resultMemoryBlockSpan = resultMemoryBlocksSpan[blockIndex]; - //result._count = itemsCount; - //return result; + if (blockIndex == lastBlockWithData) + { + break; + } + } + else + { + itemIndex++; + } + } - throw new NotImplementedException(); + if (blockIndex == lastBlockWithData) + { + // We're re-using another variable for better performance + lastBlockWithData = list._nextItemIndex > 0 ? list._nextItemIndex : blockSize; + while (itemIndex < lastBlockWithData) + { + resultMemoryBlockSpan[itemIndex] = converter(sourceMemoryBlockSpan[itemIndex++]); + } + } + + result._longCount = list._longCount; + result._nextItemBlockIndex = list._nextItemBlockIndex; + result._nextItemIndex = list._nextItemIndex; + result._lastBlockWithData = lastBlockWithData; + return result; } [MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)]