diff --git a/Recyclable.Collections/RecyclableList.Enumerator.cs b/Recyclable.Collections/RecyclableList.Enumerator.cs index acaae28..7a0b603 100644 --- a/Recyclable.Collections/RecyclableList.Enumerator.cs +++ b/Recyclable.Collections/RecyclableList.Enumerator.cs @@ -6,9 +6,10 @@ namespace Recyclable.Collections { public partial class RecyclableList { - [StructLayout(LayoutKind.Sequential, Pack = 1)] - public struct Enumerator : IEnumerator - { + [StructLayout(LayoutKind.Sequential, Pack = 1)] + [VersionedCollectionsGenerator.CloneForVersioned] + public struct Enumerator : IEnumerator + { private static readonly bool _isReferenceType = !typeof(T).IsValueType; private int _currentItemIndex; diff --git a/Recyclable.Collections/RecyclableList.Extensions.cs b/Recyclable.Collections/RecyclableList.Extensions.cs index d10ac29..bf55211 100644 --- a/Recyclable.Collections/RecyclableList.Extensions.cs +++ b/Recyclable.Collections/RecyclableList.Extensions.cs @@ -3,8 +3,9 @@ using System.Runtime.CompilerServices; namespace Recyclable.Collections { - public static class RecyclableListExtensions - { + [VersionedCollectionsGenerator.GenerateVersioned] + public static class RecyclableListExtensions + { [MethodImpl(MethodImplOptions.AggressiveInlining)] public static RecyclableList ToRecyclableList(this Array values) => new(values); diff --git a/Recyclable.Collections/RecyclableList.VersionedEnumerator.cs b/Recyclable.Collections/RecyclableList.VersionedEnumerator.cs index 5e729f7..2623ebd 100644 --- a/Recyclable.Collections/RecyclableList.VersionedEnumerator.cs +++ b/Recyclable.Collections/RecyclableList.VersionedEnumerator.cs @@ -6,11 +6,13 @@ namespace Recyclable.Collections { public partial class RecyclableList : IRecyclableVersionedList { - VersionedEnumerator IRecyclableVersionedList.GetEnumerator() => new(this); + [VersionedCollectionsGenerator.CloneForVersioned] + VersionedEnumerator IRecyclableVersionedList.GetEnumerator() => new(this); - [StructLayout(LayoutKind.Sequential, Pack = 1)] - public struct VersionedEnumerator : IEnumerator - { + [StructLayout(LayoutKind.Sequential, Pack = 1)] + [VersionedCollectionsGenerator.CloneForVersioned] + public struct VersionedEnumerator : IEnumerator + { private int _currentItemIndex; private readonly ulong _enumeratorVersion; private readonly RecyclableList _list; diff --git a/Recyclable.Collections/RecyclableList.cs b/Recyclable.Collections/RecyclableList.cs index 5a46ab2..8f068dc 100644 --- a/Recyclable.Collections/RecyclableList.cs +++ b/Recyclable.Collections/RecyclableList.cs @@ -363,14 +363,29 @@ namespace Recyclable.Collections #endif } - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public Enumerator GetEnumerator() => new(this); + [MethodImpl(MethodImplOptions.AggressiveInlining)] + [VersionedCollectionsGenerator.CloneForVersioned] +#if WITH_VERSIONING + public VersionedEnumerator GetEnumerator() => new(this); +#else + public Enumerator GetEnumerator() => new(this); +#endif - [MethodImpl(MethodImplOptions.AggressiveInlining)] - IEnumerator IEnumerable.GetEnumerator() => new Enumerator(this); + [MethodImpl(MethodImplOptions.AggressiveInlining)] + [VersionedCollectionsGenerator.CloneForVersioned] +#if WITH_VERSIONING + IEnumerator IEnumerable.GetEnumerator() => new VersionedEnumerator(this); +#else + IEnumerator IEnumerable.GetEnumerator() => new Enumerator(this); +#endif - [MethodImpl(MethodImplOptions.AggressiveInlining)] - IEnumerator IEnumerable.GetEnumerator() => new Enumerator(this); + [MethodImpl(MethodImplOptions.AggressiveInlining)] + [VersionedCollectionsGenerator.CloneForVersioned] +#if WITH_VERSIONING + IEnumerator IEnumerable.GetEnumerator() => new VersionedEnumerator(this); +#else + IEnumerator IEnumerable.GetEnumerator() => new Enumerator(this); +#endif public void Dispose() { diff --git a/Recyclable.Collections/RecyclableLongList.AddRange.cs b/Recyclable.Collections/RecyclableLongList.AddRange.cs index cec751b..9e1bd79 100644 --- a/Recyclable.Collections/RecyclableLongList.AddRange.cs +++ b/Recyclable.Collections/RecyclableLongList.AddRange.cs @@ -126,7 +126,9 @@ namespace Recyclable.Collections } targetList._capacity = capacity; - targetList._version++; + #if WITH_VERSIONING +targetList._version++; +#endif return; } @@ -186,10 +188,13 @@ namespace Recyclable.Collections targetList._nextItemBlockIndex = targetBlockIdx; targetList._nextItemIndex = targetItemIdx; targetList._lastBlockWithData = targetBlockIdx - (targetItemIdx > 0 ? 0 : 1); - targetList._version++; + #if WITH_VERSIONING +targetList._version++; +#endif } - public static void AddRange(this RecyclableLongList targetList, in Array items) + [VersionedCollectionsGenerator.RewriteForVersioned] + public static void AddRange(this RecyclableLongList targetList, in Array items) { if (items.LongLength == 0) { @@ -240,7 +245,9 @@ namespace Recyclable.Collections } targetList._longCount = targetCapacity; - targetList._version++; + #if WITH_VERSIONING +targetList._version++; +#endif } public static void AddRange(this RecyclableLongList targetList, ICollection items) @@ -305,7 +312,9 @@ namespace Recyclable.Collections RecyclableArrayPool.ReturnShared(itemsBuffer, RecyclableLongList._needsClearing); } - targetList._version++; + #if WITH_VERSIONING +targetList._version++; +#endif } public static void AddRange(this RecyclableLongList targetList, ICollection items) @@ -373,7 +382,9 @@ namespace Recyclable.Collections RecyclableArrayPool.ReturnShared(itemsBuffer, RecyclableLongList._needsClearing); } - targetList._version++; + #if WITH_VERSIONING +targetList._version++; +#endif } public static void AddRange(this RecyclableLongList targetList, IEnumerable source) @@ -616,7 +627,9 @@ namespace Recyclable.Collections targetList._nextItemBlockIndex = targetBlockIndex; targetList._longCount = targetCapacity; targetList._lastBlockWithData = targetBlockIndex - (targetList._nextItemIndex > 0 ? 0 : 1); - targetList._version++; + #if WITH_VERSIONING +targetList._version++; +#endif } public static void AddRange(this RecyclableLongList targetList, ReadOnlySpan items) @@ -671,7 +684,9 @@ namespace Recyclable.Collections targetList._longCount = targetCapacity; targetList._lastBlockWithData = targetBlockIndex; - targetList._version++; + #if WITH_VERSIONING +targetList._version++; +#endif } public static void AddRange(this RecyclableLongList targetList, RecyclableList items) @@ -728,7 +743,9 @@ namespace Recyclable.Collections } targetList._longCount = targetCapacity; - targetList._version++; + #if WITH_VERSIONING +targetList._version++; +#endif } public static void AddRange(this RecyclableLongList targetList, RecyclableLongList items) @@ -801,7 +818,9 @@ namespace Recyclable.Collections } targetList._longCount = targetCapacity; - targetList._version++; + #if WITH_VERSIONING +targetList._version++; +#endif } public static void AddRange(this RecyclableLongList targetList, Span items) @@ -856,7 +875,9 @@ namespace Recyclable.Collections targetList._longCount = targetCapacity; targetList._lastBlockWithData = targetBlockIndex; - targetList._version++; + #if WITH_VERSIONING +targetList._version++; +#endif } public static void AddRange(this RecyclableLongList targetList, in T[] items) @@ -912,7 +933,9 @@ namespace Recyclable.Collections targetList._longCount = targetCapacity; targetList._lastBlockWithData = targetBlockIndex; - targetList._version++; + #if WITH_VERSIONING +targetList._version++; +#endif } [MethodImpl(MethodImplOptions.NoInlining | MethodImplOptions.AggressiveOptimization)] @@ -954,7 +977,9 @@ namespace Recyclable.Collections targetList._nextItemBlockIndex = blockIndex; targetList._nextItemIndex = itemIndex; targetList._lastBlockWithData = blockIndex - (itemIndex > 0 ? 0 : 1); - targetList._version++; + #if WITH_VERSIONING +targetList._version++; +#endif } [MethodImpl(MethodImplOptions.NoInlining | MethodImplOptions.AggressiveOptimization)] @@ -999,7 +1024,9 @@ namespace Recyclable.Collections targetList._nextItemBlockIndex = blockIndex; targetList._nextItemIndex = itemIndex; targetList._lastBlockWithData = blockIndex - (itemIndex > 0 ? 0 : 1); - targetList._version++; + #if WITH_VERSIONING +targetList._version++; +#endif } [MethodImpl(MethodImplOptions.NoInlining | MethodImplOptions.AggressiveOptimization)] @@ -1038,7 +1065,9 @@ namespace Recyclable.Collections targetList._nextItemBlockIndex = blockIndex; targetList._nextItemIndex = itemIndex; targetList._lastBlockWithData = blockIndex - (itemIndex > 0 ? 0 : 1); - targetList._version++; + #if WITH_VERSIONING +targetList._version++; +#endif } [MethodImpl(MethodImplOptions.NoInlining | MethodImplOptions.AggressiveOptimization)] @@ -1082,7 +1111,9 @@ namespace Recyclable.Collections targetList._nextItemBlockIndex = blockIndex; targetList._nextItemIndex = itemIndex; targetList._lastBlockWithData = blockIndex - (itemIndex > 0 ? 0 : 1); - targetList._version++; + #if WITH_VERSIONING +targetList._version++; +#endif } [MethodImpl(MethodImplOptions.NoInlining | MethodImplOptions.AggressiveOptimization)] @@ -1121,7 +1152,9 @@ namespace Recyclable.Collections targetList._nextItemBlockIndex = blockIndex; targetList._nextItemIndex = itemIndex; targetList._lastBlockWithData = blockIndex - (itemIndex > 0 ? 0 : 1); - targetList._version++; + #if WITH_VERSIONING +targetList._version++; +#endif } [MethodImpl(MethodImplOptions.NoInlining | MethodImplOptions.AggressiveOptimization)] @@ -1165,7 +1198,9 @@ namespace Recyclable.Collections targetList._nextItemBlockIndex = blockIndex; targetList._nextItemIndex = itemIndex; targetList._lastBlockWithData = blockIndex - (itemIndex > 0 ? 0 : 1); - targetList._version++; + #if WITH_VERSIONING +targetList._version++; +#endif } [MethodImpl(MethodImplOptions.NoInlining | MethodImplOptions.AggressiveOptimization)] @@ -1208,7 +1243,9 @@ namespace Recyclable.Collections targetList._nextItemBlockIndex = blockIndex; targetList._nextItemIndex = itemIndex; targetList._lastBlockWithData = blockIndex - (itemIndex > 0 ? 0 : 1); - targetList._version++; + #if WITH_VERSIONING +targetList._version++; +#endif } [MethodImpl(MethodImplOptions.NoInlining | MethodImplOptions.AggressiveOptimization)] @@ -1248,7 +1285,9 @@ namespace Recyclable.Collections targetList._nextItemBlockIndex = blockIndex; targetList._nextItemIndex = itemIndex; targetList._lastBlockWithData = blockIndex - (itemIndex > 0 ? 0 : 1); - targetList._version++; + #if WITH_VERSIONING +targetList._version++; +#endif } } } diff --git a/Recyclable.Collections/RecyclableLongList.Compatibility.List.Sorted.cs b/Recyclable.Collections/RecyclableLongList.Compatibility.List.Sorted.cs index 7e28d19..885f574 100644 --- a/Recyclable.Collections/RecyclableLongList.Compatibility.List.Sorted.cs +++ b/Recyclable.Collections/RecyclableLongList.Compatibility.List.Sorted.cs @@ -10,19 +10,25 @@ namespace Recyclable.Collections public static void Sort(this RecyclableLongList list) { QuickSortExtensions.QuickSort(list); +#if WITH_VERSIONING list._version++; +#endif } public static void Sort(this RecyclableLongList list, Comparison comparison) { QuickSortExtensions.QuickSort(list, new ComparisonToComparerAdapter(comparison), new SystemRandomNumberGenerator()); +#if WITH_VERSIONING list._version++; +#endif } public static void Sort(this RecyclableLongList list, IComparer? comparer) { QuickSortExtensions.QuickSort(list, comparer ?? Comparer.Default, new SystemRandomNumberGenerator()); +#if WITH_VERSIONING list._version++; +#endif } public static void Sort(this RecyclableLongList list, long index, long count, IComparer? comparer) @@ -33,7 +39,9 @@ namespace Recyclable.Collections } QuickSortExtensions.QuickSort(list, (int)index, (int)(index + count - 1), comparer ?? Comparer.Default, new SystemRandomNumberGenerator()); +#if WITH_VERSIONING list._version++; +#endif } } } diff --git a/Recyclable.Collections/RecyclableLongList.Enumerator.cs b/Recyclable.Collections/RecyclableLongList.Enumerator.cs index 353f2d3..b8100c7 100644 --- a/Recyclable.Collections/RecyclableLongList.Enumerator.cs +++ b/Recyclable.Collections/RecyclableLongList.Enumerator.cs @@ -5,8 +5,9 @@ namespace Recyclable.Collections { public partial class RecyclableLongList { - public struct Enumerator : IEnumerator - { + [VersionedCollectionsGenerator.CloneForVersioned] + public struct Enumerator : IEnumerator + { #nullable disable private static readonly T _default = default; #nullable restore diff --git a/Recyclable.Collections/RecyclableLongList.Extensions.cs b/Recyclable.Collections/RecyclableLongList.Extensions.cs index 5f24356..fc89683 100644 --- a/Recyclable.Collections/RecyclableLongList.Extensions.cs +++ b/Recyclable.Collections/RecyclableLongList.Extensions.cs @@ -3,8 +3,9 @@ using System.Runtime.CompilerServices; namespace Recyclable.Collections { - public static class RecyclableLongListExtensions - { + [VersionedCollectionsGenerator.GenerateVersioned] + public static class RecyclableLongListExtensions + { [MethodImpl(MethodImplOptions.AggressiveInlining)] public static RecyclableLongList ToRecyclableLongList(this Array values, int minBlockSize = RecyclableDefaults.BlockSize) => new(values, minBlockSize); diff --git a/Recyclable.Collections/RecyclableLongList.VersionedEnumerator.cs b/Recyclable.Collections/RecyclableLongList.VersionedEnumerator.cs index ad86d10..cbb3e92 100644 --- a/Recyclable.Collections/RecyclableLongList.VersionedEnumerator.cs +++ b/Recyclable.Collections/RecyclableLongList.VersionedEnumerator.cs @@ -5,11 +5,14 @@ namespace Recyclable.Collections { public partial class RecyclableLongList : IRecyclableVersionedLongList { - public VersionedEnumerator GetVersionedEnumerator() => new(this); - VersionedEnumerator IRecyclableVersionedLongList.GetEnumerator() => new(this); + [VersionedCollectionsGenerator.CloneForVersioned] + public VersionedEnumerator GetVersionedEnumerator() => new(this); + [VersionedCollectionsGenerator.CloneForVersioned] + VersionedEnumerator IRecyclableVersionedLongList.GetEnumerator() => new(this); - public struct VersionedEnumerator : IEnumerator - { + [VersionedCollectionsGenerator.CloneForVersioned] + public struct VersionedEnumerator : IEnumerator + { #nullable disable private static readonly T _default = default; #nullable restore diff --git a/Recyclable.Collections/RecyclableLongList.cs b/Recyclable.Collections/RecyclableLongList.cs index a2daf6d..a0ebb71 100644 --- a/Recyclable.Collections/RecyclableLongList.cs +++ b/Recyclable.Collections/RecyclableLongList.cs @@ -9,7 +9,8 @@ using Recyclable.Collections.Pools; namespace Recyclable.Collections { - public partial class RecyclableLongList : IList, IReadOnlyList, IDisposable + [VersionedCollectionsGenerator.GenerateVersioned] + public partial class RecyclableLongList : IList, IReadOnlyList, IDisposable { private static readonly bool _defaultIsNull = default(T) == null; internal static readonly bool _needsClearing = !typeof(T).IsValueType; @@ -25,7 +26,7 @@ namespace Recyclable.Collections #nullable restore internal int _nextItemBlockIndex; internal int _nextItemIndex; - internal ulong _version; + internal ulong _version; public int BlockSize => _blockSize; public int BlockSizeMinus1 => _blockSizeMinus1; @@ -35,15 +36,19 @@ namespace Recyclable.Collections get => _capacity; private set { - _capacity = value; - _version++; - if (_capacity != value) - { - _capacity = Helpers.Resize(this, _blockSize, _blockSizePow2BitShift, checked((long)BitOperations.RoundUpToPowerOf2((ulong)value))); - _version++; - } - } - } + _capacity = value; +#if WITH_VERSIONING + _version++; +#endif + if (_capacity != value) + { + _capacity = Helpers.Resize(this, _blockSize, _blockSizePow2BitShift, checked((long)BitOperations.RoundUpToPowerOf2((ulong)value))); +#if WITH_VERSIONING + _version++; +#endif + } + } + } public int Count => checked((int)_longCount); public bool IsReadOnly => false; @@ -51,7 +56,8 @@ namespace Recyclable.Collections public long LongCount => _longCount; public int NextItemBlockIndex => _nextItemBlockIndex; public int NextItemIndex => _nextItemIndex; - public ulong Version => _version; + [VersionedCollectionsGenerator.CloneForVersioned] + public ulong Version => _version; public RecyclableLongList(int minBlockSize = RecyclableDefaults.BlockSize, long initialCapacity = RecyclableDefaults.InitialCapacity) { @@ -251,20 +257,24 @@ namespace Recyclable.Collections get => _memoryBlocks[index >> _blockSizePow2BitShift][index & _blockSizeMinus1]; set { - new Span(_memoryBlocks[(int)(index >> _blockSizePow2BitShift)])[(int)(index & _blockSizeMinus1)] = value; - _version++; - } - } + new Span(_memoryBlocks[(int)(index >> _blockSizePow2BitShift)])[(int)(index & _blockSizeMinus1)] = value; +#if WITH_VERSIONING + _version++; +#endif + } + } public T this[int index] { get => _memoryBlocks[index >> _blockSizePow2BitShift][index & _blockSizeMinus1]; set { - new Span(_memoryBlocks[index >> _blockSizePow2BitShift])[index & _blockSizeMinus1] = value; - _version++; - } - } + new Span(_memoryBlocks[index >> _blockSizePow2BitShift])[index & _blockSizeMinus1] = value; +#if WITH_VERSIONING + _version++; +#endif + } + } public T[][] AsArray => _memoryBlocks; @@ -292,9 +302,11 @@ namespace Recyclable.Collections _lastBlockWithData++; } - _longCount++; - _version++; - } + _longCount++; +#if WITH_VERSIONING + _version++; +#endif + } public void Clear() { @@ -326,9 +338,11 @@ namespace Recyclable.Collections _nextItemBlockIndex = 0; _nextItemIndex = 0; _lastBlockWithData = RecyclableDefaults.ItemNotFoundIndex; - _longCount = 0; - _version++; - } + _longCount = 0; +#if WITH_VERSIONING + _version++; +#endif + } [MethodImpl(MethodImplOptions.AggressiveInlining)] public bool Contains(T item) @@ -358,9 +372,24 @@ namespace Recyclable.Collections public void CopyTo(T[] array, int arrayIndex) => Helpers.CopyTo(_memoryBlocks, 0, _blockSize, _longCount, array, arrayIndex); - public Enumerator GetEnumerator() => new(this); - IEnumerator IEnumerable.GetEnumerator() => new Enumerator(this); - IEnumerator IEnumerable.GetEnumerator() => new Enumerator(this); + [VersionedCollectionsGenerator.CloneForVersioned] +#if WITH_VERSIONING + public VersionedEnumerator GetEnumerator() => new(this); +#else + public Enumerator GetEnumerator() => new(this); +#endif + [VersionedCollectionsGenerator.CloneForVersioned] +#if WITH_VERSIONING + IEnumerator IEnumerable.GetEnumerator() => new VersionedEnumerator(this); +#else + IEnumerator IEnumerable.GetEnumerator() => new Enumerator(this); +#endif + [VersionedCollectionsGenerator.CloneForVersioned] +#if WITH_VERSIONING + IEnumerator IEnumerable.GetEnumerator() => new VersionedEnumerator(this); +#else + IEnumerator IEnumerable.GetEnumerator() => new Enumerator(this); +#endif [MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)] public int IndexOf(T item) @@ -433,8 +462,10 @@ namespace Recyclable.Collections _lastBlockWithData++; } - _version++; - } +#if WITH_VERSIONING + _version++; +#endif + } public void Insert(long index, T item) { @@ -472,8 +503,10 @@ namespace Recyclable.Collections _lastBlockWithData++; } - _version++; - } +#if WITH_VERSIONING + _version++; +#endif + } [MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)] public long LongIndexOf(T item) @@ -543,9 +576,11 @@ namespace Recyclable.Collections #nullable restore } - _version++; - return true; - } +#if WITH_VERSIONING + _version++; +#endif + return true; + } return false; } @@ -585,8 +620,10 @@ namespace Recyclable.Collections #nullable restore } - _version++; - } +#if WITH_VERSIONING + _version++; +#endif + } [MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)] public void RemoveAt(long index) @@ -623,8 +660,10 @@ namespace Recyclable.Collections #nullable restore } - _version++; - } +#if WITH_VERSIONING + _version++; +#endif + } public void RemoveBlock(int index) { @@ -644,17 +683,21 @@ namespace Recyclable.Collections _nextItemBlockIndex--; } - _lastBlockWithData--; - _version++; - } + _lastBlockWithData--; +#if WITH_VERSIONING + _version++; +#endif + } - public void Dispose() - { - _version++; - if (_capacity > 0) - { - Clear(); - if (_memoryBlocks.Length >= RecyclableDefaults.MinPooledArrayLength) + public void Dispose() + { +#if WITH_VERSIONING + _version++; +#endif + if (_capacity > 0) + { + Clear(); + if (_memoryBlocks.Length >= RecyclableDefaults.MinPooledArrayLength) { // If anything, it has been already cleared by .Clear(), Remove() or RemoveAt() methods, as the list was modified / disposed. RecyclableArrayPool.ReturnShared(_memoryBlocks, false);