RecyclableList.Enumerator optimized. Tests fixed.

This commit is contained in:
mlemanczyk committed 2023-06-21 02:15:09 +02:00
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
+26 -82
View File
@@ -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);