From 49c0615a622ec169f4e16f1822a8578b1014f3c8 Mon Sep 17 00:00:00 2001 From: mlemanczyk Date: Sat, 24 Jun 2023 20:29:03 +0200 Subject: [PATCH] RecyclableLongList.VersionedEnumerator added --- .../RecyclableLongList.VersionedEnumerator.cs | 97 +++++++++++++++++++ Recyclable.Collections/RecyclableLongList.cs | 1 + 2 files changed, 98 insertions(+) create mode 100644 Recyclable.Collections/RecyclableLongList.VersionedEnumerator.cs diff --git a/Recyclable.Collections/RecyclableLongList.VersionedEnumerator.cs b/Recyclable.Collections/RecyclableLongList.VersionedEnumerator.cs new file mode 100644 index 0000000..bd339ae --- /dev/null +++ b/Recyclable.Collections/RecyclableLongList.VersionedEnumerator.cs @@ -0,0 +1,97 @@ +using System.Collections; +using System.Diagnostics.Contracts; + +namespace Recyclable.Collections +{ + public partial class RecyclableLongList + { + public struct VersionedEnumerator : IEnumerator + { +#nullable disable + private static readonly T _default = default; +#nullable restore + + private static readonly bool _isReferenceType = !typeof(T).IsValueType; + + private int _currentBlockIndex; + private int _currentItemIndex; + private readonly RecyclableLongList _list; + +#nullable disable + private T _current; +#nullable restore + public readonly T Current => _enumeratorVersion == _list._version ? _current : throw new InvalidOperationException(); + + private readonly ulong _enumeratorVersion; + + public bool MoveNext() + { + if (_enumeratorVersion != _list._version) + { + throw new InvalidOperationException(); + } + + Contract.EndContractBlock(); + var list = _list; + + if (_currentBlockIndex < list._lastBlockWithData) + { + _current = list._memoryBlocks[_currentBlockIndex][_currentItemIndex]; + if (_currentItemIndex + 1 < list._blockSize) + { + _currentItemIndex++; + } + else + { + _currentBlockIndex++; + _currentItemIndex = 0; + } + + return true; + } + // 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)) + { + _current = list._memoryBlocks[_currentBlockIndex][_currentItemIndex]; + _currentItemIndex++; + return true; + } + + return false; + } + +#nullable disable + readonly object IEnumerator.Current => _enumeratorVersion == _list._version ? _current : throw new InvalidOperationException(); +#nullable restore + + public VersionedEnumerator(RecyclableLongList list) + { + _current = _default; + _currentBlockIndex = 0; + _currentItemIndex = 0; + _enumeratorVersion = list._version; + _list = list; + } + + public void Reset() + { + if (_enumeratorVersion != _list._version) + { + throw new InvalidOperationException(); + } + + _current = _default; + _currentBlockIndex = 0; + _currentItemIndex = 0; + } + + public void Dispose() + { + if (_isReferenceType) + { + _current = _default; + } + } + } + } +} diff --git a/Recyclable.Collections/RecyclableLongList.cs b/Recyclable.Collections/RecyclableLongList.cs index 90ef792..3b069e5 100644 --- a/Recyclable.Collections/RecyclableLongList.cs +++ b/Recyclable.Collections/RecyclableLongList.cs @@ -1109,6 +1109,7 @@ namespace Recyclable.Collections public Enumerator GetEnumerator() => new(this); IEnumerator IEnumerable.GetEnumerator() => new Enumerator(this); IEnumerator IEnumerable.GetEnumerator() => new Enumerator(this); + public VersionedEnumerator GetVersionedEnumerator() => new(this); [MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)] public int IndexOf(T item)