diff --git a/README.md b/README.md index 03c4a2b..b4d826f 100644 --- a/README.md +++ b/README.md @@ -222,7 +222,31 @@ * `blockSize` MUST be a power of 2. It will be rounded up to the closest power of 2, if needed. That is due to high performance gain on some operations, like the calculation of item index in a block. * Array pools are shared between the same `T` type. I.e. `List` will use a different pool from `List` and so on. For high concurrency environments you may want to provide your own pools, when this feature becomes available in the upcoming releases. * Trying to access `this[int index]`, `this[long index]`, `Count`, `LongCount` etc. when `Capacity == 0` will raise `NullReferenceException`. This is by design to remove all non-critical code from the constructor. +* ⚠️ The default enumerators don't check if the collection was modified. That's by design due to high performance hit of the check. That should be fine in most use-cases. If you need to check for modifications, you're welcomed to use `.GetVersionedEnumerator()` / `IRecyclableVersionedXxxList` type-casting, e.g. in `foreach` loops. +```csharp +foreach (var item in (IRecyclableVersionedList)recyclableList) +{ + ... + ... + ... +} +foreach (var item in (IRecyclableVersionedLongList)recyclableLongList) +{ + ... + ... + ... +} +``` +* ⚠️ The state of the default enumerators before the first & after the last call to `.MoveNext()` is undefined, but no exception is raised. That's by design due to high performance hit of the checks. This behavior is compatible with all `foreach` loop, which will never access `.Current` property + * when the collection is empty, or + * when `.MoveNext()` returned `false`, after reaching the end of the collection. + +* ⚠️ If you decide to use `.GetEnumerator()` / `.GetVersionedEnumerator()`, instead of relying on `foreach` loops +* you MUST ensure that you always respect the the result of `.MoveNext()` call, and +* you MUST NEVER access `.Current` property before calling `.MoveNext()` or after reaching the end of the collection. + +**Failing to do so WILL result in unpredictable behavior.** ## `RecyclableList` * Range: `int` * Interfaces: `IList`, `IEnumerable`, `IDisposable` diff --git a/Recyclable.Collections.Benchmarks/Benchmarks/ForEach.cs b/Recyclable.Collections.Benchmarks/Benchmarks/ForEach.cs index bba42e9..b3df02a 100644 --- a/Recyclable.Collections.Benchmarks/Benchmarks/ForEach.cs +++ b/Recyclable.Collections.Benchmarks/Benchmarks/ForEach.cs @@ -60,7 +60,7 @@ public void RecyclableList_VersionedForEach() { - foreach (var item in (IVersionedList)TestObjectsAsRecyclableList) + foreach (var item in (IRecyclableVersionedList)TestObjectsAsRecyclableList) { DoNothing(item); } @@ -76,7 +76,7 @@ public void RecyclableLongList_VersionedForEach() { - foreach (var item in (IVersionedLongList)TestObjectsAsRecyclableLongList) + foreach (var item in (IRecyclableVersionedLongList)TestObjectsAsRecyclableLongList) { DoNothing(item); } diff --git a/Recyclable.Collections/IVersionedList.cs b/Recyclable.Collections/IRecyclableVersionedList.cs similarity index 62% rename from Recyclable.Collections/IVersionedList.cs rename to Recyclable.Collections/IRecyclableVersionedList.cs index b62f75e..7ae18e9 100644 --- a/Recyclable.Collections/IVersionedList.cs +++ b/Recyclable.Collections/IRecyclableVersionedList.cs @@ -1,6 +1,6 @@ namespace Recyclable.Collections { - public interface IVersionedList : IEnumerable + public interface IRecyclableVersionedList : IEnumerable { new RecyclableList.VersionedEnumerator GetEnumerator(); } diff --git a/Recyclable.Collections/IVersionedLongList.cs b/Recyclable.Collections/IRecyclableVersionedLongList.cs similarity index 62% rename from Recyclable.Collections/IVersionedLongList.cs rename to Recyclable.Collections/IRecyclableVersionedLongList.cs index 022de93..b67dd0e 100644 --- a/Recyclable.Collections/IVersionedLongList.cs +++ b/Recyclable.Collections/IRecyclableVersionedLongList.cs @@ -1,6 +1,6 @@ namespace Recyclable.Collections { - public interface IVersionedLongList : IEnumerable + public interface IRecyclableVersionedLongList : IEnumerable { new RecyclableLongList.VersionedEnumerator GetEnumerator(); } diff --git a/Recyclable.Collections/RecyclableList.VersionedEnumerator.cs b/Recyclable.Collections/RecyclableList.VersionedEnumerator.cs index d36f548..30795e0 100644 --- a/Recyclable.Collections/RecyclableList.VersionedEnumerator.cs +++ b/Recyclable.Collections/RecyclableList.VersionedEnumerator.cs @@ -4,9 +4,9 @@ using System.Runtime.InteropServices; namespace Recyclable.Collections { - public partial class RecyclableList : IVersionedList + public partial class RecyclableList : IRecyclableVersionedList { - VersionedEnumerator IVersionedList.GetEnumerator() => new(this); + VersionedEnumerator IRecyclableVersionedList.GetEnumerator() => new(this); [StructLayout(LayoutKind.Sequential, Pack = 1)] public struct VersionedEnumerator : IEnumerator diff --git a/Recyclable.Collections/RecyclableLongList.VersionedEnumerator.cs b/Recyclable.Collections/RecyclableLongList.VersionedEnumerator.cs index e11b112..843c46a 100644 --- a/Recyclable.Collections/RecyclableLongList.VersionedEnumerator.cs +++ b/Recyclable.Collections/RecyclableLongList.VersionedEnumerator.cs @@ -4,10 +4,10 @@ using System.Diagnostics.Contracts; namespace Recyclable.Collections { -public partial class RecyclableLongList : IVersionedLongList +public partial class RecyclableLongList : IRecyclableVersionedLongList { public VersionedEnumerator GetVersionedEnumerator() => new(this); - VersionedEnumerator IVersionedLongList.GetEnumerator() => new(this); + VersionedEnumerator IRecyclableVersionedLongList.GetEnumerator() => new(this); public struct VersionedEnumerator : IEnumerator { diff --git a/Recyclable.CollectionsTests/RecyclableListTests.cs b/Recyclable.CollectionsTests/RecyclableListTests.cs index 1cda68c..2e1a4a5 100644 --- a/Recyclable.CollectionsTests/RecyclableListTests.cs +++ b/Recyclable.CollectionsTests/RecyclableListTests.cs @@ -560,7 +560,7 @@ namespace Recyclable.CollectionsTests // Act var yieldedItems = new List((int)itemsCount); - foreach (var item in (IVersionedList)list) + foreach (var item in (IRecyclableVersionedList)list) { yieldedItems.Add(item); } diff --git a/Recyclable.CollectionsTests/RecyclableLongListTests.cs b/Recyclable.CollectionsTests/RecyclableLongListTests.cs index f1489a2..7704e9d 100644 --- a/Recyclable.CollectionsTests/RecyclableLongListTests.cs +++ b/Recyclable.CollectionsTests/RecyclableLongListTests.cs @@ -407,7 +407,7 @@ namespace Recyclable.CollectionsTests // Act var actual = new List(); - foreach(var item in (IVersionedLongList)list) + foreach(var item in (IRecyclableVersionedLongList)list) { actual.Add(item); }