RecyclableList.Enumerator optimized. Tests fixed.
This commit is contained in:
1 parent
85aac1dad6
commit
20fe0cc491
3 files changed
+200
-209
No files matched your search
@@ -1,87 +1,185 @@
|
||||
using System.Collections;
|
||||
using System.Diagnostics.Contracts;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.ConstrainedExecution;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace Recyclable.Collections
|
||||
{
|
||||
public partial class RecyclableList<T>
|
||||
{
|
||||
|
||||
public struct Enumerator : IEnumerator<T>, IEnumerator
|
||||
[StructLayout(LayoutKind.Auto)]
|
||||
public struct Enumerator : IEnumerator<T>
|
||||
{
|
||||
#nullable disable
|
||||
private readonly RecyclableList<T> _list;
|
||||
private int _currentIndex;
|
||||
private T _current;
|
||||
private readonly ulong _enumeratorVersion;
|
||||
private readonly RecyclableList<T> _list;
|
||||
|
||||
//[Pure]
|
||||
//private readonly int _listCount;
|
||||
//private readonly int _listCountMinus1;
|
||||
//private readonly T[] _memoryBlock;
|
||||
//private bool _endOfCollectionReached;
|
||||
// & WAS SLOWER
|
||||
// private bool _isInValidState = false;
|
||||
// private bool _endOfCollectionReached;
|
||||
// private T _current;
|
||||
|
||||
//private RecyclableCollectionVersion _listVersion;
|
||||
//private ulong _enumeratorVersion;
|
||||
//private bool _isVersionChanged;
|
||||
|
||||
//private void VersionChanged() => _isVersionChanged = true;
|
||||
|
||||
//internal RecyclableListEnumeratorPool? _pool;
|
||||
//internal bool _returned;
|
||||
|
||||
//public RecyclableListEnumerator()
|
||||
//{
|
||||
//}
|
||||
|
||||
//[Pure]
|
||||
internal Enumerator(RecyclableList<T> list)
|
||||
#nullable disable
|
||||
// [Pure]
|
||||
public readonly T Current
|
||||
{
|
||||
_current = default;
|
||||
_currentIndex = 0;
|
||||
_list = list;
|
||||
//_memoryBlock = list._memoryBlock;
|
||||
//_listCount = list._count;
|
||||
//_listVersion = list._version!;
|
||||
//_listVersion.VersionChanged += VersionChanged;
|
||||
//_enumeratorVersion = _listVersion.Version;
|
||||
get
|
||||
{
|
||||
if (_enumeratorVersion != _list._version)
|
||||
{
|
||||
throw new InvalidOperationException();
|
||||
// & WAS SLOWER
|
||||
// ThrowHelper.ThrowListModifiedException();
|
||||
}
|
||||
|
||||
if (_currentIndex == 0 || _currentIndex > _list._count)
|
||||
{
|
||||
throw new IndexOutOfRangeException();
|
||||
// & WAS SLOWER
|
||||
// ThrowHelper.ThrowCollectionNotInitialized();// new IndexOutOfRangeException();// _current;
|
||||
}
|
||||
|
||||
Contract.EndContractBlock();
|
||||
|
||||
return _list._memoryBlock[_currentIndex - 1];// _current;
|
||||
}
|
||||
}
|
||||
|
||||
//{
|
||||
// //[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
// get =>
|
||||
// //if (_currentIndex < 0)
|
||||
// //{
|
||||
// // ThrowHelper.ThrowInvalidOperationException("The enumerator wasn't initialized. You need to call MoveNext() before getting the current iterator value");
|
||||
// //}
|
||||
// //else
|
||||
// //if (_endOfCollectionReached)
|
||||
// //{
|
||||
// // throw new InvalidOperationException("The enumerator reached the end of the collection. You need to call Reset(), if you want to enumerate the collection again");
|
||||
// //}
|
||||
// //else
|
||||
// //{
|
||||
// //if (_currentIndex < 0)
|
||||
// //{
|
||||
// // ThrowHelper.ThrowInvalidOperationException("The enumerator wasn't initialized. You need to call MoveNext() before getting the current iterator value");
|
||||
// //}
|
||||
// //else
|
||||
// _memoryBlock[_currentIndex];//}
|
||||
//}
|
||||
// [Pure]
|
||||
object IEnumerator.Current
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_enumeratorVersion != _list._version)
|
||||
{
|
||||
throw new InvalidOperationException();
|
||||
// & WAS SLOWER
|
||||
// ThrowHelper.ThrowListModifiedException();
|
||||
}
|
||||
|
||||
if (_currentIndex == 0 || _currentIndex > _list._count)
|
||||
{
|
||||
throw new IndexOutOfRangeException();
|
||||
// & WAS SLOWER
|
||||
// ThrowHelper.ThrowCollectionNotInitialized();
|
||||
}
|
||||
|
||||
Contract.EndContractBlock();
|
||||
|
||||
return _list._memoryBlock[_currentIndex - 1];
|
||||
|
||||
// & WAS SLOWER
|
||||
// return _current;
|
||||
}
|
||||
}
|
||||
|
||||
// & WAS SLOWER
|
||||
// private readonly int _listCount;
|
||||
// private RecyclableCollectionVersion _listVersion;
|
||||
// private readonly T[] _memoryBlock;
|
||||
// private bool _isVersionChanged;
|
||||
// private void VersionChanged() => _isVersionChanged = true;
|
||||
// internal RecyclableListEnumeratorPool? _pool;
|
||||
// internal bool _returned;
|
||||
// private readonly int _listCountMinus1;
|
||||
|
||||
// & WAS SLOWER
|
||||
// [MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
// [MethodImpl(MethodImplOptions.NoInlining)]
|
||||
public bool MoveNext()
|
||||
{
|
||||
// & WAS SLOWER
|
||||
// var list = _list;
|
||||
if (_enumeratorVersion != _list._version)
|
||||
{
|
||||
throw new InvalidOperationException();
|
||||
// & WAS SLOWER
|
||||
// ThrowHelper.ThrowListModifiedException();
|
||||
}
|
||||
|
||||
Contract.EndContractBlock();
|
||||
|
||||
// & WAS SLOWER
|
||||
// if (_currentIndex == 0)
|
||||
// {
|
||||
// _isInValidState = true;
|
||||
// _currentIndex++;
|
||||
// return true;
|
||||
// }
|
||||
// else
|
||||
if (_currentIndex < _list._count)
|
||||
{
|
||||
// & WAS SLOWER
|
||||
// _current = _list._memoryBlock[_currentIndex];
|
||||
_currentIndex++;
|
||||
return true;
|
||||
}
|
||||
|
||||
// & WAS SLOWER
|
||||
// else if (_currentIndex == _list._count)
|
||||
// {
|
||||
// & WAS SLOWER
|
||||
// This isn't needed in most use-cases, because the enumerator will get disposed, releasing the reference, if any.
|
||||
// _current = _defaultValue;
|
||||
// _currentIndex++;
|
||||
// return false;
|
||||
// }
|
||||
// else if (!_endOfCollectionReached)
|
||||
// {
|
||||
// // & WAS SLOWER
|
||||
// // This isn't needed in most use-cases, because the enumerator will get disposed, releasing the reference, if any.
|
||||
// // _current = _defaultValue;
|
||||
// // _currentIndex = int.MinValue;
|
||||
// _endOfCollectionReached = true;
|
||||
// return false;
|
||||
// }
|
||||
|
||||
// & WAS SLOWER
|
||||
// else if (!_endOfCollectionReached)
|
||||
// {
|
||||
// _current = default;
|
||||
// _endOfCollectionReached = true;
|
||||
// return false;
|
||||
// }
|
||||
|
||||
// & WAS SLOWER
|
||||
// _current = default;
|
||||
// _currentIndex = _list._count + 1;
|
||||
return false;
|
||||
}
|
||||
|
||||
public Enumerator(RecyclableList<T> list)
|
||||
{
|
||||
_currentIndex = 0;
|
||||
_list = list;
|
||||
_enumeratorVersion = list._version;
|
||||
|
||||
// & WAS SLOWER
|
||||
// _current = default;
|
||||
// _endOfCollectionReached = false;
|
||||
// _listCount = list._count;
|
||||
// _memoryBlock = list._memoryBlock;
|
||||
// _isVersionChanged = false;
|
||||
// _listVersion = list.Version;
|
||||
// _listVersion.AddEnumerator();
|
||||
// _enumeratorVersion = list._version.Version;
|
||||
// list._version.RegisterHandler(VersionChanged);
|
||||
// _enumeratorVersion = _listVersion.Version;
|
||||
// _endOfCollectionReached = false;
|
||||
// _listCountMinus1 = list._count - 1;
|
||||
}
|
||||
|
||||
//[Pure]
|
||||
public readonly void Dispose()
|
||||
{
|
||||
// if (_listVersion != null)
|
||||
// {
|
||||
// _listVersion.VersionChanged -= VersionChanged;
|
||||
// //_listVersion.RemoveEnumerator(this);
|
||||
//#nullable disable
|
||||
// _listVersion = null;
|
||||
//#nullable restore
|
||||
// }
|
||||
// & WAS SLOWER
|
||||
//if (_listVersion != null)
|
||||
//{
|
||||
//_list._version.RemoveEnumerator();
|
||||
//_listVersion.RemoveEnumerator(this);
|
||||
//}
|
||||
|
||||
//if (_pool != null)
|
||||
// & WAS SLOWER
|
||||
// if (_pool != null)
|
||||
//{
|
||||
// if (!_returned)
|
||||
// {
|
||||
@@ -92,74 +190,19 @@ namespace Recyclable.Collections
|
||||
//else
|
||||
//{
|
||||
//_memoryBlock = null;
|
||||
//GC.SuppressFinalize(this);
|
||||
//GC.SuppressFinalize(this);
|
||||
//}
|
||||
}
|
||||
|
||||
//[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public bool MoveNext()
|
||||
{
|
||||
var list = _list;
|
||||
//if (_isVersionChanged)
|
||||
//{
|
||||
// ThrowHelper.ThrowListModifiedException();
|
||||
// return false;
|
||||
//}
|
||||
//else
|
||||
if (_currentIndex < list._count)
|
||||
{
|
||||
_current = list._memoryBlock[_currentIndex];
|
||||
_currentIndex++;
|
||||
return true;
|
||||
}
|
||||
|
||||
//else if (!_endOfCollectionReached)
|
||||
//{
|
||||
// _endOfCollectionReached = true;
|
||||
// return false;
|
||||
//}
|
||||
|
||||
_current = default;
|
||||
return false;
|
||||
}
|
||||
|
||||
#nullable restore
|
||||
public T Current => _current;
|
||||
object IEnumerator.Current => _current;
|
||||
#nullable disable
|
||||
|
||||
//[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
void IEnumerator.Reset()
|
||||
{
|
||||
_currentIndex = 0;
|
||||
_current = default;
|
||||
|
||||
// & WAS SLOWER
|
||||
// _endOfCollectionReached = false;
|
||||
// _isInValidState = false;
|
||||
// _current = default;
|
||||
}
|
||||
|
||||
//_endOfCollectionReached = false;
|
||||
//if (_isVersionChanged)
|
||||
//{
|
||||
//
|
||||
//_enumeratorVersion = _listVersion!.Version;
|
||||
// _isVersionChanged = false;
|
||||
//}
|
||||
|
||||
//internal RecyclableListEnumerator Reset(RecyclableListEnumeratorPool pool, RecyclableList<T> list)
|
||||
//{
|
||||
// _returned = false;
|
||||
// if (_pool != pool)
|
||||
// {
|
||||
// _pool = pool;
|
||||
// }
|
||||
|
||||
// _currentIndex = RecyclableDefaults.ItemNotFoundIndex;
|
||||
// _listVersion = list._version!;
|
||||
// _enumeratorVersion = _listVersion!.Version;
|
||||
// list._version!.AddEnumerator();
|
||||
// return this;
|
||||
//}
|
||||
|
||||
//[Pure]
|
||||
//public object Clone() => MemberwiseClone();
|
||||
}
|
||||
}
|
||||
#nullable restore
|
||||
|
||||
@@ -15,9 +15,12 @@ namespace Recyclable.Collections
|
||||
public static explicit operator ReadOnlySpan<T>(RecyclableList<T> source) => new(source._memoryBlock, 0, source.Count);
|
||||
|
||||
protected T[] _memoryBlock;
|
||||
internal RecyclableCollectionVersion? _version;
|
||||
// & WAS SLOWER
|
||||
// internal RecyclableCollectionVersion _version;
|
||||
// public RecyclableCollectionVersion Version => _version;
|
||||
|
||||
public RecyclableCollectionVersion? Version => _version;
|
||||
protected ulong _version;
|
||||
public ulong Version => _version;
|
||||
|
||||
protected IEnumerator<T> AddRangeEnumerated(IEnumerable<T> source, int growByCount)
|
||||
{
|
||||
@@ -196,11 +199,7 @@ namespace Recyclable.Collections
|
||||
set
|
||||
{
|
||||
_memoryBlock[index] = value;
|
||||
|
||||
if (_version?.IsVersioned ?? false)
|
||||
{
|
||||
_version.Inc();
|
||||
}
|
||||
_version++;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -214,11 +213,7 @@ namespace Recyclable.Collections
|
||||
{
|
||||
_memoryBlock = Resize(_memoryBlock, value);
|
||||
_capacity = _memoryBlock.Length;
|
||||
}
|
||||
|
||||
if (_version?.IsVersioned ?? false)
|
||||
{
|
||||
_version.Inc();
|
||||
_version++;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -254,11 +249,7 @@ namespace Recyclable.Collections
|
||||
}
|
||||
|
||||
_memoryBlock[_count++] = item;
|
||||
|
||||
if (_version?.IsVersioned ?? false)
|
||||
{
|
||||
_version.Inc();
|
||||
}
|
||||
_version++;
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.NoInlining | MethodImplOptions.AggressiveOptimization)]
|
||||
@@ -281,10 +272,7 @@ namespace Recyclable.Collections
|
||||
itemsSpan.CopyTo(targetSpan);
|
||||
_count = targetCapacity;
|
||||
|
||||
if (_version?.IsVersioned ?? false)
|
||||
{
|
||||
_version.Inc();
|
||||
}
|
||||
_version++;
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.NoInlining | MethodImplOptions.AggressiveOptimization)]
|
||||
@@ -306,10 +294,7 @@ namespace Recyclable.Collections
|
||||
itemsSpan.CopyTo(targetSpan);
|
||||
_count = targetCapacity;
|
||||
|
||||
if (_version?.IsVersioned ?? false)
|
||||
{
|
||||
_version.Inc();
|
||||
}
|
||||
_version++;
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.NoInlining | MethodImplOptions.AggressiveOptimization)]
|
||||
@@ -330,10 +315,7 @@ namespace Recyclable.Collections
|
||||
items.CopyTo(_memoryBlock, _count);
|
||||
_count = targetCapacity;
|
||||
|
||||
if (_version?.IsVersioned ?? false)
|
||||
{
|
||||
_version.Inc();
|
||||
}
|
||||
_version++;
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.NoInlining | MethodImplOptions.AggressiveOptimization)]
|
||||
@@ -354,10 +336,7 @@ namespace Recyclable.Collections
|
||||
items.CopyTo(_memoryBlock, _count);
|
||||
_count = targetCapacity;
|
||||
|
||||
if (_version?.IsVersioned ?? false)
|
||||
{
|
||||
_version.Inc();
|
||||
}
|
||||
_version++;
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.NoInlining | MethodImplOptions.AggressiveOptimization)]
|
||||
@@ -380,10 +359,7 @@ namespace Recyclable.Collections
|
||||
itemsSpan.CopyTo(targetSpan);
|
||||
_count = targetCapacity;
|
||||
|
||||
if (_version?.IsVersioned ?? false)
|
||||
{
|
||||
_version.Inc();
|
||||
}
|
||||
_version++;
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.NoInlining | MethodImplOptions.AggressiveOptimization)]
|
||||
@@ -438,10 +414,7 @@ namespace Recyclable.Collections
|
||||
|
||||
_count = targetCapacity;
|
||||
|
||||
if (_version?.IsVersioned ?? false)
|
||||
{
|
||||
_version.Inc();
|
||||
}
|
||||
_version++;
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.NoInlining | MethodImplOptions.AggressiveOptimization)]
|
||||
@@ -467,19 +440,13 @@ namespace Recyclable.Collections
|
||||
{
|
||||
AddRangeWithKnownCount(source, _count, requiredAdditionalCapacity);
|
||||
|
||||
if (_version?.IsVersioned ?? false)
|
||||
{
|
||||
_version.Inc();
|
||||
}
|
||||
_version++;
|
||||
}
|
||||
else
|
||||
{
|
||||
AddRangeEnumerated(source, growByCount);
|
||||
|
||||
if (_version?.IsVersioned ?? false)
|
||||
{
|
||||
_version.Inc();
|
||||
}
|
||||
_version++;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -494,11 +461,7 @@ namespace Recyclable.Collections
|
||||
}
|
||||
|
||||
_count = 0;
|
||||
|
||||
if (_version?.IsVersioned ?? false)
|
||||
{
|
||||
_version.Inc();
|
||||
}
|
||||
_version++;
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
@@ -529,11 +492,7 @@ namespace Recyclable.Collections
|
||||
|
||||
_memoryBlock[index] = item;
|
||||
_count++;
|
||||
|
||||
if (_version?.IsVersioned ?? false)
|
||||
{
|
||||
_version.Inc();
|
||||
}
|
||||
_version++;
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)]
|
||||
@@ -555,10 +514,7 @@ namespace Recyclable.Collections
|
||||
#pragma warning restore CS8601
|
||||
}
|
||||
|
||||
if (_version?.IsVersioned ?? false)
|
||||
{
|
||||
_version.Inc();
|
||||
}
|
||||
_version++;
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -587,22 +543,17 @@ namespace Recyclable.Collections
|
||||
#pragma warning restore CS8601
|
||||
}
|
||||
|
||||
if (_version?.IsVersioned ?? false)
|
||||
{
|
||||
_version.Inc();
|
||||
}
|
||||
_version++;
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public Enumerator GetEnumerator() => new Enumerator(this);
|
||||
//[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
IEnumerator IEnumerable.GetEnumerator() =>
|
||||
//_version ??= new(); // RecyclableCollectionVersionPool.Shared.Get();
|
||||
new Enumerator(this);//return RecyclableListEnumeratorPool.Shared.Get(this);
|
||||
|
||||
//[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
IEnumerator<T> IEnumerable<T>.GetEnumerator() =>
|
||||
//_version ??= new(); // RecyclableCollectionVersionPool.Shared.Get();
|
||||
new Enumerator(this);//return RecyclableListEnumeratorPool.Shared.Get(this);
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
IEnumerator IEnumerable.GetEnumerator() => new Enumerator(this);
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
IEnumerator<T> IEnumerable<T>.GetEnumerator() => new Enumerator(this);
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
@@ -615,13 +566,6 @@ namespace Recyclable.Collections
|
||||
_arrayPool.Return(_memoryBlock, NeedsClearing);
|
||||
}
|
||||
|
||||
if (_version != null)
|
||||
{
|
||||
//var toReturn = _version;
|
||||
_version = null;
|
||||
//RecyclableCollectionVersionPool.Shared.Return(toReturn);
|
||||
}
|
||||
|
||||
GC.SuppressFinalize(this);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -349,7 +349,11 @@ namespace Recyclable.CollectionsTests
|
||||
|
||||
// Act
|
||||
var yieldedItems = new List<long>((int)itemsCount);
|
||||
yieldedItems.AddRange(list);
|
||||
using var enumerator = list.GetEnumerator();
|
||||
while (enumerator.MoveNext())
|
||||
{
|
||||
yieldedItems.Add(enumerator.Current);
|
||||
}
|
||||
|
||||
// Validate
|
||||
_ = yieldedItems.Count.Should().Be((int)itemsCount);
|
||||
|
||||
Reference in new issue
Block a user