diff --git a/Recyclable.Collections/RecyclableLongList.Enumerator.cs b/Recyclable.Collections/RecyclableLongList.Enumerator.cs index 7f1ee37..818ea1f 100644 --- a/Recyclable.Collections/RecyclableLongList.Enumerator.cs +++ b/Recyclable.Collections/RecyclableLongList.Enumerator.cs @@ -1,149 +1,198 @@ using System.Collections; +using System.Runtime.CompilerServices; namespace Recyclable.Collections { - public sealed class RecyclableLongListEnumerator : IEnumerator + public partial class RecyclableLongList { - public static void ThrowListModifiedException() => throw new InvalidOperationException("Can't move to the next item, because the collection was modified. You must restart the enumeration by calling Reset(), if you want to enumerate the collection again"); - - private int _blockSize; - private int _blockSizeMinus1; - private int _currentBlockIndex = 0; - private int _currentIndex = RecyclableDefaults.ItemNotFoundIndex; - private int _lastBlockWithData; - private RecyclableLongList? _list; - private RecyclableCollectionVersion? _listVersion; - private T[][] _memoryBlocks; - private int _nextItemBlockIndex; - private int _nextItemIndex; - //private ulong _version; - private bool _isVersionChanged; - private void VersionChanged() => _isVersionChanged = true; - - private T? _current; - - public RecyclableLongListEnumerator(RecyclableLongList list) + // & WAS SLOWER + // [StructLayout(LayoutKind.Sequential, Pack = 1)] + // [StructLayout(LayoutKind.Sequential)] + public struct Enumerator : IEnumerator { - _listVersion = list._version; - list._version!.VersionChanged += VersionChanged; - //_listVersion!.AddEnumerator(); - _blockSize = list._blockSize; - _blockSizeMinus1 = list._blockSizeMinus1; - _lastBlockWithData = list._lastBlockWithData; - _list = list; - //_version = _listVersion!.Version; - _memoryBlocks = list._memoryBlocks; - _nextItemBlockIndex = list._nextItemBlockIndex; - _nextItemIndex = _lastBlockWithData == _nextItemBlockIndex ? _list._nextItemIndex : _blockSize; - } + // & WAS SLOWER WITHOUT + #nullable disable + private static readonly T _default = default; + #nullable restore - public T Current => _current ?? throw new InvalidOperationException("The enumerator wasn't initialized. You need to call MoveNext() before getting the current iterator value"); - object? IEnumerator.Current => _current; + private static readonly bool _isReferenceType = !typeof(T).IsValueType; - public void Dispose() - { - if (_listVersion != null) + private int _currentBlockIndex; + private int _currentItemIndex; + private readonly RecyclableLongList _list; + // & WAS SLOWER WITHOUT + #nullable disable + private T _current; + #nullable restore + // & WAS SLOWER + // private readonly ulong _enumeratorVersion; + // public T Current => _enumeratorVersion != _list._version ? throw new InvalidOperationException() : _current; + + public readonly T Current => _current; + // & WAS SLOWER + // get => _currentItemIndex > 0 + // ? _list._memoryBlocks[_currentBlockIndex][_currentItemIndex - 1] + // : _list._memoryBlocks[_currentBlockIndex - 1][_list._blockSize - 1]; + // & WAS SLOWER + // get => _currentItemIndex != RecyclableDefaults.BlockIndexLimit + // ? _currentItemIndex > 0 + // ? _list._memoryBlocks[_currentBlockIndex][_currentItemIndex - 1] + // & WAS SLOWER + // : _list._memoryBlocks[_currentBlockIndex - 1][_list._blockSize - 1] + // ? _current + // : throw new IndexOutOfRangeException(); + // & WAS SLOWER + // { + // get + // { + // if (_enumeratorVersion != _list._version) + // { + // throw new InvalidOperationException(); + // } + + // if (_list._longCount == 0 || _currentItemIndex == RecyclableDefaults.BlockIndexLimit) + // { + // throw new IndexOutOfRangeException(); + // } + + // Contract.EndContractBlock(); + + // return _currentItemIndex > 0 + // ? _list._memoryBlocks[_currentBlockIndex][_currentItemIndex - 1] + // : _list._memoryBlocks[_currentBlockIndex - 1][_list._blockSize - 1]; + // } + // } + + // & WAS SLOWER + // [MethodImpl(MethodImplOptions.AggressiveInlining)] + // [MethodImpl(MethodImplOptions.NoInlining)] + // [MethodImpl(MethodImplOptions.AggressiveOptimization)] + // [MethodImpl(MethodImplOptions.NoInlining | MethodImplOptions.AggressiveOptimization)] + public bool MoveNext() { - _listVersion.VersionChanged -= VersionChanged; - //_listVersion.RemoveEnumerator(); - _listVersion = null; - } + // & WAS SLOWER + // if (_enumeratorVersion != _list._version) + // { + // throw new InvalidOperationException(); + // } + // + // Contract.EndContractBlock(); - if (_list != null) - { - _list = null; - } + // & WAS SLOWER WITHOUT + var list = _list; + // & WAS SLOWER + // ref var currentBlockIndex = ref _currentBlockIndex; + // & WAS SLOWER + // ref var currentItemIndex = ref _currentItemIndex; - GC.SuppressFinalize(this); - } - - public bool MoveNext() - { - if (_list != null) - { - if (_isVersionChanged) + if (_currentBlockIndex < list._lastBlockWithData) { - _current = default; - ThrowListModifiedException(); - return false; - } - else if (_currentBlockIndex < _lastBlockWithData) - { - if (_currentIndex < _blockSizeMinus1) + // & WAS SLOWER WITHOUT + _current = list._memoryBlocks[_currentBlockIndex][_currentItemIndex]; + if (_currentItemIndex + 1 < list._blockSize) { - _currentIndex++; + _currentItemIndex++; } else { - _currentIndex = 0; _currentBlockIndex++; - if (_currentBlockIndex == _lastBlockWithData && _currentIndex >= _nextItemIndex) - { - _current = default; - return false; - } + _currentItemIndex = 0; } - _current = _memoryBlocks[_currentBlockIndex][_currentIndex]; return true; } - else if (_currentBlockIndex == _lastBlockWithData && !(_currentIndex >= _nextItemIndex - 1)) + // & WAS SLOWER + // else if (list._longCount == 0) + // { + // return false; + // } + // Move to the next item if we're within block boundaries, otherwise report end of collection. + else if (list._longCount > 0 && _currentItemIndex < (list._nextItemIndex > 0 ? list._nextItemIndex : list._blockSize)) { - _currentIndex++; - _current = _memoryBlocks[_currentBlockIndex][_currentIndex]; + // & WAS SLOWER WITHOUT + _current = list._memoryBlocks[_currentBlockIndex][_currentItemIndex]; + // & WAS SLOWER WITHOUT + _currentItemIndex++; return true; } - else - { - _current = default; - return false; - } - } - else - { - _current = default; + // & WAS SLOWER + // else if (_currentItemIndex != RecyclableDefaults.BlockIndexLimit) + // { + // _currentItemIndex = RecyclableDefaults.BlockIndexLimit; + // _current = _default; + // } + return false; } - } - public void Reset() - { - _currentBlockIndex = 0; - _currentIndex = RecyclableDefaults.ItemNotFoundIndex; - _current = default; - if (_isVersionChanged) - { - //_blockSize = _list!._blockSize; - //_blockSizeMinus1 = _list._blockSizeMinus1; - _isVersionChanged = false; - //_lastBlockWithData = _list!._lastBlockWithData; - //_listVersion = _list._version; - //_memoryBlocks = _list._memoryBlocks; - //_nextItemBlockIndex = _list._nextItemBlockIndex; - //_nextItemIndex = _lastBlockWithData == _nextItemBlockIndex ? _list._nextItemIndex : _blockSize; - //_version = _listVersion!.Version; - } - } +#nullable disable + readonly object IEnumerator.Current => _current; + // & WAS SLOWER + // get => _currentItemIndex > 0 + // ? _list._memoryBlocks[_currentBlockIndex][_currentItemIndex - 1] + // : (object)_list._memoryBlocks[_currentBlockIndex - 1][_list._blockSize - 1]; + // & WAS SLOWER + // get => _currentItemIndex != RecyclableDefaults.BlockIndexLimit + // // ? _currentItemIndex > 0 + // // ? _list._memoryBlocks[_currentBlockIndex][_currentItemIndex - 1] + // // : _list._memoryBlocks[_currentBlockIndex - 1][_list._blockSize - 1] + // // & WAS SLOWER + // ? _current + // : throw new IndexOutOfRangeException(); +#nullable restore + // & WAS SLOWER + // readonly object? IEnumerator.Current => _enumeratorVersion != _list._version ? throw new InvalidOperationException() : _current; + // { + // get + // { + // // if (_enumeratorVersion != _list._version) + // // { + // // throw new InvalidOperationException(); + // // } - internal RecyclableLongListEnumerator Init() - { - _currentBlockIndex = 0; - _currentIndex = RecyclableDefaults.ItemNotFoundIndex; - _current = default; - if (_list != null) + // // if (_list._longCount == 0 || _currentItemIndex == RecyclableDefaults.BlockIndexLimit) + // // { + // // throw new IndexOutOfRangeException(); + // // } + + // // Contract.EndContractBlock(); + + // return _currentItemIndex > 0 + // ? _list._memoryBlocks[_currentBlockIndex][_currentItemIndex - 1] + // : _list._memoryBlocks[_currentBlockIndex - 1][_list._blockSize - 1]; + // } + // } + + public Enumerator(RecyclableLongList list) { - _blockSize = _list._blockSize; - _blockSizeMinus1 = _list._blockSizeMinus1; - _isVersionChanged = false; - _lastBlockWithData = _list._lastBlockWithData; - _listVersion = _list._version; - _memoryBlocks = _list._memoryBlocks; - _nextItemBlockIndex = _list._nextItemBlockIndex; - _nextItemIndex = _lastBlockWithData == _nextItemBlockIndex ? _list._nextItemIndex : _blockSize; - //_version = _listVersion!.Version; + // & WAS SLOWER WITHOUT + _current = _default; + _currentBlockIndex = 0; + // & WAS SLOWER + //_currentBlockIndex = -1; + _currentItemIndex = 0; + _list = list; + // & WAS SLOWER + // _enumeratorVersion = list._version; } - return this; + public void Reset() + { + // & WAS SLOWER WITHOUT + _current = _default; + _currentBlockIndex = 0; + // & WAS SLOWER + //_currentBlockIndex = -1; + _currentItemIndex = 0; + } + + public void Dispose() + { + if (_isReferenceType) + { + _current = _default; + } + } } } } diff --git a/Recyclable.Collections/RecyclableLongList.cs b/Recyclable.Collections/RecyclableLongList.cs index db6664c..90ef792 100644 --- a/Recyclable.Collections/RecyclableLongList.cs +++ b/Recyclable.Collections/RecyclableLongList.cs @@ -39,11 +39,7 @@ namespace Recyclable.Collections protected set { _capacity = value; - - if (_version?.IsVersioned ?? false) - { - _version.Inc(); - } + _version++; } } @@ -54,11 +50,7 @@ namespace Recyclable.Collections set { _longCount = value; - - if (_version?.IsVersioned ?? false) - { - _version.Inc(); - } + _version++; } } @@ -74,11 +66,7 @@ namespace Recyclable.Collections set { _longCount = value; - - if (_version?.IsVersioned ?? false) - { - _version.Inc(); - } + _version++; } } @@ -88,9 +76,9 @@ namespace Recyclable.Collections public byte BlockSizePow2BitShift => _blockSizePow2BitShift; public int NextItemBlockIndex => _nextItemBlockIndex; public int NextItemIndex => _nextItemIndex; - - internal RecyclableCollectionVersion? _version; - public RecyclableCollectionVersion? Version => _version; + + private ulong _version; + public ulong Version => _version; [MethodImpl(MethodImplOptions.NoInlining | MethodImplOptions.AggressiveOptimization)] private static void CopyFollowingItems(RecyclableLongList list, long destinationItemIndex) @@ -667,11 +655,7 @@ namespace Recyclable.Collections set { new Span(_memoryBlocks[checked((int)(index >> _blockSizePow2BitShift))])[checked((int)(index & _blockSizeMinus1))] = value; - - if (_version?.IsVersioned ?? false) - { - _version.Inc(); - } + _version++; } } @@ -681,11 +665,7 @@ namespace Recyclable.Collections set { new Span(_memoryBlocks[index >> _blockSizePow2BitShift])[index & _blockSizeMinus1] = value; - - if (_version?.IsVersioned ?? false) - { - _version.Inc(); - } + _version++; } } @@ -716,11 +696,7 @@ namespace Recyclable.Collections } _longCount++; - - if (_version?.IsVersioned ?? false) - { - _version.Inc(); - } + _version++; } public void AddRange(in T[] items) @@ -769,11 +745,7 @@ namespace Recyclable.Collections _nextItemIndex = itemsSpan.Length; _longCount = targetCapacity; _lastBlockWithData = targetBlockIndex; - - if (_version?.IsVersioned ?? false) - { - _version.Inc(); - } + _version++; } public void AddRange(RecyclableList items) @@ -814,11 +786,7 @@ namespace Recyclable.Collections _longCount = targetCapacity; _nextItemBlockIndex = targetBlockIndex; _lastBlockWithData = targetBlockIndex - (itemsSpan.Length > 0 ? 0 : 1); - - if (_version?.IsVersioned ?? false) - { - _version.Inc(); - } + _version++; } public void AddRange(ReadOnlySpan itemsSpan) @@ -866,11 +834,7 @@ namespace Recyclable.Collections _nextItemIndex = itemsSpan.Length; _longCount = targetCapacity; _lastBlockWithData = targetBlockIndex; - - if (_version?.IsVersioned ?? false) - { - _version.Inc(); - } + _version++; } public void AddRange(RecyclableLongList items) @@ -943,11 +907,7 @@ namespace Recyclable.Collections } _longCount = targetCapacity; - - if (_version?.IsVersioned ?? false) - { - _version.Inc(); - } + _version++; } public void AddRange(List items) @@ -995,11 +955,7 @@ namespace Recyclable.Collections _nextItemBlockIndex = targetBlockIndex; _longCount = targetCapacity; _lastBlockWithData = targetBlockIndex - (_nextItemIndex > 0 ? 0 : 1); - - if (_version?.IsVersioned ?? false) - { - _version.Inc(); - } + _version++; } public void AddRange(IList items) @@ -1055,10 +1011,7 @@ namespace Recyclable.Collections _defaultBlockArrayPool.Return(itemsBuffer, NeedsClearing); } - if (_version?.IsVersioned ?? false) - { - _version.Inc(); - } + _version++; } } @@ -1087,20 +1040,12 @@ namespace Recyclable.Collections else if (source.TryGetNonEnumeratedCount(out var requiredAdditionalCapacity)) { AddRangeWithKnownCount(source, requiredAdditionalCapacity); - - if (_version?.IsVersioned ?? false) - { - _version.Inc(); - } + _version++; } else { AddRangeEnumerated(source, growByCount); - - if (_version?.IsVersioned ?? false) - { - _version.Inc(); - } + _version++; } } @@ -1130,11 +1075,7 @@ namespace Recyclable.Collections _nextItemIndex = 0; _lastBlockWithData = RecyclableDefaults.ItemNotFoundIndex; _longCount = 0; - - if (_version?.IsVersioned ?? false) - { - _version.Inc(); - } + _version++; } [MethodImpl(MethodImplOptions.AggressiveInlining)] @@ -1165,17 +1106,9 @@ namespace Recyclable.Collections public void CopyTo(T[] array, int arrayIndex) => RecyclableLongList.RecyclableLongListHelpers.CopyTo(_memoryBlocks, 0, _blockSize, _longCount, array, arrayIndex); - public IEnumerator GetEnumerator() - { - _version ??= new(); - return new RecyclableLongListEnumerator(this); - } - - IEnumerator IEnumerable.GetEnumerator() - { - _version ??= new(); - return new RecyclableLongListEnumerator(this); - } + public Enumerator GetEnumerator() => new(this); + IEnumerator IEnumerable.GetEnumerator() => new Enumerator(this); + IEnumerator IEnumerable.GetEnumerator() => new Enumerator(this); [MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)] public int IndexOf(T item) @@ -1288,11 +1221,7 @@ namespace Recyclable.Collections #pragma warning restore CS8601 } - if (_version?.IsVersioned ?? false) - { - _version.Inc(); - } - + _version++; return true; } @@ -1322,11 +1251,7 @@ namespace Recyclable.Collections } _lastBlockWithData--; - - if (_version?.IsVersioned ?? false) - { - _version.Inc(); - } + _version++; } [MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)] @@ -1344,7 +1269,6 @@ namespace Recyclable.Collections CopyFollowingItems(this, index); } - if (_nextItemIndex > 0) { _nextItemIndex--; @@ -1367,10 +1291,7 @@ namespace Recyclable.Collections #pragma warning restore CS8601 } - if (_version?.IsVersioned ?? false) - { - _version.Inc(); - } + _version++; } [MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)] @@ -1410,21 +1331,16 @@ namespace Recyclable.Collections #pragma warning restore CS8601 } - if (_version?.IsVersioned ?? false) - { - _version.Inc(); - } + _version++; } ~RecyclableLongList() { - // Do not change this code. Put cleanup code in 'Dispose(bool disposing)' method Dispose(); } public void Dispose() { - // Do not change this code. Put cleanup code in 'Dispose(bool disposing)' method if (_capacity > 0) { Clear(); @@ -1432,16 +1348,9 @@ namespace Recyclable.Collections { _memoryBlocksPool.Return(_memoryBlocks, NeedsClearing); } - - if (_version != null) - { - //var toReturn = _version; - _version = null; - //RecyclableCollectionVersionPool.Shared.Return(toReturn); - } - - GC.SuppressFinalize(this); } + + GC.SuppressFinalize(this); } } }