Versioned enumerator for RecyclableList implemented. Benchmarks & tests added.
This commit is contained in:
1 parent
be746d65bf
commit
d830a53006
7 files changed
+177
-205
No files matched your search
@@ -10,6 +10,14 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void Array_VersionedForEach()
|
||||||
|
{
|
||||||
|
foreach (var item in TestObjects)
|
||||||
|
{
|
||||||
|
DoNothing(item);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public void List_ForEach()
|
public void List_ForEach()
|
||||||
{
|
{
|
||||||
foreach (var item in TestObjectsAsList)
|
foreach (var item in TestObjectsAsList)
|
||||||
@@ -18,6 +26,14 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void List_VersionedForEach()
|
||||||
|
{
|
||||||
|
foreach (var item in TestObjectsAsList)
|
||||||
|
{
|
||||||
|
DoNothing(item);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public void PooledList_ForEach()
|
public void PooledList_ForEach()
|
||||||
{
|
{
|
||||||
foreach (var item in TestObjectsAsPooledList)
|
foreach (var item in TestObjectsAsPooledList)
|
||||||
@@ -26,6 +42,14 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void PooledList_VersionedForEach()
|
||||||
|
{
|
||||||
|
foreach (var item in TestObjectsAsPooledList)
|
||||||
|
{
|
||||||
|
DoNothing(item);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public void RecyclableList_ForEach()
|
public void RecyclableList_ForEach()
|
||||||
{
|
{
|
||||||
foreach (var item in TestObjectsAsRecyclableList)
|
foreach (var item in TestObjectsAsRecyclableList)
|
||||||
@@ -34,6 +58,14 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void RecyclableList_VersionedForEach()
|
||||||
|
{
|
||||||
|
foreach (var item in (IVersionedList<long>)TestObjectsAsRecyclableList)
|
||||||
|
{
|
||||||
|
DoNothing(item);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public void RecyclableLongList_ForEach()
|
public void RecyclableLongList_ForEach()
|
||||||
{
|
{
|
||||||
foreach (var item in TestObjectsAsRecyclableLongList)
|
foreach (var item in TestObjectsAsRecyclableLongList)
|
||||||
@@ -41,5 +73,13 @@
|
|||||||
DoNothing(item);
|
DoNothing(item);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void RecyclableLongList_VersionedForEach()
|
||||||
|
{
|
||||||
|
foreach (var item in (IVersionedLongList<long>)TestObjectsAsRecyclableLongList)
|
||||||
|
{
|
||||||
|
DoNothing(item);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -9,7 +9,7 @@ namespace Recyclable.Collections.Benchmarks
|
|||||||
AddRangeWhenSourceIsIList, AddRangeWhenSourceIsList, AddRangeWhenSourceIsSameType, Contains_FirstItems,
|
AddRangeWhenSourceIsIList, AddRangeWhenSourceIsList, AddRangeWhenSourceIsSameType, Contains_FirstItems,
|
||||||
Contains_LastItems, Count, Create_WithCapacity, Create, ForEach, GetItem, IndexOf_BestAndWorstCases, IndexOf_FirstItems,
|
Contains_LastItems, Count, Create_WithCapacity, Create, ForEach, GetItem, IndexOf_BestAndWorstCases, IndexOf_FirstItems,
|
||||||
IndexOf_LastItems, LongCount, Remove_FirstItems, Remove_LastItems, RemoveAt_FirstItems, RemoveAt_LastItems,
|
IndexOf_LastItems, LongCount, Remove_FirstItems, Remove_LastItems, RemoveAt_FirstItems, RemoveAt_LastItems,
|
||||||
SetItem,
|
SetItem, VersionedForEach
|
||||||
}
|
}
|
||||||
|
|
||||||
public partial class RecyclableCollectionsBenchmarks : RecyclableBenchmarkBase<RecyclableCollectionsBenchmarkSource>
|
public partial class RecyclableCollectionsBenchmarks : RecyclableBenchmarkBase<RecyclableCollectionsBenchmarkSource>
|
||||||
@@ -23,47 +23,48 @@ namespace Recyclable.Collections.Benchmarks
|
|||||||
|
|
||||||
[Params
|
[Params
|
||||||
(
|
(
|
||||||
//RecyclableCollectionsBenchmarkType.Add_WithCapacity,
|
RecyclableCollectionsBenchmarkType.Add_WithCapacity,
|
||||||
//RecyclableCollectionsBenchmarkType.Add,
|
RecyclableCollectionsBenchmarkType.Add,
|
||||||
//RecyclableCollectionsBenchmarkType.AddRange_WithCapacity,
|
RecyclableCollectionsBenchmarkType.AddRange_WithCapacity,
|
||||||
//RecyclableCollectionsBenchmarkType.AddRangeWhenSourceIsArray,
|
RecyclableCollectionsBenchmarkType.AddRangeWhenSourceIsArray,
|
||||||
//RecyclableCollectionsBenchmarkType.AddRangeWhenSourceIsIEnumerable,
|
RecyclableCollectionsBenchmarkType.AddRangeWhenSourceIsIEnumerable,
|
||||||
//RecyclableCollectionsBenchmarkType.AddRangeWhenSourceIsIList,
|
RecyclableCollectionsBenchmarkType.AddRangeWhenSourceIsIList,
|
||||||
//RecyclableCollectionsBenchmarkType.AddRangeWhenSourceIsList,
|
RecyclableCollectionsBenchmarkType.AddRangeWhenSourceIsList,
|
||||||
//RecyclableCollectionsBenchmarkType.AddRangeWhenSourceIsSameType,
|
RecyclableCollectionsBenchmarkType.AddRangeWhenSourceIsSameType,
|
||||||
//RecyclableCollectionsBenchmarkType.Contains_FirstItems,
|
RecyclableCollectionsBenchmarkType.Contains_FirstItems,
|
||||||
//RecyclableCollectionsBenchmarkType.Contains_LastItems,
|
RecyclableCollectionsBenchmarkType.Contains_LastItems,
|
||||||
//RecyclableCollectionsBenchmarkType.Count,
|
RecyclableCollectionsBenchmarkType.Count,
|
||||||
//RecyclableCollectionsBenchmarkType.Create_WithCapacity,
|
RecyclableCollectionsBenchmarkType.Create_WithCapacity,
|
||||||
//RecyclableCollectionsBenchmarkType.Create,
|
RecyclableCollectionsBenchmarkType.Create,
|
||||||
RecyclableCollectionsBenchmarkType.ForEach
|
RecyclableCollectionsBenchmarkType.ForEach,
|
||||||
//RecyclableCollectionsBenchmarkType.GetItem,
|
RecyclableCollectionsBenchmarkType.GetItem,
|
||||||
//RecyclableCollectionsBenchmarkType.IndexOf_BestAndWorstCases,
|
RecyclableCollectionsBenchmarkType.IndexOf_BestAndWorstCases,
|
||||||
//RecyclableCollectionsBenchmarkType.IndexOf_FirstItems,
|
RecyclableCollectionsBenchmarkType.IndexOf_FirstItems,
|
||||||
//RecyclableCollectionsBenchmarkType.IndexOf_LastItems,
|
RecyclableCollectionsBenchmarkType.IndexOf_LastItems,
|
||||||
//RecyclableCollectionsBenchmarkType.LongCount,
|
RecyclableCollectionsBenchmarkType.LongCount,
|
||||||
//RecyclableCollectionsBenchmarkType.Remove_FirstItems,
|
RecyclableCollectionsBenchmarkType.Remove_FirstItems,
|
||||||
//RecyclableCollectionsBenchmarkType.Remove_LastItems,
|
RecyclableCollectionsBenchmarkType.Remove_LastItems,
|
||||||
//RecyclableCollectionsBenchmarkType.RemoveAt_FirstItems,
|
RecyclableCollectionsBenchmarkType.RemoveAt_FirstItems,
|
||||||
//RecyclableCollectionsBenchmarkType.RemoveAt_LastItems,
|
RecyclableCollectionsBenchmarkType.RemoveAt_LastItems,
|
||||||
//RecyclableCollectionsBenchmarkType.SetItem
|
RecyclableCollectionsBenchmarkType.SetItem,
|
||||||
|
RecyclableCollectionsBenchmarkType.VersionedForEach
|
||||||
)]
|
)]
|
||||||
|
|
||||||
public RecyclableCollectionsBenchmarkType TestCase { get; set; } = RecyclableCollectionsBenchmarkType.IndexOf_BestAndWorstCases;
|
public RecyclableCollectionsBenchmarkType TestCase { get; set; } = RecyclableCollectionsBenchmarkType.IndexOf_BestAndWorstCases;
|
||||||
|
|
||||||
//[Params
|
[Params
|
||||||
//(
|
(
|
||||||
// RecyclableCollectionsBenchmarkSource.List
|
RecyclableCollectionsBenchmarkSource.List
|
||||||
//)]
|
)]
|
||||||
public override RecyclableCollectionsBenchmarkSource BaseDataType { get => base.BaseDataType; set => base.BaseDataType = value; }
|
public override RecyclableCollectionsBenchmarkSource BaseDataType { get => base.BaseDataType; set => base.BaseDataType = value; }
|
||||||
|
|
||||||
[Params
|
[Params
|
||||||
(
|
(
|
||||||
//RecyclableCollectionsBenchmarkSource.Array,
|
RecyclableCollectionsBenchmarkSource.Array,
|
||||||
//RecyclableCollectionsBenchmarkSource.List,
|
RecyclableCollectionsBenchmarkSource.List,
|
||||||
//RecyclableCollectionsBenchmarkSource.PooledList,
|
RecyclableCollectionsBenchmarkSource.PooledList,
|
||||||
RecyclableCollectionsBenchmarkSource.RecyclableList
|
RecyclableCollectionsBenchmarkSource.RecyclableList,
|
||||||
//RecyclableCollectionsBenchmarkSource.RecyclableLongList
|
RecyclableCollectionsBenchmarkSource.RecyclableLongList
|
||||||
)]
|
)]
|
||||||
public override RecyclableCollectionsBenchmarkSource DataType { get => base.DataType; set => base.DataType = value; }
|
public override RecyclableCollectionsBenchmarkSource DataType { get => base.DataType; set => base.DataType = value; }
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,7 @@
|
|||||||
|
namespace Recyclable.Collections
|
||||||
|
{
|
||||||
|
public interface IVersionedList<T> : IEnumerable<T>
|
||||||
|
{
|
||||||
|
new RecyclableList<T>.VersionedEnumerator GetEnumerator();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -2,6 +2,7 @@
|
|||||||
{
|
{
|
||||||
public static class RecyclableDefaults
|
public static class RecyclableDefaults
|
||||||
{
|
{
|
||||||
|
public const int BlockIndexLimit = int.MaxValue;
|
||||||
public const int BlockSize = 16_384;
|
public const int BlockSize = 16_384;
|
||||||
public const int Capacity = 1;
|
public const int Capacity = 1;
|
||||||
public const long MinItemsCountForParallelization = 850_000;
|
public const long MinItemsCountForParallelization = 850_000;
|
||||||
|
|||||||
@@ -1,209 +1,50 @@
|
|||||||
using System.Collections;
|
using System.Collections;
|
||||||
using System.Diagnostics.Contracts;
|
|
||||||
using System.Runtime.CompilerServices;
|
|
||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
|
|
||||||
namespace Recyclable.Collections
|
namespace Recyclable.Collections
|
||||||
{
|
{
|
||||||
public partial class RecyclableList<T>
|
public partial class RecyclableList<T>
|
||||||
{
|
{
|
||||||
[StructLayout(LayoutKind.Auto)]
|
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
||||||
public struct Enumerator : IEnumerator<T>
|
public struct Enumerator : IEnumerator<T>
|
||||||
{
|
{
|
||||||
private int _currentIndex;
|
private static readonly bool _isReferenceType = !typeof(T).IsValueType;
|
||||||
private readonly ulong _enumeratorVersion;
|
|
||||||
private readonly RecyclableList<T> _list;
|
|
||||||
|
|
||||||
// & WAS SLOWER
|
private int _currentItemIndex;
|
||||||
// private bool _isInValidState = false;
|
private readonly RecyclableList<T> _list;
|
||||||
// private bool _endOfCollectionReached;
|
|
||||||
// private T _current;
|
|
||||||
|
|
||||||
#nullable disable
|
#nullable disable
|
||||||
// [Pure]
|
// [Pure]
|
||||||
public readonly T Current
|
public readonly T Current => _list._memoryBlock[_currentItemIndex - 1];
|
||||||
{
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// [Pure]
|
// [Pure]
|
||||||
object IEnumerator.Current
|
readonly object IEnumerator.Current => _list._memoryBlock[_currentItemIndex - 1];
|
||||||
{
|
#nullable restore
|
||||||
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()
|
public bool MoveNext()
|
||||||
{
|
{
|
||||||
// & WAS SLOWER
|
if (_currentItemIndex < _list._count)
|
||||||
// var list = _list;
|
|
||||||
if (_enumeratorVersion != _list._version)
|
|
||||||
{
|
{
|
||||||
throw new InvalidOperationException();
|
_currentItemIndex++;
|
||||||
// & 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;
|
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;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Enumerator(RecyclableList<T> list)
|
public Enumerator(RecyclableList<T> list)
|
||||||
{
|
{
|
||||||
_currentIndex = 0;
|
_currentItemIndex = 0;
|
||||||
_list = list;
|
_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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public readonly void Dispose()
|
public readonly void Dispose()
|
||||||
{
|
{
|
||||||
// & WAS SLOWER
|
|
||||||
//if (_listVersion != null)
|
|
||||||
//{
|
|
||||||
//_list._version.RemoveEnumerator();
|
|
||||||
//_listVersion.RemoveEnumerator(this);
|
|
||||||
//}
|
|
||||||
|
|
||||||
// & WAS SLOWER
|
|
||||||
// if (_pool != null)
|
|
||||||
//{
|
|
||||||
// if (!_returned)
|
|
||||||
// {
|
|
||||||
// _returned = true;
|
|
||||||
// _pool?.Return(this);
|
|
||||||
// }
|
|
||||||
//}
|
|
||||||
//else
|
|
||||||
//{
|
|
||||||
//_memoryBlock = null;
|
|
||||||
//GC.SuppressFinalize(this);
|
|
||||||
//}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void IEnumerator.Reset()
|
void IEnumerator.Reset()
|
||||||
{
|
{
|
||||||
_currentIndex = 0;
|
_currentItemIndex = 0;
|
||||||
|
|
||||||
// & WAS SLOWER
|
|
||||||
// _endOfCollectionReached = false;
|
|
||||||
// _isInValidState = false;
|
|
||||||
// _current = default;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#nullable restore
|
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,65 @@
|
|||||||
|
using System.Collections;
|
||||||
|
using System.Diagnostics.Contracts;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
|
|
||||||
|
namespace Recyclable.Collections
|
||||||
|
{
|
||||||
|
public partial class RecyclableList<T> : IVersionedList<T>
|
||||||
|
{
|
||||||
|
VersionedEnumerator IVersionedList<T>.GetEnumerator() => new(this);
|
||||||
|
|
||||||
|
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
||||||
|
public struct VersionedEnumerator : IEnumerator<T>
|
||||||
|
{
|
||||||
|
private int _currentItemIndex;
|
||||||
|
private readonly ulong _enumeratorVersion;
|
||||||
|
private readonly RecyclableList<T> _list;
|
||||||
|
|
||||||
|
#nullable disable
|
||||||
|
// [Pure]
|
||||||
|
public readonly T Current => _enumeratorVersion == _list._version ? _list._memoryBlock[_currentItemIndex - 1] : throw new InvalidOperationException();
|
||||||
|
// [Pure]
|
||||||
|
readonly object IEnumerator.Current => _enumeratorVersion == _list._version ? _list._memoryBlock[_currentItemIndex - 1] : throw new InvalidOperationException();
|
||||||
|
#nullable restore
|
||||||
|
|
||||||
|
public bool MoveNext()
|
||||||
|
{
|
||||||
|
if (_enumeratorVersion != _list._version)
|
||||||
|
{
|
||||||
|
throw new InvalidOperationException();
|
||||||
|
}
|
||||||
|
|
||||||
|
Contract.EndContractBlock();
|
||||||
|
|
||||||
|
if (_currentItemIndex < _list._count)
|
||||||
|
{
|
||||||
|
_currentItemIndex++;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public VersionedEnumerator(RecyclableList<T> list)
|
||||||
|
{
|
||||||
|
_currentItemIndex = 0;
|
||||||
|
_list = list;
|
||||||
|
_enumeratorVersion = list._version;
|
||||||
|
}
|
||||||
|
|
||||||
|
public readonly void Dispose()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void IEnumerator.Reset()
|
||||||
|
{
|
||||||
|
if (_enumeratorVersion != _list._version)
|
||||||
|
{
|
||||||
|
throw new InvalidOperationException();
|
||||||
|
}
|
||||||
|
|
||||||
|
_currentItemIndex = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -336,7 +336,6 @@ namespace Recyclable.CollectionsTests
|
|||||||
list.CopyTo(copiedItems, 0);
|
list.CopyTo(copiedItems, 0);
|
||||||
|
|
||||||
// Validate
|
// Validate
|
||||||
_ = copiedItems.Length.Should().Be((int)itemsCount);
|
|
||||||
_ = copiedItems.Should().ContainInConsecutiveOrder(testData);
|
_ = copiedItems.Should().ContainInConsecutiveOrder(testData);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -551,5 +550,23 @@ namespace Recyclable.CollectionsTests
|
|||||||
_ = list.Should().ContainInConsecutiveOrder(testData.Take((int)(itemsCount - deleted)));
|
_ = list.Should().ContainInConsecutiveOrder(testData.Take((int)(itemsCount - deleted)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Theory]
|
||||||
|
[MemberData(nameof(RecyclableLongListTestData.SourceDataVariants), MemberType = typeof(RecyclableLongListTestData))]
|
||||||
|
public void VersionedEnumerateShouldYieldAllItemsInCorrectOrder(string testCase, IEnumerable<long> testData, long itemsCount)
|
||||||
|
{
|
||||||
|
// Prepare
|
||||||
|
using var list = new RecyclableList<long>(testData);
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var yieldedItems = new List<long>((int)itemsCount);
|
||||||
|
foreach (var item in (IVersionedList<long>)list)
|
||||||
|
{
|
||||||
|
yieldedItems.Add(item);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Validate
|
||||||
|
_ = yieldedItems.Should().ContainInConsecutiveOrder(testData);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Reference in new issue
Block a user