diff --git a/README.md b/README.md index 9e69183..afef32e 100644 --- a/README.md +++ b/README.md @@ -139,9 +139,9 @@ 1. โœ… `T[]` 1. โœ… Release 0.0.5 1. โœ… Implement `List` compatibility pack in `RecyclableList` - 1. ๐Ÿ‘‰ Overflow review - 1. ๐Ÿ…ฟ๏ธ Add type casting to `long` for `<<` & `>>` operations, where required - 1. ๐Ÿ…ฟ๏ธ Make type castings `checked`, where required + 1. โœ… Overflow review + 1. โœ… Add type casting to `long` for `<<` & `>>` operations, where required + 1. โœ… Make type castings `checked`, where required 1. ๐Ÿ…ฟ๏ธ Release 0.0.6 1. ๐Ÿ…ฟ๏ธ Implement `List` compatibility pack in `RecyclableLongList` 1. ๐Ÿ…ฟ๏ธ Port `RecyclableLongList` optimizations to `RecyclableList` @@ -191,6 +191,7 @@ 1. ๐Ÿ…ฟ๏ธ Multi-threading benchmarks 1. ๐Ÿ…ฟ๏ธ `SpinLockSlimmer` 1. ๐Ÿ…ฟ๏ธ Multi-threading benchmarks + 1. ๐Ÿ…ฟ๏ธ Remove range operators, where possible 1. ๐Ÿ…ฟ๏ธ Release 0.0.14 1. ๐Ÿ…ฟ๏ธ Extend unit tests 1. ๐Ÿ…ฟ๏ธ `RecyclableLongListExtensions.CopyTo` diff --git a/Recyclable.Collections.Benchmarks/POC/SpanConstructorVsTypecasting.Benchmarks.cs b/Recyclable.Collections.Benchmarks/POC/SpanConstructorVsTypecasting.Benchmarks.cs new file mode 100644 index 0000000..bee88e7 --- /dev/null +++ b/Recyclable.Collections.Benchmarks/POC/SpanConstructorVsTypecasting.Benchmarks.cs @@ -0,0 +1,64 @@ +๏ปฟusing System.Runtime.CompilerServices; +using BenchmarkDotNet.Attributes; + +namespace Recyclable.Collections.Benchmarks.POC +{ + public enum SpanConstructorVsTypecastingPocBenchmarkType + { + Unknown, + Constructor, + TypeCasting, + } + + [MemoryDiagnoser] + public class SpanConstructorVsTypecastingPocBenchmarks : PocBenchmarkBase + { + private int[]? TestData { get; set; } + + [MethodImpl(MethodImplOptions.NoOptimization | MethodImplOptions.NoInlining)] + private void DoNothing(ReadOnlySpan span) { } + + [Params(SpanConstructorVsTypecastingPocBenchmarkType.TypeCasting)] + public override SpanConstructorVsTypecastingPocBenchmarkType BaseDataType { get => base.BaseDataType; set => base.BaseDataType = value; } + + [Params(SpanConstructorVsTypecastingPocBenchmarkType.Constructor)] + public override SpanConstructorVsTypecastingPocBenchmarkType DataType { get => base.DataType; set => base.DataType = value; } + + [Params(8)] + public override int TestObjectCount { get => base.TestObjectCount; set => base.TestObjectCount = value; } + + public static void Run() + { + var benchmark = new SpanConstructorVsTypecastingPocBenchmarks(); + benchmark.Setup(); + benchmark.Constructor(); + benchmark.TypeCasting(); + benchmark.Cleanup(); + } + + public void Constructor() + { + ReadOnlySpan span = new(TestData); + DoNothing(span); + } + + public void TypeCasting() + { + ReadOnlySpan span = TestData; + DoNothing(span); + } + + public override void Setup() + { + TestData = new int[TestObjectCount]; + base.Setup(); + } + + protected override Action? GetTestMethod(SpanConstructorVsTypecastingPocBenchmarkType benchmarkType) => benchmarkType switch + { + SpanConstructorVsTypecastingPocBenchmarkType.Constructor => Constructor, + SpanConstructorVsTypecastingPocBenchmarkType.TypeCasting => TypeCasting, + _ => throw CreateUnknownBenchmarkTypeException(benchmarkType), + }; + } +} \ No newline at end of file diff --git a/Recyclable.Collections.Benchmarks/Program.cs b/Recyclable.Collections.Benchmarks/Program.cs index d359734..0ae9ba7 100644 --- a/Recyclable.Collections.Benchmarks/Program.cs +++ b/Recyclable.Collections.Benchmarks/Program.cs @@ -42,7 +42,6 @@ namespace Recyclable.Collections.Benchmarks _ = BenchmarkRunner.Run(BenchmarkConfig); _ = BenchmarkRunner.Run(BenchmarkConfig); _ = BenchmarkRunner.Run(BenchmarkConfig); - _ = BenchmarkRunner.Run(BenchmarkConfig); _ = BenchmarkRunner.Run(BenchmarkConfig); _ = BenchmarkRunner.Run(BenchmarkConfig); _ = BenchmarkRunner.Run(BenchmarkConfig); @@ -51,6 +50,7 @@ namespace Recyclable.Collections.Benchmarks _ = BenchmarkRunner.Run(BenchmarkConfig); _ = BenchmarkRunner.Run(BenchmarkConfig); _ = BenchmarkRunner.Run(BenchmarkConfig); + _ = BenchmarkRunner.Run(BenchmarkConfig); // ArraySizeLimitPocBenchmarks>(BenchmarkConfig); } diff --git a/Recyclable.Collections/RecyclableList.AddRange.cs b/Recyclable.Collections/RecyclableList.AddRange.cs index 7c605dd..5aa15ee 100644 --- a/Recyclable.Collections/RecyclableList.AddRange.cs +++ b/Recyclable.Collections/RecyclableList.AddRange.cs @@ -5,7 +5,7 @@ using System.Runtime.CompilerServices; namespace Recyclable.Collections { public static class zRecyclableListAddRange - { + { private static void AddRangeEnumerated(this RecyclableList list, IEnumerable items, int growByCount) { var enumerator = items.GetEnumerator(); @@ -19,19 +19,19 @@ namespace Recyclable.Collections available = capacity - targetItemIndex, i; - Span memorySpan = new(list._memoryBlock); + Span targetSpan = list._memoryBlock; do { if (targetItemIndex + growByCount > capacity) { capacity = RecyclableListHelpers.EnsureCapacity(list, targetItemIndex, checked((int)BitOperations.RoundUpToPowerOf2((uint)(targetItemIndex + growByCount)))); - memorySpan = new(list._memoryBlock); + targetSpan = list._memoryBlock; available = capacity - targetItemIndex; } for (i = 0; i < available; i++) { - memorySpan[targetItemIndex++] = enumerator.Current; + targetSpan[targetItemIndex++] = enumerator.Current; if (!enumerator.MoveNext()) { break; @@ -48,10 +48,10 @@ namespace Recyclable.Collections { list._capacity = RecyclableListHelpers.EnsureCapacity(list, currentItemsCount, checked((int)BitOperations.RoundUpToPowerOf2((uint)(currentItemsCount + requiredAdditionalCapacity)))); - Span memorySpan = new(list._memoryBlock); + Span targetSpan = list._memoryBlock; foreach (var item in items) { - memorySpan[currentItemsCount++] = item; + targetSpan[currentItemsCount++] = item; } list._count = currentItemsCount; @@ -78,7 +78,7 @@ namespace Recyclable.Collections list._capacity = RecyclableListHelpers.EnsureCapacity(list, list._count, checked((int)BitOperations.RoundUpToPowerOf2((uint)(list._count + items.Length)))); } - new Span(items).CopyTo(new Span(list._memoryBlock, list._count, items.Length)); + new ReadOnlySpan(items).CopyTo(new Span(list._memoryBlock, list._count, items.Length)); list._count += items.Length; list._version++; } @@ -156,7 +156,7 @@ namespace Recyclable.Collections list._capacity = RecyclableListHelpers.EnsureCapacity(list, list._count, checked((int)BitOperations.RoundUpToPowerOf2((uint)(list._count + items._count)))); } - new Span(items._memoryBlock, 0, items._count).CopyTo(new Span(list._memoryBlock, list._count, items._count)); + new ReadOnlySpan(items._memoryBlock, 0, items._count).CopyTo(new Span(list._memoryBlock, list._count, items._count)); list._count += items._count; list._version++; } @@ -215,13 +215,13 @@ namespace Recyclable.Collections public static IEnumerator AddRange(this RecyclableList list, IEnumerable source, int growByCount = RecyclableDefaults.MinPooledArrayLength) { int targetItemIndex = list._count; - Span memorySpan; + Span targetSpan; int i; var enumerator = source.GetEnumerator(); int capacity = list._capacity; - memorySpan = new(list._memoryBlock); + targetSpan = list._memoryBlock; if (enumerator.MoveNext()) { int available = capacity - targetItemIndex; @@ -230,13 +230,13 @@ namespace Recyclable.Collections if (targetItemIndex + growByCount > capacity) { capacity = RecyclableListHelpers.EnsureCapacity(list, targetItemIndex, checked((int)BitOperations.RoundUpToPowerOf2((uint)(targetItemIndex + growByCount)))); - memorySpan = new(list._memoryBlock); + targetSpan = list._memoryBlock; available = capacity - targetItemIndex; } for (i = 0; i < available; i++) { - memorySpan[targetItemIndex++] = (T)enumerator.Current; + targetSpan[targetItemIndex++] = (T)enumerator.Current; if (!enumerator.MoveNext()) { break; @@ -259,10 +259,10 @@ namespace Recyclable.Collections list._capacity = RecyclableListHelpers.EnsureCapacity(list, list._count, checked((int)BitOperations.RoundUpToPowerOf2((uint)(list._count + sourceItemsCount)))); } - Span memorySpan = new(list._memoryBlock, list._count, sourceItemsCount); + Span targetSpan = new(list._memoryBlock, list._count, sourceItemsCount); for (var sourceItemIndex = 0; sourceItemIndex < sourceItemsCount; sourceItemIndex++) { - memorySpan[sourceItemIndex] = items[sourceItemIndex]; + targetSpan[sourceItemIndex] = items[sourceItemIndex]; } list._count += sourceItemsCount; @@ -314,5 +314,5 @@ namespace Recyclable.Collections list._version++; } } - } + } } \ No newline at end of file diff --git a/Recyclable.Collections/RecyclableList.Compatibility.List.Find.cs b/Recyclable.Collections/RecyclableList.Compatibility.List.Find.cs index 3ebd098..d86cab1 100644 --- a/Recyclable.Collections/RecyclableList.Compatibility.List.Find.cs +++ b/Recyclable.Collections/RecyclableList.Compatibility.List.Find.cs @@ -12,7 +12,7 @@ namespace Recyclable.Collections return false; } - ReadOnlySpan sourceSpan = new(list._memoryBlock); + ReadOnlySpan sourceSpan = list._memoryBlock; for (var itemIndex = 0; itemIndex < sourceItemsCount; itemIndex++) { if (match(sourceSpan[itemIndex])) @@ -32,7 +32,7 @@ namespace Recyclable.Collections return default; } - ReadOnlySpan sourceSpan = new(list._memoryBlock); + ReadOnlySpan sourceSpan = list._memoryBlock; for (var itemIndex = 0; itemIndex < sourceItemsCount; itemIndex++) { if (match(sourceSpan[itemIndex])) @@ -52,7 +52,7 @@ namespace Recyclable.Collections return new(); } - ReadOnlySpan sourceSpan = new(list._memoryBlock); + ReadOnlySpan sourceSpan = list._memoryBlock; RecyclableList result = new(sourceItemsCount >> 3); Span resultSpan = result._memoryBlock; int capacity = result._capacity, @@ -85,7 +85,7 @@ namespace Recyclable.Collections return new(); } - ReadOnlySpan sourceSpan = new(list._memoryBlock); + ReadOnlySpan sourceSpan = list._memoryBlock; RecyclableList result = new(sourceItemsCount >> 3); Span resultSpan = result._memoryBlock; int capacity = result._capacity, @@ -120,7 +120,7 @@ namespace Recyclable.Collections } sourceItemsCount = Math.Min(sourceItemsCount, startIndex + sourceItemsCount); - ReadOnlySpan sourceSpan = new(list._memoryBlock); + ReadOnlySpan sourceSpan = list._memoryBlock; for (var itemIndex = startIndex; itemIndex < sourceItemsCount; itemIndex++) { if (match(sourceSpan[itemIndex])) @@ -141,7 +141,7 @@ namespace Recyclable.Collections } sourceItemsCount = Math.Min(sourceItemsCount, startIndex + sourceItemsCount); - ReadOnlySpan sourceSpan = new(list._memoryBlock); + ReadOnlySpan sourceSpan = list._memoryBlock; for (var itemIndex = startIndex; itemIndex < sourceItemsCount; itemIndex++) { if (match(sourceSpan[itemIndex])) @@ -161,7 +161,7 @@ namespace Recyclable.Collections return RecyclableDefaults.ItemNotFoundIndex; } - ReadOnlySpan sourceSpan = new(list._memoryBlock); + ReadOnlySpan sourceSpan = list._memoryBlock; for (var itemIndex = 0; itemIndex < sourceItemsCount; itemIndex++) { if (match(sourceSpan[itemIndex])) @@ -180,7 +180,7 @@ namespace Recyclable.Collections return default; } - ReadOnlySpan sourceSpan = new(list._memoryBlock); + ReadOnlySpan sourceSpan = list._memoryBlock; for (var itemIndex = list._count - 1; itemIndex >= 0; itemIndex--) { if (match(sourceSpan[itemIndex])) @@ -218,7 +218,7 @@ namespace Recyclable.Collections } int lastItemIndex = startIndex - sourceItemsCount; - ReadOnlySpan sourceSpan = new(list._memoryBlock); + ReadOnlySpan sourceSpan = list._memoryBlock; for (var itemIndex = startIndex; itemIndex > lastItemIndex; itemIndex--) { if (match(sourceSpan[itemIndex])) @@ -237,7 +237,7 @@ namespace Recyclable.Collections return RecyclableDefaults.ItemNotFoundIndex; } - ReadOnlySpan sourceSpan = new(list._memoryBlock); + ReadOnlySpan sourceSpan = list._memoryBlock; for (var itemIndex = startIndex; itemIndex >= 0; itemIndex--) { if (match(sourceSpan[itemIndex])) @@ -256,7 +256,7 @@ namespace Recyclable.Collections return RecyclableDefaults.ItemNotFoundIndex; } - ReadOnlySpan sourceSpan = new(list._memoryBlock); + ReadOnlySpan sourceSpan = list._memoryBlock; for (var itemIndex = list._count - 1; itemIndex >= 0; itemIndex--) { if (match(sourceSpan[itemIndex])) diff --git a/Recyclable.Collections/RecyclableList.Compatibility.List.InsertRange.cs b/Recyclable.Collections/RecyclableList.Compatibility.List.InsertRange.cs index 4022043..4c50cd9 100644 --- a/Recyclable.Collections/RecyclableList.Compatibility.List.InsertRange.cs +++ b/Recyclable.Collections/RecyclableList.Compatibility.List.InsertRange.cs @@ -26,7 +26,7 @@ namespace Recyclable.Collections Array.Copy(memoryBlock, index, memoryBlock, capacity - movingBlockLength, movingBlockLength); } - Span memorySpan = new(memoryBlock); + Span memorySpan = memoryBlock; do { if (index + available + movingBlockLength > capacity) @@ -34,7 +34,7 @@ namespace Recyclable.Collections var capacityBeforeIncrease = capacity; capacity = checked((int)BitOperations.RoundUpToPowerOf2((uint)(capacity + growByCount))); _ = RecyclableListHelpers.EnsureCapacity(list, memoryBlock.Length, capacity); - memorySpan = new(memoryBlock = list._memoryBlock); + memorySpan = memoryBlock = list._memoryBlock; available = capacity - index - movingBlockLength; Array.Copy(memoryBlock, capacityBeforeIncrease - movingBlockLength, memoryBlock, capacity - movingBlockLength, movingBlockLength); } @@ -71,7 +71,7 @@ namespace Recyclable.Collections list._capacity = RecyclableListHelpers.EnsureCapacity(list, currentItemsCount, checked((int)BitOperations.RoundUpToPowerOf2((uint)(currentItemsCount + requiredAdditionalCapacity)))); Array.Copy(list._memoryBlock, index, list._memoryBlock, index + requiredAdditionalCapacity, list._count - index); - Span memorySpan = new(list._memoryBlock); + Span memorySpan = list._memoryBlock; foreach (var item in items) { memorySpan[index++] = item; @@ -106,7 +106,7 @@ namespace Recyclable.Collections T[] memoryBlock = list._memoryBlock; Array.Copy(memoryBlock, index, memoryBlock, index + items.Length, list._count - index); - new Span(items).CopyTo(new Span(memoryBlock, index, items.Length)); + new ReadOnlySpan(items).CopyTo(new Span(memoryBlock, index, items.Length)); list._count += items.Length; list._version++; } @@ -196,7 +196,7 @@ namespace Recyclable.Collections T[] memoryBlock = list._memoryBlock; Array.Copy(memoryBlock, index, memoryBlock, index + items.Count, list._count - index); - new Span(items._memoryBlock, 0, items._count).CopyTo(new(list._memoryBlock, index, items._count)); + new ReadOnlySpan(items._memoryBlock, 0, items._count).CopyTo(new(list._memoryBlock, index, items._count)); list._count += items._count; list._version++; } @@ -262,7 +262,7 @@ namespace Recyclable.Collections var enumerator = source.GetEnumerator(); int capacity = list._capacity; - memorySpan = new(list._memoryBlock); + memorySpan = list._memoryBlock; if (enumerator.MoveNext()) { int available = capacity - targetItemIndex; @@ -271,7 +271,7 @@ namespace Recyclable.Collections if (targetItemIndex + growByCount > capacity) { capacity = RecyclableListHelpers.EnsureCapacity(list, targetItemIndex, checked((int)BitOperations.RoundUpToPowerOf2((uint)(targetItemIndex + growByCount)))); - memorySpan = new(list._memoryBlock); + memorySpan = list._memoryBlock; available = capacity - targetItemIndex; } diff --git a/Recyclable.Collections/RecyclableList.Compatibility.List.cs b/Recyclable.Collections/RecyclableList.Compatibility.List.cs index 94cad31..1db3766 100644 --- a/Recyclable.Collections/RecyclableList.Compatibility.List.cs +++ b/Recyclable.Collections/RecyclableList.Compatibility.List.cs @@ -50,7 +50,7 @@ namespace Recyclable.Collections return; } - ReadOnlySpan sourceSpan = new(list._memoryBlock); + ReadOnlySpan sourceSpan = list._memoryBlock; for (var itemIndex = 0; itemIndex < sourceItemsCount; itemIndex++) { action(sourceSpan[itemIndex]); @@ -65,14 +65,14 @@ namespace Recyclable.Collections return new(); } - ReadOnlySpan sourceSpan = new(list._memoryBlock); + ReadOnlySpan sourceSpan = list._memoryBlock; RecyclableList result = new(sourceItemsCount); - Span resultSpan = result._memoryBlock; + Span targetSpan = result._memoryBlock; int resultItemsCount = 0; sourceItemsCount += index; for (var itemIndex = index; itemIndex < sourceItemsCount; itemIndex++) { - resultSpan[resultItemsCount++] = sourceSpan[itemIndex]; + targetSpan[resultItemsCount++] = sourceSpan[itemIndex]; } result._count = resultItemsCount; @@ -166,7 +166,7 @@ namespace Recyclable.Collections public static T[] ToArray(this RecyclableList list) { T[] result = new T[list._count]; - new Span(list._memoryBlock, 0, list._count).CopyTo(new Span(result)); + new ReadOnlySpan(list._memoryBlock, 0, list._count).CopyTo(result); return result; } @@ -179,7 +179,7 @@ namespace Recyclable.Collections ? RecyclableArrayPool.RentShared(requiredCapacity) : new T[requiredCapacity]; - new Span(oldMemoryBlock, 0, list._count).CopyTo(new(result)); + new ReadOnlySpan(oldMemoryBlock, 0, list._count).CopyTo(result); if (oldMemoryBlock.Length >= RecyclableDefaults.MinPooledArrayLength) { @@ -198,7 +198,7 @@ namespace Recyclable.Collections return false; } - ReadOnlySpan sourceSpan = new(list._memoryBlock); + ReadOnlySpan sourceSpan = list._memoryBlock; for (var itemIndex = 0; itemIndex < sourceItemsCount; itemIndex++) { if (!match(sourceSpan[itemIndex])) diff --git a/Recyclable.Collections/RecyclableList.Helpers.cs b/Recyclable.Collections/RecyclableList.Helpers.cs index a33a5ff..e8882c8 100644 --- a/Recyclable.Collections/RecyclableList.Helpers.cs +++ b/Recyclable.Collections/RecyclableList.Helpers.cs @@ -20,7 +20,7 @@ namespace Recyclable.Collections : RecyclableArrayPool.RentShared(list._capacity); // & WAS SLOWER WITHOUT - new Span(oldMemoryBlock, 0, list._count).CopyTo(list._memoryBlock); + new ReadOnlySpan(oldMemoryBlock, 0, list._count).CopyTo(list._memoryBlock); if (oldMemoryBlock.Length >= RecyclableDefaults.MinPooledArrayLength) { @@ -43,7 +43,7 @@ namespace Recyclable.Collections : new T[newSize]; // & WAS SLOWER AS ARRAY - new Span(oldMemoryBlock, 0, sourceList._capacity).CopyTo(sourceList._memoryBlock); + new ReadOnlySpan(oldMemoryBlock, 0, sourceList._capacity).CopyTo(sourceList._memoryBlock); if (oldMemoryBlock.Length >= RecyclableDefaults.MinPooledArrayLength) { @@ -69,7 +69,7 @@ namespace Recyclable.Collections : new T[newSize]; // & WAS SLOWER AS ARRAY - new Span(oldMemoryBlock, 0, oldSize).CopyTo(sourceList._memoryBlock); + new ReadOnlySpan(oldMemoryBlock, 0, oldSize).CopyTo(sourceList._memoryBlock); if (oldMemoryBlock.Length >= RecyclableDefaults.MinPooledArrayLength) { diff --git a/Recyclable.Collections/RecyclableList.cs b/Recyclable.Collections/RecyclableList.cs index 9812d49..4593fd6 100644 --- a/Recyclable.Collections/RecyclableList.cs +++ b/Recyclable.Collections/RecyclableList.cs @@ -222,7 +222,7 @@ namespace Recyclable.Collections } else { - _capacity = RecyclableListHelpers.EnsureCapacity(this, (int)BitOperations.RoundUpToPowerOf2((uint)_capacity)); + _capacity = RecyclableListHelpers.EnsureCapacity(this, checked((int)BitOperations.RoundUpToPowerOf2((uint)_capacity))); } } @@ -273,7 +273,7 @@ namespace Recyclable.Collections { // TODO: Compare performance // Array.Copy(_memoryBlock, index, _memoryBlock, index + 1, oldCount); - new Span(_memoryBlock, index, oldCount -= index) + new ReadOnlySpan(_memoryBlock, index, oldCount -= index) .CopyTo(new Span(_memoryBlock, index + 1, oldCount)); } diff --git a/Recyclable.Collections/RecyclableLongList.AddRange.cs b/Recyclable.Collections/RecyclableLongList.AddRange.cs index dc96591..e8f5b79 100644 --- a/Recyclable.Collections/RecyclableLongList.AddRange.cs +++ b/Recyclable.Collections/RecyclableLongList.AddRange.cs @@ -23,7 +23,7 @@ namespace Recyclable.Collections available = capacity - copied, i; - Span memoryBlocksSpan = new(targetList._memoryBlocks); + ReadOnlySpan memoryBlocksSpan = targetList._memoryBlocks; Span blockArraySpan; while (true) @@ -31,11 +31,11 @@ namespace Recyclable.Collections if (copied + blockSize > capacity) { capacity = RecyclableLongList.Helpers.Resize(targetList, blockSize, targetList._blockSizePow2BitShift, checked((long)BitOperations.RoundUpToPowerOf2((ulong)(capacity + blockSize)))); - memoryBlocksSpan = new(targetList._memoryBlocks); + memoryBlocksSpan = targetList._memoryBlocks; available = capacity - copied; } - blockArraySpan = new(memoryBlocksSpan[targetBlockIdx]); + blockArraySpan = memoryBlocksSpan[targetBlockIdx]; for (i = 1; i <= available; i++) { blockArraySpan[targetItemIdx++] = enumerator.Current; @@ -69,7 +69,7 @@ namespace Recyclable.Collections break; } - blockArraySpan = new(memoryBlocksSpan[targetBlockIdx]); + blockArraySpan = memoryBlocksSpan[targetBlockIdx]; } } @@ -94,8 +94,8 @@ namespace Recyclable.Collections targetList._capacity = RecyclableLongList.Helpers.Resize(targetList, blockSize, targetList._blockSizePow2BitShift, checked((long)BitOperations.RoundUpToPowerOf2((ulong)requiredCapacity))); } - Span memoryBlocksSpan = new(targetList._memoryBlocks); - Span blockArraySpan = new(memoryBlocksSpan[targetBlockIdx]); + ReadOnlySpan memoryBlocksSpan = targetList._memoryBlocks; + Span blockArraySpan = memoryBlocksSpan[targetBlockIdx]; foreach (var item in items) { blockArraySpan[targetItemIdx++] = item; @@ -108,7 +108,7 @@ namespace Recyclable.Collections break; } - blockArraySpan = new Span(memoryBlocksSpan[targetBlockIdx]); + blockArraySpan = memoryBlocksSpan[targetBlockIdx]; } } @@ -138,7 +138,7 @@ namespace Recyclable.Collections targetList._capacity = RecyclableLongList.Helpers.Resize(targetList, blockSize, targetList._blockSizePow2BitShift, checked((long)BitOperations.RoundUpToPowerOf2((ulong)targetCapacity))); } - Span memoryBlocksSpan = new(targetList._memoryBlocks); + ReadOnlySpan memoryBlocksSpan = targetList._memoryBlocks; Array.Copy(items, 0, memoryBlocksSpan[targetBlockIndex++], targetList._nextItemIndex, sourceItemIndex); while (sourceItemIndex < fullBlockItemsCount) { @@ -165,7 +165,7 @@ namespace Recyclable.Collections } else { - targetList._nextItemIndex += (int)sourceItemIndex; + targetList._nextItemIndex += checked((int)sourceItemIndex); } } @@ -189,11 +189,11 @@ namespace Recyclable.Collections // We're better off to temporarily copy it to a fixed array, // than copying them item by item. We may run into OOMs, though. - T[] itemsBuffer = items.Count >= RecyclableDefaults.MinPooledArrayLength ? RecyclableArrayPool.RentShared((int)BitOperations.RoundUpToPowerOf2((uint)items.Count)) : new T[items.Count]; + T[] itemsBuffer = items.Count >= RecyclableDefaults.MinPooledArrayLength ? RecyclableArrayPool.RentShared(checked((int)BitOperations.RoundUpToPowerOf2((uint)items.Count))) : new T[items.Count]; items.CopyTo(itemsBuffer, 0); - Span itemsSpan = new(itemsBuffer, 0, items.Count); - Span memoryBlocksSpan = new(targetList._memoryBlocks); + ReadOnlySpan itemsSpan = new(itemsBuffer, 0, items.Count); + ReadOnlySpan memoryBlocksSpan = targetList._memoryBlocks; Span targetBlockArraySpan = new(memoryBlocksSpan[targetBlockIndex], targetList._nextItemIndex, targetList._blockSize - targetList._nextItemIndex); while (targetBlockArraySpan.Length <= itemsSpan.Length) { @@ -205,7 +205,7 @@ namespace Recyclable.Collections break; } - targetBlockArraySpan = new(memoryBlocksSpan[targetBlockIndex]); + targetBlockArraySpan = memoryBlocksSpan[targetBlockIndex]; } if (itemsSpan.Length > 0) @@ -255,12 +255,12 @@ namespace Recyclable.Collections // We're better off to temporarily copy it to a fixed array, // than copying them item by item. We may run into OOMs, though. - T[] itemsBuffer = items.Count >= RecyclableDefaults.MinPooledArrayLength ? RecyclableArrayPool.RentShared((int)BitOperations.RoundUpToPowerOf2((uint)items.Count)) : new T[items.Count]; + T[] itemsBuffer = items.Count >= RecyclableDefaults.MinPooledArrayLength ? RecyclableArrayPool.RentShared(checked((int)BitOperations.RoundUpToPowerOf2((uint)items.Count))) : new T[items.Count]; items.CopyTo(itemsBuffer, 0); - Span itemsSpan = new(itemsBuffer, 0, items.Count); - Span memoryBlocksSpan = new(targetList._memoryBlocks); + ReadOnlySpan itemsSpan = new(itemsBuffer, 0, items.Count); + ReadOnlySpan memoryBlocksSpan = targetList._memoryBlocks; Span targetBlockArraySpan = new(memoryBlocksSpan[targetBlockIndex], targetList._nextItemIndex, targetList._blockSize - targetList._nextItemIndex); while (targetBlockArraySpan.Length <= itemsSpan.Length) @@ -273,7 +273,7 @@ namespace Recyclable.Collections break; } - targetBlockArraySpan = new(memoryBlocksSpan[targetBlockIndex]); + targetBlockArraySpan = memoryBlocksSpan[targetBlockIndex]; } if (itemsSpan.Length > 0) @@ -323,7 +323,7 @@ namespace Recyclable.Collections available = capacity - copied, i; - Span memoryBlocksSpan = new(targetList._memoryBlocks); + ReadOnlySpan memoryBlocksSpan = targetList._memoryBlocks; Span blockArraySpan; while (true) @@ -331,11 +331,11 @@ namespace Recyclable.Collections if (copied + blockSize > capacity) { capacity = RecyclableLongList.Helpers.Resize(targetList, blockSize, targetList._blockSizePow2BitShift, checked((long)BitOperations.RoundUpToPowerOf2((ulong)(capacity + blockSize)))); - memoryBlocksSpan = new(targetList._memoryBlocks); + memoryBlocksSpan = targetList._memoryBlocks; available = capacity - copied; } - blockArraySpan = new(memoryBlocksSpan[targetBlockIdx]); + blockArraySpan = memoryBlocksSpan[targetBlockIdx]; for (i = 1; i <= available; i++) { blockArraySpan[targetItemIdx++] = (T)enumerator.Current; @@ -369,7 +369,7 @@ namespace Recyclable.Collections break; } - blockArraySpan = new(memoryBlocksSpan[targetBlockIdx]); + blockArraySpan = memoryBlocksSpan[targetBlockIdx]; } } @@ -446,8 +446,8 @@ namespace Recyclable.Collections targetList._capacity = RecyclableLongList.Helpers.Resize(targetList, blockSize, targetList._blockSizePow2BitShift, checked((long)BitOperations.RoundUpToPowerOf2((ulong)requiredCapacity))); } - Span memoryBlocksSpan = new(targetList._memoryBlocks); - Span blockArraySpan = new(memoryBlocksSpan[targetBlockIdx]); + ReadOnlySpan memoryBlocksSpan = targetList._memoryBlocks; + Span blockArraySpan = memoryBlocksSpan[targetBlockIdx]; for (var itemIndex = 0; itemIndex < sourceItemsCount; itemIndex++) { @@ -461,7 +461,7 @@ namespace Recyclable.Collections break; } - blockArraySpan = new Span(memoryBlocksSpan[targetBlockIdx]); + blockArraySpan = memoryBlocksSpan[targetBlockIdx]; } } @@ -489,7 +489,7 @@ namespace Recyclable.Collections targetList._capacity = RecyclableLongList.Helpers.Resize(targetList, blockSize, targetList._blockSizePow2BitShift, checked((long)BitOperations.RoundUpToPowerOf2((ulong)targetCapacity))); } - Span memoryBlocksSpan = new(targetList._memoryBlocks); + ReadOnlySpan memoryBlocksSpan = targetList._memoryBlocks; items.CopyTo(0, memoryBlocksSpan[targetBlockIndex], targetList._nextItemIndex, copied); if (targetList._nextItemIndex + copied == blockSize) @@ -535,7 +535,7 @@ namespace Recyclable.Collections targetList._capacity = RecyclableLongList.Helpers.Resize(targetList, targetList._blockSize, targetList._blockSizePow2BitShift, checked((long)BitOperations.RoundUpToPowerOf2((ulong)targetCapacity))); } - Span memoryBlocksSpan = new(targetList._memoryBlocks); + ReadOnlySpan memoryBlocksSpan = targetList._memoryBlocks; Span targetBlockArraySpan = new(memoryBlocksSpan[targetBlockIndex], targetList._nextItemIndex, targetList._blockSize - targetList._nextItemIndex); while (items.Length >= targetBlockArraySpan.Length) @@ -548,7 +548,7 @@ namespace Recyclable.Collections } targetBlockIndex++; - targetBlockArraySpan = new(memoryBlocksSpan[targetBlockIndex]); + targetBlockArraySpan = memoryBlocksSpan[targetBlockIndex]; } if (items.Length > 0) @@ -590,8 +590,8 @@ namespace Recyclable.Collections targetList._capacity = RecyclableLongList.Helpers.Resize(targetList, targetList._blockSize, targetList._blockSizePow2BitShift, checked((long)BitOperations.RoundUpToPowerOf2((ulong)targetCapacity))); } - Span itemsSpan = new(items._memoryBlock, 0, items._count); - Span targetMemoryBlocksSpan = new(targetList._memoryBlocks); + ReadOnlySpan itemsSpan = new(items._memoryBlock, 0, items._count); + ReadOnlySpan targetMemoryBlocksSpan = targetList._memoryBlocks; Span targetBlockArraySpan = new(targetMemoryBlocksSpan[targetBlockIndex], targetList._nextItemIndex, targetList._blockSize - targetList._nextItemIndex); while (itemsSpan.Length >= targetBlockArraySpan.Length) @@ -604,7 +604,7 @@ namespace Recyclable.Collections break; } - targetBlockArraySpan = new(targetMemoryBlocksSpan[targetBlockIndex]); + targetBlockArraySpan = targetMemoryBlocksSpan[targetBlockIndex]; } if (itemsSpan.Length > 0) @@ -652,20 +652,20 @@ namespace Recyclable.Collections targetList._capacity = RecyclableLongList.Helpers.Resize(targetList, targetList._blockSize, targetList._blockSizePow2BitShift, checked((long)BitOperations.RoundUpToPowerOf2((ulong)targetCapacity))); } - Span sourceMemoryBlocksSpan = new(items._memoryBlocks); - Span itemsSpan = new(sourceMemoryBlocksSpan[sourceBlockIndex]); - Span targetMemoryBlocksSpan = new(targetList._memoryBlocks); + ReadOnlySpan sourceMemoryBlocksSpan = items._memoryBlocks; + ReadOnlySpan itemsSpan = sourceMemoryBlocksSpan[sourceBlockIndex]; + ReadOnlySpan targetMemoryBlocksSpan = targetList._memoryBlocks; Span targetBlockArraySpan = new(targetMemoryBlocksSpan[targetBlockIndex], targetList._nextItemIndex, targetList._blockSize - targetList._nextItemIndex); while (copiedCount < itemsCount) { - toCopy = checked((int)Math.Min(itemsCount - copiedCount, itemsSpan.Length)); + toCopy = (int)Math.Min(itemsCount - copiedCount, itemsSpan.Length); if (targetBlockArraySpan.Length < toCopy) { toCopy = targetBlockArraySpan.Length; itemsSpan[..toCopy].CopyTo(targetBlockArraySpan); targetBlockIndex++; - targetBlockArraySpan = new(targetMemoryBlocksSpan[targetBlockIndex]); + targetBlockArraySpan = targetMemoryBlocksSpan[targetBlockIndex]; itemsSpan = itemsSpan[toCopy..]; copiedCount += toCopy; } @@ -677,14 +677,14 @@ namespace Recyclable.Collections if (itemsSpan.IsEmpty && sourceBlockIndex + 1 < sourceMemoryBlocksSpan.Length) { sourceBlockIndex++; - itemsSpan = new(sourceMemoryBlocksSpan[sourceBlockIndex]); + itemsSpan = sourceMemoryBlocksSpan[sourceBlockIndex]; } copiedCount += toCopy; if (targetBlockArraySpan.IsEmpty && copiedCount < itemsCount) { targetBlockIndex++; - targetBlockArraySpan = new(targetMemoryBlocksSpan[targetBlockIndex]); + targetBlockArraySpan = targetMemoryBlocksSpan[targetBlockIndex]; } } } @@ -697,7 +697,7 @@ namespace Recyclable.Collections } else { - targetList._nextItemIndex = checked((int)(targetCapacity & targetList._blockSizeMinus1)); + targetList._nextItemIndex = (int)(targetCapacity & targetList._blockSizeMinus1); targetList._nextItemBlockIndex = targetBlockIndex; } @@ -712,15 +712,15 @@ namespace Recyclable.Collections return; } - int targetBlockIndex = targetList._nextItemBlockIndex; - + int targetBlockIndex = targetList._nextItemBlockIndex; long targetCapacity = targetList._longCount + items.Length; + if (targetList._capacity < targetCapacity) { targetList._capacity = RecyclableLongList.Helpers.Resize(targetList, targetList._blockSize, targetList._blockSizePow2BitShift, checked((long)BitOperations.RoundUpToPowerOf2((ulong)targetCapacity))); } - Span memoryBlocksSpan = new(targetList._memoryBlocks); + ReadOnlySpan memoryBlocksSpan = targetList._memoryBlocks; Span targetBlockArraySpan = new(memoryBlocksSpan[targetBlockIndex], targetList._nextItemIndex, targetList._blockSize - targetList._nextItemIndex); while (items.Length >= targetBlockArraySpan.Length) @@ -733,7 +733,7 @@ namespace Recyclable.Collections } targetBlockIndex++; - targetBlockArraySpan = new(memoryBlocksSpan[targetBlockIndex]); + targetBlockArraySpan = memoryBlocksSpan[targetBlockIndex]; } if (items.Length > 0) @@ -775,8 +775,8 @@ namespace Recyclable.Collections targetList._capacity = RecyclableLongList.Helpers.Resize(targetList, targetList._blockSize, targetList._blockSizePow2BitShift, checked((long)BitOperations.RoundUpToPowerOf2((ulong)targetCapacity))); } - Span itemsSpan = new(items); - Span memoryBlocksSpan = new(targetList._memoryBlocks); + ReadOnlySpan itemsSpan = items; + ReadOnlySpan memoryBlocksSpan = targetList._memoryBlocks; Span targetBlockArraySpan = new(memoryBlocksSpan[targetBlockIndex], targetList._nextItemIndex, targetList._blockSize - targetList._nextItemIndex); while (itemsSpan.Length >= targetBlockArraySpan.Length) @@ -789,7 +789,7 @@ namespace Recyclable.Collections } targetBlockIndex++; - targetBlockArraySpan = new(memoryBlocksSpan[targetBlockIndex]); + targetBlockArraySpan = memoryBlocksSpan[targetBlockIndex]; } if (itemsSpan.Length > 0) diff --git a/Recyclable.Collections/RecyclableLongList.Helpers.cs b/Recyclable.Collections/RecyclableLongList.Helpers.cs index b7e870e..6015f77 100644 --- a/Recyclable.Collections/RecyclableLongList.Helpers.cs +++ b/Recyclable.Collections/RecyclableLongList.Helpers.cs @@ -22,21 +22,21 @@ namespace Recyclable.Collections T[][] memoryBlocks = list._memoryBlocks; T[] currentBlock = memoryBlocks[targetBlockIndex]; - new Span(currentBlock, targetItemIndex + 1, blockSizeMinus1 - targetItemIndex) + new ReadOnlySpan(currentBlock, targetItemIndex + 1, blockSizeMinus1 - targetItemIndex) .CopyTo(new Span(currentBlock, targetItemIndex, blockSizeMinus1 - targetItemIndex)); while (targetBlockIndex < lastTakenBlockIndex) { new Span(currentBlock)[blockSizeMinus1] = (currentBlock = memoryBlocks[++targetBlockIndex])[0]; - new Span(currentBlock, 1, blockSizeMinus1) - .CopyTo(new Span(currentBlock)); + new ReadOnlySpan(currentBlock, 1, blockSizeMinus1) + .CopyTo(currentBlock); } if (targetBlockIndex == lastTakenBlockIndex) { new Span(currentBlock)[blockSizeMinus1] = (currentBlock = memoryBlocks[targetBlockIndex + 1])[0]; - new Span(currentBlock, 1, list._nextItemIndex != 0 ? list._nextItemIndex - 1 : blockSizeMinus1) - .CopyTo(new Span(currentBlock)); + new ReadOnlySpan(currentBlock, 1, list._nextItemIndex != 0 ? list._nextItemIndex - 1 : blockSizeMinus1) + .CopyTo(currentBlock); } } @@ -58,12 +58,12 @@ namespace Recyclable.Collections int currentBlockIndex = lastTakenBlockIndex; while (currentBlockIndex > targetBlockIndex) { - new Span(currentBlock = memoryBlocks[currentBlockIndex--], 0, blockSizeMinus1) + new ReadOnlySpan(currentBlock = memoryBlocks[currentBlockIndex--], 0, blockSizeMinus1) .CopyTo(new Span(currentBlock, 1, blockSizeMinus1)); new Span(currentBlock)[0] = memoryBlocks[currentBlockIndex][blockSizeMinus1]; } - new Span(currentBlock = memoryBlocks[targetBlockIndex], targetItemIndex, blockSizeMinus1 - targetItemIndex) + new ReadOnlySpan(currentBlock = memoryBlocks[targetBlockIndex], targetItemIndex, blockSizeMinus1 - targetItemIndex) .CopyTo(new Span(currentBlock, targetItemIndex + 1, blockSizeMinus1 - targetItemIndex)); new Span(memoryBlocks[targetBlockIndex])[targetItemIndex] = item; @@ -76,11 +76,12 @@ namespace Recyclable.Collections return; } - Span sourceBlockMemory; + ReadOnlySpan sourceBlockMemory; Span destinationArrayMemory; + // TODO: Replace with bit-shifting int startingBlockIndex = (int)(startingIndex / blockSize); int lastBlockIndex = (int)((itemsCount / blockSize) + (itemsCount % blockSize != 0 ? 1 : 0)) - 1; - Span sourceMemoryBlocksSpan = new(sourceMemoryBlocks, startingBlockIndex, lastBlockIndex + 1); + ReadOnlySpan sourceMemoryBlocksSpan = new(sourceMemoryBlocks, startingBlockIndex, lastBlockIndex + 1); destinationArrayMemory = new Span(destinationArray, destinationArrayIndex, (int)Math.Min(destinationArray.Length - destinationArrayIndex, itemsCount)); int memoryBlockIndex; for (memoryBlockIndex = 0; memoryBlockIndex < lastBlockIndex; memoryBlockIndex++) @@ -104,11 +105,12 @@ namespace Recyclable.Collections return; } + // TODO: Replace with bit-shifting int startingBlockIndex = (int)(startingIndex / blockSize); int lastBlockIndex = (int)((itemsCount / blockSize) + (itemsCount % blockSize != 0 ? 1 : 0)) - 1; var destinationIndex = destinationArrayIndex; - Span sourceMemoryBlocksSpan = new(sourceMemoryBlocks, startingBlockIndex, lastBlockIndex + 1); + ReadOnlySpan sourceMemoryBlocksSpan = new(sourceMemoryBlocks, startingBlockIndex, lastBlockIndex + 1); for (int memoryBlockIndex = 0; memoryBlockIndex < lastBlockIndex; memoryBlockIndex++) { Array.ConstrainedCopy(sourceMemoryBlocksSpan[memoryBlockIndex], 0, destinationArray, destinationIndex, blockSize); @@ -192,7 +194,7 @@ namespace Recyclable.Collections } } - return checked(requiredBlockCount << minBlockSizePow2Shift); + return requiredBlockCount << minBlockSizePow2Shift; } #pragma warning disable CA2208 diff --git a/Recyclable.Collections/RecyclableLongList.IList.cs b/Recyclable.Collections/RecyclableLongList.IList.cs index befd6bf..5349c05 100644 --- a/Recyclable.Collections/RecyclableLongList.IList.cs +++ b/Recyclable.Collections/RecyclableLongList.IList.cs @@ -49,12 +49,12 @@ namespace Recyclable.Collections if (value is T typeValue) { Add(typeValue); - return (int)(_longCount - 1); + return checked((int)(_longCount - 1)); } else if (value == null && _defaultIsNull) { Add(null); - return (int)(_longCount - 1); + return checked((int)(_longCount - 1)); } else { diff --git a/Recyclable.Collections/RecyclableLongList.IndexOfHelpers.cs b/Recyclable.Collections/RecyclableLongList.IndexOfHelpers.cs index c3f0756..a7f1b50 100644 --- a/Recyclable.Collections/RecyclableLongList.IndexOfHelpers.cs +++ b/Recyclable.Collections/RecyclableLongList.IndexOfHelpers.cs @@ -28,7 +28,7 @@ namespace Recyclable.Collections long index = Array.IndexOf(list._memoryBlocks[blockIndex], itemToFind, 0, list._blockSize); if (index >= 0 && (!context._isItemFound || index < context.FoundItemIndex)) { - ExchangeFoundItemIndexIfLower(context, blockIndex, checked((long)blockIndex << list._blockSizePow2BitShift) + index); + ExchangeFoundItemIndexIfLower(context, blockIndex, ((long)blockIndex << list._blockSizePow2BitShift) + index); return; } else if (context._isItemFound) @@ -41,7 +41,7 @@ namespace Recyclable.Collections index = Array.IndexOf(list._memoryBlocks[blockIndex + 1], itemToFind, 0, list._blockSize); if (index >= 0) { - ExchangeFoundItemIndexIfLower(context, blockIndex + 1, checked((long)(blockIndex + 1) << list._blockSizePow2BitShift) + index); + ExchangeFoundItemIndexIfLower(context, blockIndex + 1, ((long)(blockIndex + 1) << list._blockSizePow2BitShift) + index); return; } else if (context._isItemFound) @@ -56,7 +56,7 @@ namespace Recyclable.Collections index = Array.IndexOf(list._memoryBlocks[blockIndex + 2], itemToFind, 0, list._blockSize); if (index >= 0 && (!context._isItemFound || index < context.FoundItemIndex)) { - ExchangeFoundItemIndexIfLower(context, blockIndex + 2, checked((long)(blockIndex + 2) << list._blockSizePow2BitShift) + index); + ExchangeFoundItemIndexIfLower(context, blockIndex + 2, ((long)(blockIndex + 2) << list._blockSizePow2BitShift) + index); return; } else if (context._isItemFound) @@ -71,7 +71,7 @@ namespace Recyclable.Collections index = Array.IndexOf(list._memoryBlocks[blockIndex + 3], itemToFind, 0, list._blockSize); if (!context._isItemFound && index >= 0) { - ExchangeFoundItemIndexIfLower(context, blockIndex + 3, checked((long)(blockIndex + 3) << list._blockSizePow2BitShift) + index); + ExchangeFoundItemIndexIfLower(context, blockIndex + 3, ((long)(blockIndex + 3) << list._blockSizePow2BitShift) + index); } #endif @@ -81,7 +81,7 @@ namespace Recyclable.Collections index = Array.IndexOf(list._memoryBlocks[blockIndex + 4], itemToFind, 0, list._blockSize); if (!context._isItemFound && index >= 0 && (!context._isItemFound || index < context.FoundItemIndex)) { - ExchangeFoundItemIndexIfLower(context, blockIndex + 4, checked((long)(blockIndex + 4) << list._blockSizePow2BitShift) + index); + ExchangeFoundItemIndexIfLower(context, blockIndex + 4, ((long)(blockIndex + 4) << list._blockSizePow2BitShift) + index); } #endif @@ -91,7 +91,7 @@ namespace Recyclable.Collections index = Array.IndexOf(list._memoryBlocks[blockIndex + 5], itemToFind, 0, list._blockSize); if (!context._isItemFound && index >= 0 && (!context._isItemFound || index < context.FoundItemIndex)) { - ExchangeFoundItemIndexIfLower(context, blockIndex + 5, checked((long)(blockIndex + 5) << list._blockSizePow2BitShift) + index); + ExchangeFoundItemIndexIfLower(context, blockIndex + 5, ((long)(blockIndex + 5) << list._blockSizePow2BitShift) + index); } #endif @@ -101,7 +101,7 @@ namespace Recyclable.Collections index = Array.IndexOf(list._memoryBlocks[blockIndex + 6], itemToFind, 0, list._blockSize); if (!context._isItemFound && index >= 0 && (!context._isItemFound || index < context.FoundItemIndex)) { - ExchangeFoundItemIndexIfLower(context, blockIndex + 6, checked((long)(blockIndex + 6) << list._blockSizePow2BitShift) + index); + ExchangeFoundItemIndexIfLower(context, blockIndex + 6, ((long)(blockIndex + 6) << list._blockSizePow2BitShift) + index); } #endif @@ -111,7 +111,7 @@ namespace Recyclable.Collections index = Array.IndexOf(list._memoryBlocks[blockIndex + 7], itemToFind, 0, list._blockSize); if (!context._isItemFound && index >= 0 && (!context._isItemFound || index < context.FoundItemIndex)) { - ExchangeFoundItemIndexIfLower(context, blockIndex + 7, checked((long)(blockIndex + 7) << list._blockSizePow2BitShift) + index); + ExchangeFoundItemIndexIfLower(context, blockIndex + 7, ((long)(blockIndex + 7) << list._blockSizePow2BitShift) + index); } #endif @@ -157,7 +157,7 @@ namespace Recyclable.Collections long index = Array.IndexOf(list._memoryBlocks[blockIndex], itemToFind, 0, list._blockSize); if (!context._isItemFound && index >= 0) { - ExchangeFoundItemIndexIfLower(context, blockIndex, checked((long)blockIndex << list._blockSizePow2BitShift) + index); + ExchangeFoundItemIndexIfLower(context, blockIndex, ((long)blockIndex << list._blockSizePow2BitShift) + index); } } catch (Exception e) @@ -214,7 +214,7 @@ namespace Recyclable.Collections // & WAS SLOWER // int blockSize = _blockSize; // & WAS SLOWER - // while (checked((long)blockIndex << list._blockSizePow2BitShift) + itemIndex > step) + // while (((long)blockIndex << list._blockSizePow2BitShift) + itemIndex > step) //long blockSize = checked((long)list._blockSize << 1); int lastBlockWithData = list._lastBlockWithData - BlocksForEachTask; while (blockIndex < lastBlockWithData) @@ -265,7 +265,7 @@ namespace Recyclable.Collections int itemIndex = Array.IndexOf(list._memoryBlocks[list._lastBlockWithData], item, 0, list._nextItemIndex > 0 ? list._nextItemIndex : list._blockSize); if (!context._isItemFound && itemIndex >= 0) { - ExchangeFoundItemIndexIfLower(context, blockIndex, checked((long)blockIndex << list._blockSizePow2BitShift) + itemIndex); + ExchangeFoundItemIndexIfLower(context, blockIndex, ((long)blockIndex << list._blockSizePow2BitShift) + itemIndex); } } @@ -300,14 +300,14 @@ namespace Recyclable.Collections int itemIndex; // & WAS SLOWER //int lastBlockWithData = list._lastBlockWithData; - Span memoryBlocksSpan = new(list._memoryBlocks, 0, list._lastBlockWithData + 1); + ReadOnlySpan memoryBlocksSpan = new(list._memoryBlocks, 0, list._lastBlockWithData + 1); int blockIndex; for (blockIndex = 1; blockIndex < list._lastBlockWithData; blockIndex += 4) { itemIndex = Array.IndexOf(memoryBlocksSpan[blockIndex], item, 0, list._blockSize); if (itemIndex >= 0) { - return itemIndex + checked((long)blockIndex << list._blockSizePow2BitShift); + return itemIndex + (long)blockIndex << list._blockSizePow2BitShift; } if (blockIndex + 1 < list._lastBlockWithData) @@ -315,7 +315,7 @@ namespace Recyclable.Collections itemIndex = Array.IndexOf(memoryBlocksSpan[blockIndex + 1], item, 0, list._blockSize); if (itemIndex >= 0) { - return itemIndex + checked((long)(blockIndex + 1)<< list._blockSizePow2BitShift); + return itemIndex + (long)(blockIndex + 1)<< list._blockSizePow2BitShift; } if (blockIndex + 2 < list._lastBlockWithData) @@ -323,7 +323,7 @@ namespace Recyclable.Collections itemIndex = Array.IndexOf(memoryBlocksSpan[blockIndex + 2], item, 0, list._blockSize); if (itemIndex >= 0) { - return itemIndex + checked((long)(blockIndex + 2)<< list._blockSizePow2BitShift); + return itemIndex + (long)(blockIndex + 2)<< list._blockSizePow2BitShift; } if (blockIndex + 3 < list._lastBlockWithData) @@ -331,7 +331,7 @@ namespace Recyclable.Collections itemIndex = Array.IndexOf(memoryBlocksSpan[blockIndex + 3], item, 0, list._blockSize); if (itemIndex >= 0) { - return itemIndex + checked((long)(blockIndex + 3)<< list._blockSizePow2BitShift); + return itemIndex + (long)(blockIndex + 3)<< list._blockSizePow2BitShift; } } } @@ -342,7 +342,7 @@ namespace Recyclable.Collections ? Array.IndexOf(memoryBlocksSpan[list._lastBlockWithData], item, 0, list._nextItemIndex) : Array.IndexOf(memoryBlocksSpan[list._lastBlockWithData], item, 0, list._blockSize); - return itemIndex >= 0 ? itemIndex + checked((long)list._lastBlockWithData << list._blockSizePow2BitShift) : RecyclableDefaults.ItemNotFoundIndexLong; + return itemIndex >= 0 ? itemIndex + (long)list._lastBlockWithData << list._blockSizePow2BitShift : RecyclableDefaults.ItemNotFoundIndexLong; } } } diff --git a/Recyclable.Collections/RecyclableLongList.cs b/Recyclable.Collections/RecyclableLongList.cs index 818ceb4..b2cf1c0 100644 --- a/Recyclable.Collections/RecyclableLongList.cs +++ b/Recyclable.Collections/RecyclableLongList.cs @@ -250,7 +250,7 @@ namespace Recyclable.Collections get => _memoryBlocks[index >> _blockSizePow2BitShift][index & _blockSizeMinus1]; set { - new Span(_memoryBlocks[checked((int)(index >> _blockSizePow2BitShift))])[checked((int)(index & _blockSizeMinus1))] = value; + new Span(_memoryBlocks[(int)(index >> _blockSizePow2BitShift)])[(int)(index & _blockSizeMinus1)] = value; _version++; } } @@ -339,10 +339,10 @@ namespace Recyclable.Collections if (_nextItemBlockIndex == 0 || (_nextItemIndex == 0 && _nextItemBlockIndex == 1)) { - return Array.IndexOf(_memoryBlocks[0], item, 0, checked((int)_longCount)) >= 0; + return Array.IndexOf(_memoryBlocks[0], item, 0, (int)_longCount) >= 0; } - Span memoryBlocksSpan = new(_memoryBlocks); + ReadOnlySpan memoryBlocksSpan = _memoryBlocks; int lastBlockIndex = _lastBlockWithData; for (int blockIndex = 0; blockIndex < lastBlockIndex; blockIndex++) { @@ -387,7 +387,7 @@ namespace Recyclable.Collections if (_longCount > _blockSize) { itemIndex = Array.IndexOf(_memoryBlocks[1], item, 0, (int)Math.Min(_blockSize, _longCount - _blockSize)); - return itemIndex >= 0 ? _blockSize + itemIndex : (int)IndexOfHelpers.IndexOfParallel(this, item); + return itemIndex >= 0 ? _blockSize + itemIndex : checked((int)IndexOfHelpers.IndexOfParallel(this, item)); } else { diff --git a/Recyclable.Collections/RecyclableQueue.Helpers.cs b/Recyclable.Collections/RecyclableQueue.Helpers.cs index 45c0edf..bce03fc 100644 --- a/Recyclable.Collections/RecyclableQueue.Helpers.cs +++ b/Recyclable.Collections/RecyclableQueue.Helpers.cs @@ -18,28 +18,28 @@ namespace Recyclable.Collections [MethodImpl(MethodImplOptions.AggressiveInlining)] internal static void CopyTo(RecyclableList arrays, long startingIndex, int blockSize, int lastBlockSize, T[] destinationArray, int destinationArrayIndex) { - Span arrayMemory = destinationArray.AsSpan(); + Span arrayMemory = destinationArray; arrayMemory = arrayMemory[destinationArrayIndex..]; // TODO: Convert "/" & "%" to bit-shifting int startingArrayIndex = (int)(startingIndex / blockSize); startingIndex %= blockSize; if (arrays._count > 0) { - ReadOnlySpan sourceMemory = arrays[0].AsSpan(); + ReadOnlySpan sourceMemory = arrays[0]; var maxToCopy = (int)Math.Min(blockSize - startingIndex, arrayMemory.Length); if (arrays._count == 1) { maxToCopy = Math.Min(maxToCopy, lastBlockSize); } - sourceMemory = sourceMemory[(int)startingIndex..maxToCopy]; + sourceMemory = sourceMemory[checked((int)startingIndex)..maxToCopy]; sourceMemory.CopyTo(arrayMemory); arrayMemory = arrayMemory[maxToCopy..]; } for (var arrayIdx = startingArrayIndex + 1; arrayIdx < arrays._count - 1 && arrayMemory.Length > 0; arrayIdx++) { - ReadOnlySpan sourceMemory = arrays[arrayIdx].AsSpan(); + ReadOnlySpan sourceMemory = arrays[arrayIdx]; var maxToCopy = Math.Min(blockSize, arrayMemory.Length); sourceMemory = sourceMemory[..maxToCopy]; sourceMemory.CopyTo(arrayMemory); @@ -48,7 +48,7 @@ namespace Recyclable.Collections if (arrays._count > 1 && arrayMemory.Length > 0) { - ReadOnlySpan sourceMemory = arrays[^1].AsSpan(); + ReadOnlySpan sourceMemory = arrays[^1]; var maxToCopy = Math.Min(lastBlockSize, arrayMemory.Length); sourceMemory = sourceMemory[..maxToCopy]; sourceMemory.CopyTo(arrayMemory); @@ -94,7 +94,7 @@ namespace Recyclable.Collections for (var arrayIdx = 0; arrayIdx < arrays._count; arrayIdx++) { var array = arrays[arrayIdx]; - Span arrayMemory = array.AsSpan(); + ReadOnlySpan arrayMemory = array; for (int memoryIdx = 0; memoryIdx < arrayMemory.Length; memoryIdx++) { if (comparer.Equals(arrayMemory[memoryIdx], item)) diff --git a/Recyclable.Collections/RecyclableQueue.cs b/Recyclable.Collections/RecyclableQueue.cs index 7e12a09..bc9e910 100644 --- a/Recyclable.Collections/RecyclableQueue.cs +++ b/Recyclable.Collections/RecyclableQueue.cs @@ -76,7 +76,7 @@ namespace Recyclable.Collections public int Count { - get => (int)LongCount; + get => checked((int)LongCount); set => LongCount = value; } @@ -167,11 +167,11 @@ namespace Recyclable.Collections #pragma warning disable CS0618 public bool Contains(T item) => RecyclableQueueHelpers.Contains(Memory, item); - public void CopyTo(T[] array, int arrayIndex) => RecyclableQueueHelpers.CopyTo(Memory, RemovedCount, BlockSize, (int)(LongCount % BlockSize), array, arrayIndex); + public void CopyTo(T[] array, int arrayIndex) => RecyclableQueueHelpers.CopyTo(Memory, RemovedCount, BlockSize, checked((int)(LongCount % BlockSize)), array, arrayIndex); public IEnumerable Enumerate() => RecyclableQueueHelpers.Enumerate(Memory, BlockSize, LongCount); public IEnumerator GetEnumerator() => RecyclableQueueHelpers.Enumerate(Memory, BlockSize, LongCount).GetEnumerator(); IEnumerator IEnumerable.GetEnumerator() => RecyclableQueueHelpers.Enumerate(Memory, BlockSize, LongCount).GetEnumerator(); - public int IndexOf(T item) => (int)GetRelativeIndex(RecyclableQueueHelpers.LongIndexOf(Memory, BlockSize, item, _equalityComparer)); + public int IndexOf(T item) => checked((int)GetRelativeIndex(RecyclableQueueHelpers.LongIndexOf(Memory, BlockSize, item, _equalityComparer))); public long LongIndexOf(T item) => GetRelativeIndex(RecyclableQueueHelpers.LongIndexOf(Memory, BlockSize, item, _equalityComparer)); #pragma warning restore CS0618