List<T> compatibility code moved to Recyclable.Collections.Compatibility.List package. Cleanup.

This commit is contained in:
mlemanczyk committed 2023-10-21 17:29:53 +02:00
1 parent ec69b1c406
commit 203b13268f
61 files changed
+1634 -4375

No files matched your search

+1 -1
View File
@@ -3,7 +3,7 @@ The project &amp; source code is free for educational &amp; personal use. **Any
# Donation requirements for a life-time, commercial use
* Commercial license is paid one time.
* It can be obtained by donaiting $10 for each developer seat, using the link provided below. If you hire 2 developers, you need to donate $20 for a life-time, commercial use of this package.
* It can be obtained by donating $10 for each developer seat, using the link provided below. If you hire 2 developers, you need to donate $20 for a life-time, commercial use of this package.
* Your license stays with you, if your developer moves somewhere else.
# Link for donations
@@ -0,0 +1,63 @@
###############################################################################
# Set default behavior to automatically normalize line endings.
###############################################################################
* text=auto
###############################################################################
# Set default behavior for command prompt diff.
#
# This is need for earlier builds of msysgit that does not have it on by
# default for csharp files.
# Note: This is only used by command line
###############################################################################
#*.cs diff=csharp
###############################################################################
# Set the merge driver for project and solution files
#
# Merging from the command prompt will add diff markers to the files if there
# are conflicts (Merging from VS is not affected by the settings below, in VS
# the diff markers are never inserted). Diff markers may cause the following
# file extensions to fail to load in VS. An alternative would be to treat
# these files as binary and thus will always conflict and require user
# intervention with every merge. To do so, just uncomment the entries below
###############################################################################
#*.sln merge=binary
#*.csproj merge=binary
#*.vbproj merge=binary
#*.vcxproj merge=binary
#*.vcproj merge=binary
#*.dbproj merge=binary
#*.fsproj merge=binary
#*.lsproj merge=binary
#*.wixproj merge=binary
#*.modelproj merge=binary
#*.sqlproj merge=binary
#*.wwaproj merge=binary
###############################################################################
# behavior for image files
#
# image files are treated as binary by default.
###############################################################################
#*.jpg binary
#*.png binary
#*.gif binary
###############################################################################
# diff behavior for common document formats
#
# Convert binary document formats to text before diffing them. This feature
# is only available from the command line. Turn it on by uncommenting the
# entries below.
###############################################################################
#*.doc diff=astextplain
#*.DOC diff=astextplain
#*.docx diff=astextplain
#*.DOCX diff=astextplain
#*.dot diff=astextplain
#*.DOT diff=astextplain
#*.pdf diff=astextplain
#*.PDF diff=astextplain
#*.rtf diff=astextplain
#*.RTF diff=astextplain
@@ -0,0 +1,6 @@
################################################################################
# This .gitignore file was automatically created by Microsoft(R) Visual Studio.
################################################################################
/bin
/obj
@@ -1,65 +0,0 @@
namespace Recyclable.Collections.Benchmarks
{
public partial class RecyclableCollectionsBenchmarks
{
public void Array_BinarySearch_BestAndWorstCases()
{
var data = TestObjects;
var list = TestObjects;
var dataCount = TestObjectCountForSlowMethods;
for (var i = 0; i < dataCount; i++)
{
DoNothing(Array.BinarySearch(list, data[i]));
DoNothing(Array.BinarySearch(list, data[^(i + 1)]));
}
}
public void List_BinarySearch_BestAndWorstCases()
{
var data = TestObjects;
var list = TestObjectsAsList;
var dataCount = TestObjectCountForSlowMethods;
for (var i = 0; i < dataCount; i++)
{
DoNothing(list.BinarySearch(data[i]));
DoNothing(list.BinarySearch(data[^(i + 1)]));
}
}
public void PooledList_BinarySearch_BestAndWorstCases()
{
var data = TestObjects;
var list = TestObjectsAsPooledList;
var dataCount = TestObjectCountForSlowMethods;
for (var i = 0; i < dataCount; i++)
{
DoNothing(list.BinarySearch(data[i]));
DoNothing(list.BinarySearch(data[^(i + 1)]));
}
}
public void RecyclableList_BinarySearch_BestAndWorstCases()
{
var data = TestObjects;
var list = TestObjectsAsRecyclableList;
var dataCount = TestObjectCountForSlowMethods;
for (var i = 0; i < dataCount; i++)
{
DoNothing(list.BinarySearch(data[i]));
DoNothing(list.BinarySearch(data[^(i + 1)]));
}
}
// public void RecyclableLongList_BinarySearch_BestAndWorstCases()
// {
// var data = TestObjects;
// var list = TestObjectsAsRecyclableLongList;
// var dataCount = TestObjectCountForSlowMethods;
// for (var i = 0; i < dataCount; i++)
// {
// DoNothing(list.BinarySearch(data[i]));
// DoNothing(list.BinarySearch(data[^(i + 1)]));
// }
// }
}
}
@@ -1,4 +1,6 @@
namespace Recyclable.Collections.Benchmarks
using Collections.Benchmarks.Core;
namespace Recyclable.Collections.Benchmarks
{
public partial class RecyclableCollectionsBenchmarks
{
@@ -9,7 +11,7 @@
var dataCount = TestObjectCount / 10 > 0 ? TestObjectCount / 10 : TestObjectCount;
for (var i = 0; i < dataCount; i++)
{
DoNothing(Array.IndexOf(list, data[i]) >= 0);
DoNothing.With(Array.IndexOf(list, data[i]) >= 0);
}
}
@@ -20,7 +22,7 @@
var dataCount = TestObjectCount / 10 > 0 ? TestObjectCount / 10 : TestObjectCount;
for (var i = 0; i < dataCount; i++)
{
DoNothing(list.Contains(data[i]));
DoNothing.With(list.Contains(data[i]));
}
}
@@ -31,7 +33,7 @@
var dataCount = TestObjectCount / 10 > 0 ? TestObjectCount / 10 : TestObjectCount;
for (var i = 0; i < dataCount; i++)
{
DoNothing(list.Contains(data[i]));
DoNothing.With(list.Contains(data[i]));
}
}
@@ -42,7 +44,7 @@
var dataCount = TestObjectCount / 10 > 0 ? TestObjectCount / 10 : TestObjectCount;
for (var i = 0; i < dataCount; i++)
{
DoNothing(list.Contains(data[i]));
DoNothing.With(list.Contains(data[i]));
}
}
@@ -53,7 +55,7 @@
var dataCount = TestObjectCount / 10 > 0 ? TestObjectCount / 10 : TestObjectCount;
for (var i = 0; i < dataCount; i++)
{
DoNothing(list.Contains(data[i]));
DoNothing.With(list.Contains(data[i]));
}
}
}
@@ -1,4 +1,6 @@
namespace Recyclable.Collections.Benchmarks
using Collections.Benchmarks.Core;
namespace Recyclable.Collections.Benchmarks
{
public partial class RecyclableCollectionsBenchmarks
{
@@ -9,7 +11,7 @@
var dataCount = TestObjectCount / 10 > 0 ? TestObjectCount / 10 : TestObjectCount;
for (var i = 0; i < dataCount; i++)
{
DoNothing(list.Contains(data[^(i + 1)]));
DoNothing.With(list.Contains(data[^(i + 1)]));
}
}
@@ -20,7 +22,7 @@
var dataCount = TestObjectCount / 10 > 0 ? TestObjectCount / 10 : TestObjectCount;
for (var i = 0; i < dataCount; i++)
{
DoNothing(list.Contains(data[^(i + 1)]));
DoNothing.With(list.Contains(data[^(i + 1)]));
}
}
@@ -31,7 +33,7 @@
var dataCount = TestObjectCount / 10 > 0 ? TestObjectCount / 10 : TestObjectCount;
for (var i = 0; i < dataCount; i++)
{
DoNothing(list.Contains(data[^(i + 1)]));
DoNothing.With(list.Contains(data[^(i + 1)]));
}
}
@@ -42,7 +44,7 @@
var dataCount = TestObjectCount / 10 > 0 ? TestObjectCount / 10 : TestObjectCount;
for (var i = 0; i < dataCount; i++)
{
DoNothing(list.Contains(data[^(i + 1)]));
DoNothing.With(list.Contains(data[^(i + 1)]));
}
}
@@ -53,7 +55,7 @@
var dataCount = TestObjectCount / 10 > 0 ? TestObjectCount / 10 : TestObjectCount;
for (var i = 0; i < dataCount; i++)
{
DoNothing(list.Contains(data[^(i + 1)]));
DoNothing.With(list.Contains(data[^(i + 1)]));
}
}
}
@@ -1,48 +0,0 @@
namespace Recyclable.Collections.Benchmarks
{
public partial class RecyclableCollectionsBenchmarks
{
public void Array_ConvertAll()
{
var data = TestObjects;
var list = TestObjects;
var dataCount = TestObjectCountForSlowMethods;
DoNothing(Array.ConvertAll(list, static (item) => (long) item));
}
public void List_ConvertAll()
{
var data = TestObjects;
var list = TestObjectsAsList;
var dataCount = TestObjectCountForSlowMethods;
DoNothing(list.ConvertAll(static (item) => (long)item));
}
public void PooledList_ConvertAll()
{
var data = TestObjects;
var list = TestObjectsAsPooledList;
var dataCount = TestObjectCountForSlowMethods;
using var converted = list.ConvertAll(static (item) => (long)item);
DoNothing(converted);
}
public void RecyclableList_ConvertAll()
{
var data = TestObjects;
var list = TestObjectsAsRecyclableList;
var dataCount = TestObjectCountForSlowMethods;
using RecyclableList<long> converted = list.ConvertAll(static (item) => (long)item);
DoNothing(converted);
}
// public void RecyclableLongList_ConvertAll()
// {
// var data = TestObjects;
// var list = TestObjectsAsRecyclableLongList;
// var dataCount = TestObjectCountForSlowMethods;
// using RecyclableList<long> converted = list.ConvertAll(static (item) => (long)item);
// DoNothing(converted);
// }
}
}
@@ -1,35 +1,37 @@
namespace Recyclable.Collections.Benchmarks
using Collections.Benchmarks.Core;
namespace Recyclable.Collections.Benchmarks
{
public partial class RecyclableCollectionsBenchmarks
{
public void Array_Count()
{
var data = TestObjects;
DoNothing(data.Length);
DoNothing.With(data.Length);
}
public void List_Count()
{
var data = TestObjectsAsList;
DoNothing(data.Count);
DoNothing.With(data.Count);
}
public void PooledList_Count()
{
var data = TestObjectsAsPooledList;
DoNothing(data.Count);
DoNothing.With(data.Count);
}
public void RecyclableList_Count()
{
var data = TestObjectsAsRecyclableList;
DoNothing(data.Count);
DoNothing.With(data.Count);
}
public void RecyclableLongList_Count()
{
var data = TestObjectsAsRecyclableLongList;
DoNothing(data.Count);
DoNothing.With(data.Count);
}
}
}
@@ -1,4 +1,5 @@
using Collections.Pooled;
using Collections.Benchmarks.Core;
#pragma warning disable CA1822, CA1825
@@ -9,31 +10,31 @@ namespace Recyclable.Collections.Benchmarks
public void Array_Create()
{
var list = new int[0];
DoNothing(list);
DoNothing.With(list);
}
public void List_Create()
{
var list = new List<int>();
DoNothing(list);
DoNothing.With(list);
}
public void PooledList_Create()
{
using var list = new PooledList<int>(ClearMode.Auto);
DoNothing(list);
DoNothing.With(list);
}
public void RecyclableList_Create()
{
using var list = new RecyclableList<int>();
DoNothing(list);
DoNothing.With(list);
}
public void RecyclableLongList_Create()
{
using var list = new RecyclableLongList<int>();
DoNothing(list);
DoNothing.With(list);
}
}
}
@@ -1,4 +1,5 @@
using Collections.Pooled;
using Collections.Benchmarks.Core;
namespace Recyclable.Collections.Benchmarks
{
@@ -7,31 +8,31 @@ namespace Recyclable.Collections.Benchmarks
public void Array_Create_WithCapacity()
{
var data = new int[TestObjectCount];
DoNothing(data);
DoNothing.With(data);
}
public void List_Create_WithCapacity()
{
var list = new List<int>(TestObjectCount);
DoNothing(list);
DoNothing.With(list);
}
public void PooledList_Create_WithCapacity()
{
using var list = new PooledList<int>(capacity: TestObjectCount, ClearMode.Auto);
DoNothing(list);
DoNothing.With(list);
}
public void RecyclableList_Create_WithCapacity()
{
using var list = new RecyclableList<int>(TestObjectCount);
DoNothing(list);
DoNothing.With(list);
}
public void RecyclableLongList_Create_WithCapacity()
{
using var list = new RecyclableLongList<int>(minBlockSize: BlockSize, initialCapacity: TestObjectCount);
DoNothing(list);
DoNothing.With(list);
}
}
}
@@ -1,65 +0,0 @@
namespace Recyclable.Collections.Benchmarks
{
public partial class RecyclableCollectionsBenchmarks
{
public void Array_Exists_BestAndWorstCases()
{
var data = TestObjects;
var list = TestObjects;
var dataCount = TestObjectCountForSlowMethods;
for (var i = 0; i < dataCount; i++)
{
DoNothing(Array.Exists(list, (x) => x == data[i]));
DoNothing(Array.Exists(list, (x) => x == data[^(i + 1)]));
}
}
public void List_Exists_BestAndWorstCases()
{
var data = TestObjects;
var list = TestObjectsAsList;
var dataCount = TestObjectCountForSlowMethods;
for (var i = 0; i < dataCount; i++)
{
DoNothing(list.Exists((x) => x == data[i]));
DoNothing(list.Exists((x) => x == data[^(i + 1)]));
}
}
public void PooledList_Exists_BestAndWorstCases()
{
var data = TestObjects;
var list = TestObjectsAsPooledList;
var dataCount = TestObjectCountForSlowMethods;
for (var i = 0; i < dataCount; i++)
{
DoNothing(list.Exists((x) => x == data[i]));
DoNothing(list.Exists((x) => x == data[^(i + 1)]));
}
}
public void RecyclableList_Exists_BestAndWorstCases()
{
var data = TestObjects;
var list = TestObjectsAsRecyclableList;
var dataCount = TestObjectCountForSlowMethods;
for (var i = 0; i < dataCount; i++)
{
DoNothing(list.Exists((x) => x == data[i]));
DoNothing(list.Exists((x) => x == data[^(i + 1)]));
}
}
// public void RecyclableLongList_Exists_BestAndWorstCases()
// {
// var data = TestObjects;
// var list = TestObjectsAsRecyclableLongList;
// var dataCount = TestObjectCountForSlowMethods;
// for (var i = 0; i < dataCount; i++)
// {
// DoNothing(list.Exists((x) => x == data[i]));
// DoNothing(list.Exists((x) => x == data[^(i + 1)]));
// }
// }
}
}
@@ -1,80 +0,0 @@
namespace Recyclable.Collections.Benchmarks
{
public partial class RecyclableCollectionsBenchmarks
{
public void Array_FindAll_BestAndWorstCases()
{
var data = TestObjects;
var list = TestObjects;
var dataCount = TestObjectCountForSlowMethods;
for (var i = 0; i < dataCount; i++)
{
DoNothing(Array.FindAll(list, (item) => item == data[i]));
DoNothing(Array.FindAll(list, (item) => item == data[^(i + 1)]));
}
}
public void List_FindAll_BestAndWorstCases()
{
var data = TestObjects;
var list = TestObjectsAsList;
var dataCount = TestObjectCountForSlowMethods;
for (var i = 0; i < dataCount; i++)
{
DoNothing(list.FindAll((item) => item == data[i]));
DoNothing(list.FindAll((item) => item == data[^(i + 1)]));
}
}
public void PooledList_FindAll_BestAndWorstCases()
{
var data = TestObjects;
var list = TestObjectsAsPooledList;
var dataCount = TestObjectCountForSlowMethods;
for (var i = 0; i < dataCount; i++)
{
var temp = list.FindAll((item) => item == data[i]);
DoNothing(temp);
temp.Dispose();
temp = list.FindAll((item) => item == data[^(i + 1)]);
DoNothing(temp);
temp.Dispose();
}
}
public void RecyclableList_FindAll_BestAndWorstCases()
{
var data = TestObjects;
var list = TestObjectsAsRecyclableList;
var dataCount = TestObjectCountForSlowMethods;
for (var i = 0; i < dataCount; i++)
{
var temp = list.FindAll((item) => item == data[i]);
DoNothing(temp);
temp.Dispose();
temp = list.FindAll((item) => item == data[^(i + 1)]);
DoNothing(temp);
temp.Dispose();
}
}
// public void RecyclableLongList_FindAll_BestAndWorstCases()
// {
// var data = TestObjects;
// var list = TestObjectsAsRecyclableLongList;
// var dataCount = TestObjectCountForSlowMethods;
// for (var i = 0; i < dataCount; i++)
// {
// var temp = list.FindAll((item) => item == data[i]);
// DoNothing(temp);
// temp.Dispose();
// temp = list.FindAll((item) => item == data[^(i + 1)]);
// DoNothing(temp);
// temp.Dispose();
// }
// }
}
}
@@ -1,63 +0,0 @@
namespace Recyclable.Collections.Benchmarks
{
public partial class RecyclableCollectionsBenchmarks
{
public void Array_FindLastIndex_BestAndWorstCases()
{
var data = TestObjects;
var list = TestObjects;
var dataCount = TestObjectCountForSlowMethods;
// Console.WriteLine($"{nameof(TestObjectCount)}={TestObjectCount}");
// Console.WriteLine($"{nameof(TestObjectCountForSlowMethods)}={TestObjectCountForSlowMethods}");
for (var i = 0; i < dataCount; i++)
{
// Console.WriteLine($"data.Length={data.Length}");
// Console.WriteLine($"{nameof(TestObjectCount)}={TestObjectCount}");
// Console.WriteLine($"{nameof(TestObjectCountForSlowMethods)}={TestObjectCountForSlowMethods}");
DoNothing(Array.FindLastIndex(list, 0, (x) => x == data[i]));
DoNothing(Array.FindLastIndex(list, 0, (x) => x == data[^(i + 1)]));
}
}
public void List_FindLastIndex_BestAndWorstCases()
{
var data = TestObjects;
var list = TestObjectsAsList;
var dataCount = TestObjectCountForSlowMethods;
// Console.WriteLine($"{nameof(TestObjectCount)}={TestObjectCount}");
// Console.WriteLine($"{nameof(TestObjectCountForSlowMethods)}={TestObjectCountForSlowMethods}");
for (var i = 0; i < dataCount; i++)
{
// Console.WriteLine($"data.Length={data.Length}");
// Console.WriteLine($"{nameof(TestObjectCount)}={TestObjectCount}");
// Console.WriteLine($"{nameof(TestObjectCountForSlowMethods)}={TestObjectCountForSlowMethods}");
DoNothing(list.FindLastIndex(0, (x) => x == data[i]));
DoNothing(list.FindLastIndex(0, (x) => x == data[^(i + 1)]));
}
}
public void RecyclableList_FindLastIndex_BestAndWorstCases()
{
var data = TestObjects;
var list = TestObjectsAsRecyclableList;
var dataCount = TestObjectCountForSlowMethods;
for (var i = 0; i < dataCount; i++)
{
DoNothing(list.FindLastIndex(0, (x) => x == data[i]));
DoNothing(list.FindLastIndex(0, (x) => x == data[^(i + 1)]));
}
}
// public void RecyclableLongList_FindLastIndex_BestAndWorstCases()
// {
// var data = TestObjects;
// var list = TestObjectsAsRecyclableLongList;
// var dataCount = TestObjectCountForSlowMethods;
// for (var i = 0; i < dataCount; i++)
// {
// DoNothing(list.FindLastIndex(0, (x) => x == data[i]));
// DoNothing(list.FindLastIndex(0, (x) => x == data[^(i + 1)]));
// }
// }
}
}
@@ -1,53 +0,0 @@
namespace Recyclable.Collections.Benchmarks
{
public partial class RecyclableCollectionsBenchmarks
{
public void Array_FindLast_BestAndWorstCases()
{
var data = TestObjects;
var list = TestObjects;
var dataCount = TestObjectCountForSlowMethods;
for (var i = 0; i < dataCount; i++)
{
DoNothing(Array.FindLast(list, (x) => x == data[i]));
DoNothing(Array.FindLast(list, (x) => x == data[^(i + 1)]));
}
}
public void List_FindLast_BestAndWorstCases()
{
var data = TestObjects;
var list = TestObjectsAsList;
var dataCount = TestObjectCountForSlowMethods;
for (var i = 0; i < dataCount; i++)
{
DoNothing(list.FindLast((x) => x == data[i]));
DoNothing(list.FindLast((x) => x == data[^(i + 1)]));
}
}
public void RecyclableList_FindLast_BestAndWorstCases()
{
var data = TestObjects;
var list = TestObjectsAsRecyclableList;
var dataCount = TestObjectCountForSlowMethods;
for (var i = 0; i < dataCount; i++)
{
DoNothing(list.FindLast((x) => x == data[i]));
DoNothing(list.FindLast((x) => x == data[^(i + 1)]));
}
}
// public void RecyclableLongList_FindLast_BestAndWorstCases()
// {
// var data = TestObjects;
// var list = TestObjectsAsRecyclableLongList;
// var dataCount = TestObjectCountForSlowMethods;
// for (var i = 0; i < dataCount; i++)
// {
// DoNothing(list.FindLast((x) => x == data[i]));
// DoNothing(list.FindLast((x) => x == data[^(i + 1)]));
// }
// }
}
}
@@ -1,53 +0,0 @@
namespace Recyclable.Collections.Benchmarks
{
public partial class RecyclableCollectionsBenchmarks
{
public void Array_Find_BestAndWorstCases()
{
var data = TestObjects;
var list = TestObjects;
var dataCount = TestObjectCountForSlowMethods;
for (var i = 0; i < dataCount; i++)
{
DoNothing(Array.Find(list, (x) => x == data[i]));
DoNothing(Array.Find(list, (x) => x == data[^(i + 1)]));
}
}
public void List_Find_BestAndWorstCases()
{
var data = TestObjects;
var list = TestObjectsAsList;
var dataCount = TestObjectCountForSlowMethods;
for (var i = 0; i < dataCount; i++)
{
DoNothing(list.Find((x) => x == data[i]));
DoNothing(list.Find((x) => x == data[^(i + 1)]));
}
}
public void RecyclableList_Find_BestAndWorstCases()
{
var data = TestObjects;
var list = TestObjectsAsRecyclableList;
var dataCount = TestObjectCountForSlowMethods;
for (var i = 0; i < dataCount; i++)
{
DoNothing(list.Find((x) => x == data[i]));
DoNothing(list.Find((x) => x == data[^(i + 1)]));
}
}
// public void RecyclableLongList_Find_BestAndWorstCases()
// {
// var data = TestObjects;
// var list = TestObjectsAsRecyclableLongList;
// var dataCount = TestObjectCountForSlowMethods;
// for (var i = 0; i < dataCount; i++)
// {
// DoNothing(list.Find((x) => x == data[i]));
// DoNothing(list.Find((x) => x == data[^(i + 1)]));
// }
// }
}
}
@@ -1,4 +1,6 @@
namespace Recyclable.Collections.Benchmarks
using Collections.Benchmarks.Core;
namespace Recyclable.Collections.Benchmarks
{
public partial class RecyclableCollectionsBenchmarks
{
@@ -6,7 +8,7 @@
{
foreach (var item in TestObjects)
{
DoNothing(item);
DoNothing.With(item);
}
}
@@ -14,7 +16,7 @@
{
foreach (var item in TestObjects)
{
DoNothing(item);
DoNothing.With(item);
}
}
@@ -22,7 +24,7 @@
{
foreach (var item in TestObjectsAsList)
{
DoNothing(item);
DoNothing.With(item);
}
}
@@ -30,7 +32,7 @@
{
foreach (var item in TestObjectsAsList)
{
DoNothing(item);
DoNothing.With(item);
}
}
@@ -38,7 +40,7 @@
{
foreach (var item in TestObjectsAsPooledList)
{
DoNothing(item);
DoNothing.With(item);
}
}
@@ -46,7 +48,7 @@
{
foreach (var item in TestObjectsAsPooledList)
{
DoNothing(item);
DoNothing.With(item);
}
}
@@ -54,15 +56,15 @@
{
foreach (var item in TestObjectsAsRecyclableList)
{
DoNothing(item);
DoNothing.With(item);
}
}
public void RecyclableList_VersionedForEach()
{
foreach (var item in (IRecyclableVersionedList<long>)TestObjectsAsRecyclableList)
foreach (var item in (IRecyclableVersionedList<int>)TestObjectsAsRecyclableList)
{
DoNothing(item);
DoNothing.With(item);
}
}
@@ -70,15 +72,15 @@
{
foreach (var item in TestObjectsAsRecyclableLongList)
{
DoNothing(item);
DoNothing.With(item);
}
}
public void RecyclableLongList_VersionedForEach()
{
foreach (var item in (IRecyclableVersionedLongList<long>)TestObjectsAsRecyclableLongList)
foreach (var item in (IRecyclableVersionedLongList<int>)TestObjectsAsRecyclableLongList)
{
DoNothing(item);
DoNothing.With(item);
}
}
}
@@ -1,4 +1,6 @@
namespace Recyclable.Collections.Benchmarks
using Collections.Benchmarks.Core;
namespace Recyclable.Collections.Benchmarks
{
public partial class RecyclableCollectionsBenchmarks
{
@@ -8,7 +10,7 @@
var dataCount = TestObjectCount;
for (var i = 0; i < dataCount; i++)
{
DoNothing(data[i]);
DoNothing.With(data[i]);
}
}
@@ -18,7 +20,7 @@
var dataCount = TestObjectCount;
for (var i = 0; i < dataCount; i++)
{
DoNothing(data[i]);
DoNothing.With(data[i]);
}
}
@@ -28,7 +30,7 @@
var dataCount = TestObjectCount;
for (var i = 0; i < dataCount; i++)
{
DoNothing(data[i]);
DoNothing.With(data[i]);
}
}
@@ -38,7 +40,7 @@
var dataCount = TestObjectCount;
for (var i = 0; i < dataCount; i++)
{
DoNothing(data[i]);
DoNothing.With(data[i]);
}
}
@@ -48,7 +50,7 @@
var dataCount = TestObjectCount;
for (var i = 0; i < dataCount; i++)
{
DoNothing(data[i]);
DoNothing.With(data[i]);
}
}
@@ -64,7 +66,7 @@
var memoryBlock = new Span<int>(memoryBlocks[blockIndex], 0, blockSize);
for (var itemIndex = 0; itemIndex < blockSize; itemIndex++)
{
DoNothing(memoryBlock[itemIndex]);
DoNothing.With(memoryBlock[itemIndex]);
}
}
@@ -73,7 +75,7 @@
var memoryBlock = new Span<int>(memoryBlocks[nextItemBlockIndex], 0, data.NextItemIndex);
for (var itemIndex = 0; itemIndex < memoryBlock.Length; itemIndex++)
{
DoNothing(memoryBlock[itemIndex]);
DoNothing.With(memoryBlock[itemIndex]);
}
}
}
@@ -90,7 +92,7 @@
var memoryBlock = memoryBlocks[blockIndex];
for (var itemIndex = 0; itemIndex < blockSize; itemIndex++)
{
DoNothing(memoryBlock[itemIndex]);
DoNothing.With(memoryBlock[itemIndex]);
}
}
@@ -100,7 +102,7 @@
blockSize = data.NextItemIndex;
for (var itemIndex = 0; itemIndex < blockSize; itemIndex++)
{
DoNothing(memoryBlock[itemIndex]);
DoNothing.With(memoryBlock[itemIndex]);
}
}
}
@@ -110,7 +112,7 @@
var data = TestObjectsAsRecyclableLongList;
foreach (var item in data)
{
DoNothing(item);
DoNothing.With(item);
}
}
@@ -131,7 +133,7 @@
var memoryBlock = memoryBlocks[0];
while (blockIndex < nextItemBlockIndex)
{
DoNothing(memoryBlock[itemIndex]);
DoNothing.With(memoryBlock[itemIndex]);
if (itemIndex + 1 < blockSize)
{
itemIndex++;
@@ -150,7 +152,7 @@
blockSize = data.NextItemIndex;
while (itemIndex < blockSize)
{
DoNothing(memoryBlock[itemIndex++]);
DoNothing.With(memoryBlock[itemIndex++]);
}
}
}
@@ -1,4 +1,6 @@
namespace Recyclable.Collections.Benchmarks
using Collections.Benchmarks.Core;
namespace Recyclable.Collections.Benchmarks
{
public partial class RecyclableCollectionsBenchmarks
{
@@ -9,8 +11,8 @@
var dataCount = TestObjectCountForSlowMethods;
for (var i = 0; i < dataCount; i++)
{
DoNothing(Array.IndexOf(list, data[i]));
DoNothing(Array.IndexOf(list, data[^(i + 1)]));
DoNothing.With(Array.IndexOf(list, data[i]));
DoNothing.With(Array.IndexOf(list, data[^(i + 1)]));
}
}
@@ -21,8 +23,8 @@
var dataCount = TestObjectCountForSlowMethods;
for (var i = 0; i < dataCount; i++)
{
DoNothing(list.IndexOf(data[i]));
DoNothing(list.IndexOf(data[^(i + 1)]));
DoNothing.With(list.IndexOf(data[i]));
DoNothing.With(list.IndexOf(data[^(i + 1)]));
}
}
@@ -33,8 +35,8 @@
var dataCount = TestObjectCountForSlowMethods;
for (var i = 0; i < dataCount; i++)
{
DoNothing(list.IndexOf(data[i]));
DoNothing(list.IndexOf(data[^(i + 1)]));
DoNothing.With(list.IndexOf(data[i]));
DoNothing.With(list.IndexOf(data[^(i + 1)]));
}
}
@@ -45,8 +47,8 @@
var dataCount = TestObjectCountForSlowMethods;
for (var i = 0; i < dataCount; i++)
{
DoNothing(list.IndexOf(data[i]));
DoNothing(list.IndexOf(data[^(i + 1)]));
DoNothing.With(list.IndexOf(data[i]));
DoNothing.With(list.IndexOf(data[^(i + 1)]));
}
}
@@ -57,8 +59,8 @@
var dataCount = TestObjectCountForSlowMethods;
for (var i = 0; i < dataCount; i++)
{
DoNothing(list.IndexOf(data[i]));
DoNothing(list.IndexOf(data[^(i + 1)]));
DoNothing.With(list.IndexOf(data[i]));
DoNothing.With(list.IndexOf(data[^(i + 1)]));
}
}
@@ -69,8 +71,8 @@
var dataCount = TestObjectCountForSlowMethods;
for (var i = 0; i < dataCount; i++)
{
DoNothing(list.IndexOf(data[i]));
DoNothing(list.LongIndexOf(data[^(i + 1)]));
DoNothing.With(list.IndexOf(data[i]));
DoNothing.With(list.LongIndexOf(data[^(i + 1)]));
}
}
}
@@ -1,4 +1,6 @@
namespace Recyclable.Collections.Benchmarks
using Collections.Benchmarks.Core;
namespace Recyclable.Collections.Benchmarks
{
public partial class RecyclableCollectionsBenchmarks
{
@@ -9,7 +11,7 @@
var dataCount = TestObjectCountForSlowMethods;
for (var i = 0; i < dataCount; i++)
{
DoNothing(Array.IndexOf(list, data[i]));
DoNothing.With(Array.IndexOf(list, data[i]));
}
}
@@ -20,7 +22,7 @@
var dataCount = TestObjectCountForSlowMethods;
for (var i = 0; i < dataCount; i++)
{
DoNothing(list.IndexOf(data[i]));
DoNothing.With(list.IndexOf(data[i]));
}
}
@@ -31,7 +33,7 @@
var dataCount = TestObjectCountForSlowMethods;
for (var i = 0; i < dataCount; i++)
{
DoNothing(list.IndexOf(data[i]));
DoNothing.With(list.IndexOf(data[i]));
}
}
@@ -42,7 +44,7 @@
var dataCount = TestObjectCountForSlowMethods;
for (var i = 0; i < dataCount; i++)
{
DoNothing(list.IndexOf(data[i]));
DoNothing.With(list.IndexOf(data[i]));
}
}
@@ -53,7 +55,7 @@
var dataCount = TestObjectCountForSlowMethods;
for (var i = 0; i < dataCount; i++)
{
DoNothing(list.IndexOf(data[i]));
DoNothing.With(list.IndexOf(data[i]));
}
}
@@ -64,7 +66,7 @@
var dataCount = TestObjectCountForSlowMethods;
for (var i = 0; i < dataCount; i++)
{
DoNothing(list.LongIndexOf(data[i]));
DoNothing.With(list.LongIndexOf(data[i]));
}
}
}
@@ -1,4 +1,6 @@
namespace Recyclable.Collections.Benchmarks
using Collections.Benchmarks.Core;
namespace Recyclable.Collections.Benchmarks
{
public partial class RecyclableCollectionsBenchmarks
{
@@ -9,7 +11,7 @@
var dataCount = TestObjectCountForSlowMethods;
for (var i = 0; i < dataCount; i++)
{
DoNothing(Array.IndexOf(list, data[^(i + 1)]));
DoNothing.With(Array.IndexOf(list, data[^(i + 1)]));
}
}
@@ -20,7 +22,7 @@
var dataCount = TestObjectCountForSlowMethods;
for (var i = 0; i < dataCount; i++)
{
DoNothing(list.IndexOf(data[^(i + 1)]));
DoNothing.With(list.IndexOf(data[^(i + 1)]));
}
}
@@ -31,7 +33,7 @@
var dataCount = TestObjectCountForSlowMethods;
for (var i = 0; i < dataCount; i++)
{
DoNothing(list.IndexOf(data[^(i + 1)]));
DoNothing.With(list.IndexOf(data[^(i + 1)]));
}
}
@@ -42,7 +44,7 @@
var dataCount = TestObjectCountForSlowMethods;
for (var i = 0; i < dataCount; i++)
{
DoNothing(list.IndexOf(data[^(i + 1)]));
DoNothing.With(list.IndexOf(data[^(i + 1)]));
}
}
@@ -53,7 +55,7 @@
var dataCount = TestObjectCountForSlowMethods;
for (var i = 0; i < dataCount; i++)
{
DoNothing(list.IndexOf(data[^(i + 1)]));
DoNothing.With(list.IndexOf(data[^(i + 1)]));
}
}
@@ -64,7 +66,7 @@
var dataCount = TestObjectCountForSlowMethods;
for (var i = 0; i < dataCount; i++)
{
DoNothing(list.LongIndexOf(data[^(i + 1)]));
DoNothing.With(list.LongIndexOf(data[^(i + 1)]));
}
}
}
@@ -1,17 +1,19 @@
namespace Recyclable.Collections.Benchmarks
using Collections.Benchmarks.Core;
namespace Recyclable.Collections.Benchmarks
{
public partial class RecyclableCollectionsBenchmarks
{
public void Array_LongCount()
{
var data = TestObjects;
DoNothing(data.LongLength);
DoNothing.With(data.LongLength);
}
public void RecyclableLongList_LongCount()
{
var data = TestObjectsAsRecyclableLongList;
DoNothing(data.LongCount);
DoNothing.With(data.LongCount);
}
}
}
@@ -1,100 +1,115 @@
using System.Reflection;
using BenchmarkDotNet.Attributes;
using BenchmarkDotNet.Attributes;
using Collections.Benchmarks.Core;
namespace Recyclable.Collections.Benchmarks
{
public enum RecyclableCollectionsBenchmarkType
public partial class RecyclableCollectionsBenchmarks : DataDrivenBenchmarksBase<CollectionsBenchmarksSource>
{
Unknown, Add_WithCapacity, Add, AddRange_WithCapacity, AddRangeWhenSourceIsArray, AddRangeWhenSourceIsIEnumerable,
AddRangeWhenSourceIsIList, AddRangeWhenSourceIsList, AddRangeWhenSourceIsSameType, BinarySearch_BestAndWorstCases,
Contains_FirstItems, Contains_LastItems, ConvertAll, Count, Create_WithCapacity, Create, Exists_BestAndWorstCases,
Find_BestAndWorstCases, FindAll_BestAndWorstCases, FindLast_BestAndWorstCases, FindLastIndex_BestAndWorstCases,
ForEach, GetItem, IndexOf_BestAndWorstCases,IndexOf_FirstItems, IndexOf_LastItems, LongCount,
Remove_FirstItems, Remove_LastItems, RemoveAt_FirstItems, RemoveAt_LastItems,
SetItem, VersionedForEach
}
protected override string GetTestMethodName(CollectionsBenchmarksSource benchmarkType) => TestCase switch
{
CollectionsBenchmarkType.AddRangeWhenSourceIsSameType => $"{benchmarkType}_AddRangeWhenSourceIs{benchmarkType}",
_ => $"{benchmarkType}_{TestCase}"
};
public partial class RecyclableCollectionsBenchmarks : RecyclableBenchmarkBase<RecyclableCollectionsBenchmarkSource>
{
public RecyclableCollectionsBenchmarks()
{
TestObjectCount = 1;
//BaseDataType = RecyclableCollectionsBenchmarkSource.List;
DataType = RecyclableCollectionsBenchmarkSource.RecyclableList;
//BaseDataType = RecyclableCollectionsBenchmarksSource.List;
DataType = CollectionsBenchmarksSource.RecyclableList;
}
[Params
(
RecyclableCollectionsBenchmarkType.Add_WithCapacity,
RecyclableCollectionsBenchmarkType.Add,
RecyclableCollectionsBenchmarkType.AddRange_WithCapacity,
RecyclableCollectionsBenchmarkType.AddRangeWhenSourceIsArray,
RecyclableCollectionsBenchmarkType.AddRangeWhenSourceIsIEnumerable,
RecyclableCollectionsBenchmarkType.AddRangeWhenSourceIsIList,
RecyclableCollectionsBenchmarkType.AddRangeWhenSourceIsList,
RecyclableCollectionsBenchmarkType.AddRangeWhenSourceIsSameType,
RecyclableCollectionsBenchmarkType.BinarySearch_BestAndWorstCases,
RecyclableCollectionsBenchmarkType.Contains_FirstItems,
RecyclableCollectionsBenchmarkType.Contains_LastItems,
RecyclableCollectionsBenchmarkType.ConvertAll,
RecyclableCollectionsBenchmarkType.Count,
RecyclableCollectionsBenchmarkType.Create_WithCapacity,
RecyclableCollectionsBenchmarkType.Create,
RecyclableCollectionsBenchmarkType.Exists_BestAndWorstCases,
RecyclableCollectionsBenchmarkType.Find_BestAndWorstCases,
RecyclableCollectionsBenchmarkType.FindAll_BestAndWorstCases,
RecyclableCollectionsBenchmarkType.FindLast_BestAndWorstCases,
RecyclableCollectionsBenchmarkType.FindLastIndex_BestAndWorstCases,
RecyclableCollectionsBenchmarkType.ForEach,
RecyclableCollectionsBenchmarkType.GetItem,
RecyclableCollectionsBenchmarkType.IndexOf_BestAndWorstCases,
RecyclableCollectionsBenchmarkType.IndexOf_FirstItems,
RecyclableCollectionsBenchmarkType.IndexOf_LastItems,
RecyclableCollectionsBenchmarkType.LongCount,
RecyclableCollectionsBenchmarkType.Remove_FirstItems,
RecyclableCollectionsBenchmarkType.Remove_LastItems,
RecyclableCollectionsBenchmarkType.RemoveAt_FirstItems,
RecyclableCollectionsBenchmarkType.RemoveAt_LastItems,
RecyclableCollectionsBenchmarkType.SetItem,
RecyclableCollectionsBenchmarkType.VersionedForEach
)]
// 0 2 4 8 16 32 64 128 256 512 1024 2048 4096 8192 16384 32768 65536 131072 262144 524_288
// 1048576 2097152 4194304 8388608 16777216 33554432 67108864 134217728 268435456 536870912
// 1073741824 2147483648
public RecyclableCollectionsBenchmarkType TestCase { get; set; } = RecyclableCollectionsBenchmarkType.IndexOf_BestAndWorstCases;
// [Params(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 30, 32, 40, 50, 60, 80, 90, 100, 128, 256, 512, 1024, 2048, 4096, 8192, 1_000_000)]
// [Params(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 30, 32, 40, 50, 60, 80, 90, 100, 128, 256, 512, 1024, 2048, 4096, 8192, 1_000_000)]
// [Params(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 30, 32, 40, 50, 60, 80, 90, 100, 128, 256, 512, 1024, 2048, 4096, 8192, 100_000_000)]
// [Params(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 30, 32, 40, 50, 60, 80, 90, 100, 128, 256, 512, 1024, 2048, 4096, 8192, 850_000 - 1, 1_000_000, RecyclableDefaults.MaxPooledBlockSize)]
// [Params(1_000_000, 10_000_000, 100_000_000, 1_000_000_000)]
// [Params(1, 10, 64, 128, 192, 256, 512, 1024, 2048, 4096, 8192, 16384, 32768, 65536, 131072, 262144)]
// [Params(524_288, 786_432, 1_048_576)]
// [Params(262_144, 393_216, 524_288)]
// [Params(850_000_000)]
// [Params(100_000_000)]
// [Params(RecyclableDefaults.MinItemsCountForParallelization)]
[Params(16_384)]
// [Params(127)]
// [Params(16)]
// [Params(10, 15, 128)]
// [Params(1)]
// [Params(RecyclableDefaults.MaxPooledBlockSize)]
// [Params(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 30, 32, 40, 50, 60, 80, 90, 100, 128, 256, 512, 1024, 2048, 4096, 8192, 16384, 32768, 65536, 131072, 262144, 524288, 1048576, 10_000_000, 33_554_432, 50_000_000, 100_000_000)]
// *** [Params(RecyclableDefaults.MinPooledArrayLength - 3, RecyclableDefaults.MinPooledArrayLength - 2, RecyclableDefaults.MinPooledArrayLength - 1, RecyclableDefaults.MinPooledArrayLength, RecyclableDefaults.MinPooledArrayLength + 1, RecyclableDefaults.MinPooledArrayLength + 2, RecyclableDefaults.MinPooledArrayLength + 3)]
// *** [Params(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 30, 32, 40, RecyclableDefaults.MinPooledArrayLength - 1, RecyclableDefaults.MinPooledArrayLength, 40, 50, 60, 70, 80, 90, 100, 128, 256, 512, 1024, 2048, 4096, 8192, 16384, 32768, 65536, 131072, RecyclableDefaults.MinItemsCountForParallelization)]
// *** [Params(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 30, 32, 40, RecyclableDefaults.MinPooledArrayLength - 1, RecyclableDefaults.MinPooledArrayLength, 40, 50, 60, 70, 80, 90, 100, 128, 256, 512, 1024, 2048, 4096, 8192, 16384, 32768, 65536, 131072, RecyclableDefaults.MinItemsCountForParallelization)]
// [Params(256, 512, 1024, 2048, 4096, 8192, 16384, 32768, 65536, 131072, RecyclableDefaults.MinItemsCountForParallelization)]
// [Params(RecyclableDefaults.MinItemsCountForParallelization, 1_048_576, 2_097_152, 4_194_304, 8_388_608, 16_777_216, 33_554_432, RecyclableDefaults.MaxPooledBlockSize)]
// *** [Params(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 30, RecyclableDefaults.MinPooledArrayLength - 1, RecyclableDefaults.MinPooledArrayLength, 40, 50, 60, 64, 70, 80, 90, 100, 127, 128)]
// [Params(1, 10, 1024, 10240, RecyclableDefaults.MinPooledArrayLength, RecyclableDefaults.MinItemsCountForParallelization)]
// [Params(RecyclableDefaults.MinItemsCountForParallelization * 3)]
// [Params(1_048_576)]
public override int TestObjectCount { get => base.TestObjectCount; set => base.TestObjectCount = value; }
[Params
(
RecyclableCollectionsBenchmarkSource.List
CollectionsBenchmarksSource.Array,
CollectionsBenchmarksSource.List,
CollectionsBenchmarksSource.PooledList,
CollectionsBenchmarksSource.RecyclableList,
CollectionsBenchmarksSource.RecyclableLongList
)]
public override RecyclableCollectionsBenchmarkSource BaseDataType { get => base.BaseDataType; set => base.BaseDataType = value; }
public override CollectionsBenchmarksSource DataType { get => base.DataType; set => base.DataType = value; }
[Params
(
RecyclableCollectionsBenchmarkSource.Array,
RecyclableCollectionsBenchmarkSource.List,
RecyclableCollectionsBenchmarkSource.PooledList,
RecyclableCollectionsBenchmarkSource.RecyclableList,
RecyclableCollectionsBenchmarkSource.RecyclableLongList
CollectionsBenchmarkType.Add_WithCapacity,
CollectionsBenchmarkType.Add,
CollectionsBenchmarkType.AddRange_WithCapacity,
CollectionsBenchmarkType.AddRangeWhenSourceIsArray,
CollectionsBenchmarkType.AddRangeWhenSourceIsIEnumerable,
CollectionsBenchmarkType.AddRangeWhenSourceIsIList,
CollectionsBenchmarkType.AddRangeWhenSourceIsList,
CollectionsBenchmarkType.AddRangeWhenSourceIsSameType,
CollectionsBenchmarkType.BinarySearch_BestAndWorstCases,
CollectionsBenchmarkType.Contains_FirstItems,
CollectionsBenchmarkType.Contains_LastItems,
CollectionsBenchmarkType.ConvertAll,
CollectionsBenchmarkType.Count,
CollectionsBenchmarkType.Create_WithCapacity,
CollectionsBenchmarkType.Create,
CollectionsBenchmarkType.Exists_BestAndWorstCases,
CollectionsBenchmarkType.Find_BestAndWorstCases,
CollectionsBenchmarkType.FindAll_BestAndWorstCases,
CollectionsBenchmarkType.FindLast_BestAndWorstCases,
CollectionsBenchmarkType.FindLastIndex_BestAndWorstCases,
CollectionsBenchmarkType.ForEach,
CollectionsBenchmarkType.GetItem,
CollectionsBenchmarkType.IndexOf_BestAndWorstCases,
CollectionsBenchmarkType.IndexOf_FirstItems,
CollectionsBenchmarkType.IndexOf_LastItems,
CollectionsBenchmarkType.LongCount,
CollectionsBenchmarkType.Remove_FirstItems,
CollectionsBenchmarkType.Remove_LastItems,
CollectionsBenchmarkType.RemoveAt_FirstItems,
CollectionsBenchmarkType.RemoveAt_LastItems,
CollectionsBenchmarkType.SetItem,
CollectionsBenchmarkType.VersionedForEach
)]
public override RecyclableCollectionsBenchmarkSource DataType { get => base.DataType; set => base.DataType = value; }
protected override Action? GetTestMethod(RecyclableCollectionsBenchmarkSource benchmarkType)
=> TestCase switch
{
RecyclableCollectionsBenchmarkType.AddRangeWhenSourceIsSameType => (Action?)GetType().GetMethod($"{benchmarkType}_AddRangeWhenSourceIs{benchmarkType}", BindingFlags.Instance | BindingFlags.Public)?.CreateDelegate(typeof(Action), this),
_ => (Action?) GetType().GetMethod($"{benchmarkType}_{TestCase}", BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public)?.CreateDelegate(typeof(Action), this) ?? throw new InvalidOperationException($"Method {benchmarkType}_{TestCase} not found in class {GetType().FullName}")
};
public virtual CollectionsBenchmarkType TestCase { get; set; }
public override void Setup()
{
base.Setup();
switch(TestCase)
{
case RecyclableCollectionsBenchmarkType.AddRangeWhenSourceIsIList:
PrepareData(RecyclableCollectionsBenchmarkSource.RecyclableLongList);
case CollectionsBenchmarkType.AddRangeWhenSourceIsIList:
PrepareData(CollectionsBenchmarksSource.RecyclableLongList);
break;
case RecyclableCollectionsBenchmarkType.AddRangeWhenSourceIsSameType:
PrepareData(RecyclableCollectionsBenchmarkSource.RecyclableList);
case CollectionsBenchmarkType.AddRangeWhenSourceIsSameType:
PrepareData(CollectionsBenchmarksSource.RecyclableList);
break;
}
}
@@ -1,4 +1,5 @@
using Collections.Pooled;
using Collections.Benchmarks.Core;
namespace Recyclable.Collections.Benchmarks
{
@@ -11,7 +12,7 @@ namespace Recyclable.Collections.Benchmarks
var dataCount = TestObjectCount / 10 > 0 ? TestObjectCount / 10 : TestObjectCount;
for (var i = 0; i < dataCount; i++)
{
DoNothing(list.Remove(data[i]));
DoNothing.With(list.Remove(data[i]));
}
}
@@ -22,7 +23,7 @@ namespace Recyclable.Collections.Benchmarks
var dataCount = TestObjectCount / 10 > 0 ? TestObjectCount / 10 : TestObjectCount;
for (var i = 0; i < dataCount; i++)
{
DoNothing(list.Remove(data[i]));
DoNothing.With(list.Remove(data[i]));
}
}
@@ -33,7 +34,7 @@ namespace Recyclable.Collections.Benchmarks
var dataCount = TestObjectCount / 10 > 0 ? TestObjectCount / 10 : TestObjectCount;
for (var i = 0; i < dataCount; i++)
{
DoNothing(list.Remove(data[i]));
DoNothing.With(list.Remove(data[i]));
}
}
@@ -44,7 +45,7 @@ namespace Recyclable.Collections.Benchmarks
var dataCount = TestObjectCount / 10 > 0 ? TestObjectCount / 10 : TestObjectCount;
for (var i = 0; i < dataCount; i++)
{
DoNothing(list.Remove(data[i]));
DoNothing.With(list.Remove(data[i]));
}
}
}
@@ -1,4 +1,5 @@
using Collections.Pooled;
using Collections.Benchmarks.Core;
namespace Recyclable.Collections.Benchmarks
{
@@ -11,7 +12,7 @@ namespace Recyclable.Collections.Benchmarks
var dataCount = TestObjectCount / 10 > 0 ? TestObjectCount / 10 : TestObjectCount;
for (var i = data.Length - 1; i > data.Length - dataCount - 1; i--)
{
DoNothing(list.Remove(data[i]));
DoNothing.With(list.Remove(data[i]));
}
}
@@ -22,7 +23,7 @@ namespace Recyclable.Collections.Benchmarks
var dataCount = TestObjectCount / 10 > 0 ? TestObjectCount / 10 : TestObjectCount;
for (var i = data.Length - 1; i > data.Length - dataCount - 1; i--)
{
DoNothing(list.Remove(data[i]));
DoNothing.With(list.Remove(data[i]));
}
}
@@ -33,7 +34,7 @@ namespace Recyclable.Collections.Benchmarks
var dataCount = TestObjectCount / 10 > 0 ? TestObjectCount / 10 : TestObjectCount;
for (var i = data.Length - 1; i > data.Length - dataCount - 1; i--)
{
DoNothing(list.Remove(data[i]));
DoNothing.With(list.Remove(data[i]));
}
}
@@ -44,7 +45,7 @@ namespace Recyclable.Collections.Benchmarks
var dataCount = TestObjectCount / 10 > 0 ? TestObjectCount / 10 : TestObjectCount;
for (var i = data.Length - 1; i > data.Length - dataCount - 1; i--)
{
DoNothing(list.Remove(data[i]));
DoNothing.With(list.Remove(data[i]));
}
}
}
@@ -1,19 +0,0 @@
namespace Recyclable.Collections.Benchmarks.Core
{
public static class DataGenerator
{
public static long[] EnumerateTestObjects(long testObjectCount)
{
var result = new long[testObjectCount];
Console.WriteLine("******* TEST DATA ARRAY CREATED *******");
Span<long> resultSpan = result;
for (int i = 0; i < testObjectCount; i++)
{
resultSpan[i] = i;
}
return result;
}
}
}
@@ -1,18 +1,21 @@
using BenchmarkDotNet.Attributes;
// Ignore Spelling: Poc
using BenchmarkDotNet.Attributes;
using Collections.Benchmarks.Core;
using System.Buffers;
namespace Recyclable.Collections.Benchmarks.POC
{
public enum ArraySizeLimitPocBenchmarkType
public enum ArraySizeLimitBenchmarkType
{
ArraySizeLimit
}
public class ArraySizeLimitPocBenchmarks : PocBenchmarkBase<ArraySizeLimitPocBenchmarkType>
public class ArraySizeLimitBenchmarks : BaselineVsActualBenchmarkBase<ArraySizeLimitBenchmarkType>
{
public static void Run()
{
var benchmark = new ArraySizeLimitPocBenchmarks();
var benchmark = new ArraySizeLimitBenchmarks();
benchmark.Setup();
FindArraySizeLimit();
benchmark.Cleanup();
@@ -25,7 +28,7 @@ namespace Recyclable.Collections.Benchmarks.POC
public void Max_Allowed_Size_2_147_483_605()
{
long[] arr = ArrayPool<long>.Shared.Rent(TestObjectCount);
DoNothing(arr);
DoNothing.With(arr);
}
[Benchmark(OperationsPerInvoke = 1)]
@@ -0,0 +1,66 @@
// Ignore Spelling: Poc
using BenchmarkDotNet.Attributes;
using Collections.Benchmarks.Core;
namespace Recyclable.Collections.Benchmarks.POC
{
public enum BoolOrCompareBenchmarkType
{
Bool,
Compare,
}
[MemoryDiagnoser]
public class BoolOrCompareBenchmarks : BaselineVsActualBenchmarkBase<BoolOrCompareBenchmarkType>
{
[Params(BoolOrCompareBenchmarkType.Bool, BoolOrCompareBenchmarkType.Compare)]
public override BoolOrCompareBenchmarkType DataType { get => base.DataType; set => base.DataType = value; }
[Params(8)]
public override int TestObjectCount { get => base.TestObjectCount; set => base.TestObjectCount = value; }
[Params(true)]
public bool TestBool = true;
public static void Run()
{
var benchmark = new BoolOrCompareBenchmarks();
benchmark.Setup();
benchmark.Bool();
benchmark.Compare();
benchmark.Cleanup();
}
public void Bool()
{
if (TestBool)
{
DoNothing.With(TestBool);
}
else
{
DoNothing.With(TestBool);
}
}
public void Compare()
{
if (TestObjectCount >= RecyclableDefaults.MinPooledArrayLength)
{
DoNothing.With(TestBool);
}
else
{
DoNothing.With(TestBool);
}
}
protected override Action? GetTestMethod(BoolOrCompareBenchmarkType benchmarkType) => benchmarkType switch
{
BoolOrCompareBenchmarkType.Bool => Bool,
BoolOrCompareBenchmarkType.Compare => Compare,
_ => throw CreateUnknownBenchmarkTypeException(benchmarkType),
};
}
}
@@ -1,63 +0,0 @@
using BenchmarkDotNet.Attributes;
namespace Recyclable.Collections.Benchmarks.POC
{
public enum BoolOrComparePocBenchmarkType
{
Bool,
Compare,
}
[MemoryDiagnoser]
public class BoolOrComparePocBenchmarks : PocBenchmarkBase<BoolOrComparePocBenchmarkType>
{
[Params(BoolOrComparePocBenchmarkType.Bool, BoolOrComparePocBenchmarkType.Compare)]
public override BoolOrComparePocBenchmarkType DataType { get => base.DataType; set => base.DataType = value; }
[Params(8)]
public override int TestObjectCount { get => base.TestObjectCount; set => base.TestObjectCount = value; }
[Params(true)]
public bool TestBool = true;
public static void Run()
{
var benchmark = new BoolOrComparePocBenchmarks();
benchmark.Setup();
benchmark.Bool();
benchmark.Compare();
benchmark.Cleanup();
}
public void Bool()
{
if (TestBool)
{
DoNothing(TestBool);
}
else
{
DoNothing(TestBool);
}
}
public void Compare()
{
if (TestObjectCount >= RecyclableDefaults.MinPooledArrayLength)
{
DoNothing(TestBool);
}
else
{
DoNothing(TestBool);
}
}
protected override Action? GetTestMethod(BoolOrComparePocBenchmarkType benchmarkType) => benchmarkType switch
{
BoolOrComparePocBenchmarkType.Bool => Bool,
BoolOrComparePocBenchmarkType.Compare => Compare,
_ => throw CreateUnknownBenchmarkTypeException(benchmarkType),
};
}
}
@@ -0,0 +1,349 @@
// Ignore Spelling: Poc Structs Unboxed Funcs Comparers
using BenchmarkDotNet.Attributes;
using Collections.Benchmarks.Core;
namespace Recyclable.Collections.Benchmarks.POC
{
public enum DelegateVsComparerBenchmarkType
{
Comparer,
Delegate,
Func,
ListOfBoxedStructs,
ListOfClasses,
ListOfComparers,
ListOfDelegates,
ListOfFuncs,
ListOfLocalFuncs,
ListOfStructs,
ListOfUnboxedReadOnlyStructs,
ListOfUnboxedStructs,
StaticFunc,
}
[MemoryDiagnoser]
public class DelegateVsComparerBenchmarks : BaselineVsActualBenchmarkBase<DelegateVsComparerBenchmarkType>
{
[Params
(
DelegateVsComparerBenchmarkType.Delegate,
DelegateVsComparerBenchmarkType.Func,
DelegateVsComparerBenchmarkType.ListOfBoxedStructs,
DelegateVsComparerBenchmarkType.ListOfClasses,
DelegateVsComparerBenchmarkType.ListOfComparers,
DelegateVsComparerBenchmarkType.ListOfDelegates,
DelegateVsComparerBenchmarkType.ListOfFuncs,
DelegateVsComparerBenchmarkType.ListOfLocalFuncs,
DelegateVsComparerBenchmarkType.ListOfStructs,
DelegateVsComparerBenchmarkType.ListOfUnboxedReadOnlyStructs,
DelegateVsComparerBenchmarkType.ListOfUnboxedStructs,
DelegateVsComparerBenchmarkType.StaticFunc
)]
public override DelegateVsComparerBenchmarkType DataType { get => base.DataType; set => base.DataType = value; }
[Params(DelegateVsComparerBenchmarkType.Comparer)]
public override DelegateVsComparerBenchmarkType BaseDataType { get => base.BaseDataType; set => base.BaseDataType = value; }
#region Dummy classes
private delegate T Compare<T>(T x, T y);
public readonly struct MyComparerReadOnlyStruct<T> : IComparer<T>
{
public int Compare(T? x, T? y) => Comparer<T>.Default.Compare(x, y);
}
private struct MyComparerStruct<T> : IComparer<T>
{
public readonly int Compare(T? x, T? y) => Comparer<T>.Default.Compare(x, y);
}
private class MyComparer : IComparer<long>
{
public int Compare(long x, long y) => (x - y) switch
{
> 0 => 1,
< 0 => -1,
_ => 0,
};
}
#endregion
public static void Run()
{
var benchmark = new DelegateVsComparerBenchmarks();
benchmark.Setup();
benchmark.Comparer();
benchmark.Delegate();
benchmark.Func();
benchmark.ListOfBoxedStructs();
benchmark.ListOfClasses();
benchmark.ListOfComparers();
benchmark.ListOfDelegates();
benchmark.ListOfFuncs();
benchmark.ListOfLocalFuncs();
benchmark.ListOfStructs();
benchmark.ListOfUnboxedReadOnlyStructs();
benchmark.ListOfUnboxedStructs();
benchmark.StaticFunc();
benchmark.Cleanup();
}
private static readonly Comparer<long> _comparer = Comparer<long>.Default;
private IEnumerable<long>? _testObjects;
private IEnumerable<Func<long, long, int>>? _testListOfFunctions;
private IEnumerable<IComparer<long>>? _testListOfComparers;
private IEnumerable<Compare<long>>? _testListOfDelegates;
private IEnumerable<Func<long, long, int>>? _testListOfLocalFunctions;
private IEnumerable<MyComparer>? _testListOfClasses;
private IEnumerable<MyComparerStruct<long>>? _testListOfStructs;
private IEnumerable<IComparer<long>>? _testListOfBoxedStructs;
private IEnumerable<TComparer> TestListOfUnboxedStructs<TComparer, TValue>() where TComparer : IComparer<TValue>, new()
{
foreach (var _ in _testObjects!)
{
yield return new TComparer();
}
}
private static IEnumerable<Func<long, long, int>> GetLocalFunctions(IEnumerable<long> testObjects)
{
static int compareFunc(long x, long y)
{
return (x - y) switch
{
> 0 => 1,
< 0 => -1,
_ => 0
};
}
foreach (var _ in testObjects)
{
yield return compareFunc;
}
}
private void TestWithComparer(IComparer<long> comparer)
{
var testData = _testObjects!.ToArray();
for (var itemIdx = 0; itemIdx < testData.Length - 1; itemIdx++)
{
_ = comparer.Compare(testData[itemIdx], testData[itemIdx + 1]);
}
}
private void TestWithDelegate(Compare<long> compareFunc)
{
var testData = _testObjects!.ToArray();
for (var itemIdx = 0; itemIdx < testData.Length - 1; itemIdx++)
{
_ = compareFunc(testData[itemIdx], testData[itemIdx + 1]);
}
}
private void TestWithFunc(Func<long, long, int> compareFunc)
{
var testData = _testObjects!.ToArray();
for (var itemIdx = 0; itemIdx < testData.Length - 1; itemIdx++)
{
_ = compareFunc(testData[itemIdx], testData[itemIdx + 1]);
}
}
public void Comparer()
{
TestWithComparer(_comparer);
}
public void Func()
{
TestWithFunc((x, y) => (x - y) switch
{
> 0 => 1,
< 0 => -1,
_ => 0
});
}
public void StaticFunc()
{
TestWithFunc(static (x, y) => (x - y) switch
{
> 0 => 1,
< 0 => -1,
_ => 0
});
}
public void Delegate()
{
TestWithDelegate((x, y) => (x - y) switch
{
> 0 => 1,
< 0 => -1,
_ => 0
});
}
public void ListOfFuncs()
{
const long X = 2, Y = 5;
var testData = _testListOfFunctions!.ToArray();
for (var itemIdx = 0; itemIdx < testData.Length; itemIdx++)
{
var compareFunc = testData[itemIdx];
_ = compareFunc(X, Y);
}
}
public void ListOfLocalFuncs()
{
const long X = 2, Y = 5;
var testData = _testListOfLocalFunctions!.ToArray();
for (var itemIdx = 0; itemIdx < testData.Length; itemIdx++)
{
var compareFunc = testData[itemIdx];
_ = compareFunc(X, Y);
}
}
public void ListOfComparers()
{
const long X = 2, Y = 5;
var testData = _testListOfComparers!.ToArray();
for (var itemIdx = 0; itemIdx < testData.Length; itemIdx++)
{
var comparer = testData[itemIdx];
_ = comparer.Compare(X, Y);
}
}
public void ListOfClasses()
{
const long X = 2, Y = 5;
var testData = _testListOfClasses!.ToArray();
for (var itemIdx = 0; itemIdx < testData.Length; itemIdx++)
{
var comparer = testData[itemIdx];
_ = comparer.Compare(X, Y);
}
}
public void ListOfStructs()
{
const long X = 2, Y = 5;
var testData = _testListOfStructs!.ToArray();
for (var itemIdx = 0; itemIdx < testData.Length; itemIdx++)
{
var comparer = testData[itemIdx];
_ = comparer.Compare(X, Y);
}
}
public void ListOfBoxedStructs()
{
const long X = 2, Y = 5;
var testData = _testListOfBoxedStructs!.ToArray();
for (var itemIdx = 0; itemIdx < testData.Length; itemIdx++)
{
var comparer = testData[itemIdx];
_ = comparer.Compare(X, Y);
}
}
public void ListOfUnboxedStructs()
{
const long X = 2, Y = 5;
var testData = TestListOfUnboxedStructs<MyComparerStruct<long>, long>().ToArray();
for (var itemIdx = 0; itemIdx < testData.Length; itemIdx++)
{
var comparer = testData[itemIdx];
_ = comparer.Compare(X, Y);
}
}
public void ListOfUnboxedReadOnlyStructs()
{
const long X = 2, Y = 5;
var testData = TestListOfUnboxedStructs<MyComparerReadOnlyStruct<long>, long>().ToArray();
for (var itemIdx = 0; itemIdx < testData.Length; itemIdx++)
{
var comparer = testData[itemIdx];
_ = comparer.Compare(X, Y);
}
}
public void ListOfDelegates()
{
const long X = 2, Y = 5;
var testData = _testListOfDelegates!.ToArray();
for (var itemIdx = 0; itemIdx < testData.Length; itemIdx++)
{
var compareDelegate = testData[itemIdx];
_ = compareDelegate(X, Y);
}
}
protected override Action? GetTestMethod(DelegateVsComparerBenchmarkType benchmarkType) => benchmarkType switch
{
DelegateVsComparerBenchmarkType.Comparer => Comparer,
DelegateVsComparerBenchmarkType.Delegate => Delegate,
DelegateVsComparerBenchmarkType.Func => Func,
DelegateVsComparerBenchmarkType.ListOfBoxedStructs => ListOfBoxedStructs,
DelegateVsComparerBenchmarkType.ListOfClasses => ListOfClasses,
DelegateVsComparerBenchmarkType.ListOfComparers => ListOfComparers,
DelegateVsComparerBenchmarkType.ListOfDelegates => ListOfDelegates,
DelegateVsComparerBenchmarkType.ListOfFuncs => ListOfFuncs,
DelegateVsComparerBenchmarkType.ListOfLocalFuncs => ListOfLocalFuncs,
DelegateVsComparerBenchmarkType.ListOfStructs => ListOfStructs,
DelegateVsComparerBenchmarkType.ListOfUnboxedReadOnlyStructs => ListOfUnboxedReadOnlyStructs,
DelegateVsComparerBenchmarkType.ListOfUnboxedStructs => ListOfUnboxedStructs,
DelegateVsComparerBenchmarkType.StaticFunc => StaticFunc,
_ => throw CreateUnknownBenchmarkTypeException(benchmarkType),
};
public override void Setup()
{
Console.WriteLine("******* SETTING UP COMMON TEST DATA *******");
_testObjects = Enumerable.Range(1, TestObjectCount).Select(x => (long)x);
base.Setup();
}
public override void Cleanup()
{
_testObjects = null;
base.Cleanup();
}
protected override void PrepareData<T>(T benchmarkType)
{
switch (benchmarkType)
{
case DelegateVsComparerBenchmarkType.ListOfBoxedStructs:
_testListOfBoxedStructs = _testObjects!.Select(_ => (IComparer<long>)new MyComparerStruct<long>());
break;
case DelegateVsComparerBenchmarkType.ListOfClasses:
_testListOfClasses = _testObjects!.Select(_ => new MyComparer());
break;
case DelegateVsComparerBenchmarkType.ListOfComparers:
_testListOfComparers = _testObjects!.Select(_ => (IComparer<long>)new MyComparer());
break;
case DelegateVsComparerBenchmarkType.ListOfDelegates:
_testListOfDelegates = _testObjects!.Select(_ => new Compare<long>((x, y) => new MyComparer().Compare(x, y)));
break;
case DelegateVsComparerBenchmarkType.ListOfFuncs:
_testListOfFunctions = _testObjects!.Select<long, Func<long, long, int>>(static _ => new MyComparer().Compare);
break;
case DelegateVsComparerBenchmarkType.ListOfLocalFuncs:
_testListOfLocalFunctions = GetLocalFunctions(_testObjects!);
break;
case DelegateVsComparerBenchmarkType.ListOfStructs:
_testListOfStructs = _testObjects!.Select(_ => new MyComparerStruct<long>());
break;
}
}
}
}
@@ -1,346 +0,0 @@
using BenchmarkDotNet.Attributes;
namespace Recyclable.Collections.Benchmarks.POC
{
public enum DelegateVsComparerPocBenchmarkType
{
Comparer,
Delegate,
Func,
ListOfBoxedStructs,
ListOfClasses,
ListOfComparers,
ListOfDelegates,
ListOfFuncs,
ListOfLocalFuncs,
ListOfStructs,
ListOfUnboxedReadOnlyStructs,
ListOfUnboxedStructs,
StaticFunc,
}
[MemoryDiagnoser]
public class DelegateVsComparerPocBenchmarks : PocBenchmarkBase<DelegateVsComparerPocBenchmarkType>
{
[Params
(
DelegateVsComparerPocBenchmarkType.Delegate,
DelegateVsComparerPocBenchmarkType.Func,
DelegateVsComparerPocBenchmarkType.ListOfBoxedStructs,
DelegateVsComparerPocBenchmarkType.ListOfClasses,
DelegateVsComparerPocBenchmarkType.ListOfComparers,
DelegateVsComparerPocBenchmarkType.ListOfDelegates,
DelegateVsComparerPocBenchmarkType.ListOfFuncs,
DelegateVsComparerPocBenchmarkType.ListOfLocalFuncs,
DelegateVsComparerPocBenchmarkType.ListOfStructs,
DelegateVsComparerPocBenchmarkType.ListOfUnboxedReadOnlyStructs,
DelegateVsComparerPocBenchmarkType.ListOfUnboxedStructs,
DelegateVsComparerPocBenchmarkType.StaticFunc
)]
public override DelegateVsComparerPocBenchmarkType DataType { get => base.DataType; set => base.DataType = value; }
[Params(DelegateVsComparerPocBenchmarkType.Comparer)]
public override DelegateVsComparerPocBenchmarkType BaseDataType { get => base.BaseDataType; set => base.BaseDataType = value; }
#region Dummy classes
private delegate T Compare<T>(T x, T y);
public readonly struct MyComparerReadOnlyStruct<T> : IComparer<T>
{
public int Compare(T? x, T? y) => Comparer<T>.Default.Compare(x, y);
}
private struct MyComparerStruct<T> : IComparer<T>
{
public readonly int Compare(T? x, T? y) => Comparer<T>.Default.Compare(x, y);
}
private class MyComparer : IComparer<long>
{
public int Compare(long x, long y) => (x - y) switch
{
> 0 => 1,
< 0 => -1,
_ => 0,
};
}
#endregion
public static void Run()
{
var benchmark = new DelegateVsComparerPocBenchmarks();
benchmark.Setup();
benchmark.Comparer();
benchmark.Delegate();
benchmark.Func();
benchmark.ListOfBoxedStructs();
benchmark.ListOfClasses();
benchmark.ListOfComparers();
benchmark.ListOfDelegates();
benchmark.ListOfFuncs();
benchmark.ListOfLocalFuncs();
benchmark.ListOfStructs();
benchmark.ListOfUnboxedReadOnlyStructs();
benchmark.ListOfUnboxedStructs();
benchmark.StaticFunc();
benchmark.Cleanup();
}
private static readonly Comparer<long> _comparer = Comparer<long>.Default;
private IEnumerable<long>? _testObjects;
private IEnumerable<Func<long, long, int>>? _testListOfFunctions;
private IEnumerable<IComparer<long>>? _testListOfComparers;
private IEnumerable<Compare<long>>? _testListOfDelegates;
private IEnumerable<Func<long, long, int>>? _testListOfLocalFunctions;
private IEnumerable<MyComparer>? _testListOfClasses;
private IEnumerable<MyComparerStruct<long>>? _testListOfStructs;
private IEnumerable<IComparer<long>>? _testListOfBoxedStructs;
private IEnumerable<TComparer> TestListOfUnboxedStructs<TComparer, TValue>() where TComparer : IComparer<TValue>, new()
{
foreach (var _ in _testObjects!)
{
yield return new TComparer();
}
}
private static IEnumerable<Func<long, long, int>> GetLocalFunctions(IEnumerable<long> testObjects)
{
static int compareFunc(long x, long y)
{
return (x - y) switch
{
> 0 => 1,
< 0 => -1,
_ => 0
};
}
foreach (var _ in testObjects)
{
yield return compareFunc;
}
}
private void TestWithComparer(IComparer<long> comparer)
{
var testData = _testObjects!.ToArray();
for (var itemIdx = 0; itemIdx < testData.Length - 1; itemIdx++)
{
_ = comparer.Compare(testData[itemIdx], testData[itemIdx + 1]);
}
}
private void TestWithDelegate(Compare<long> compareFunc)
{
var testData = _testObjects!.ToArray();
for (var itemIdx = 0; itemIdx < testData.Length - 1; itemIdx++)
{
_ = compareFunc(testData[itemIdx], testData[itemIdx + 1]);
}
}
private void TestWithFunc(Func<long, long, int> compareFunc)
{
var testData = _testObjects!.ToArray();
for (var itemIdx = 0; itemIdx < testData.Length - 1; itemIdx++)
{
_ = compareFunc(testData[itemIdx], testData[itemIdx + 1]);
}
}
public void Comparer()
{
TestWithComparer(_comparer);
}
public void Func()
{
TestWithFunc((x, y) => (x - y) switch
{
> 0 => 1,
< 0 => -1,
_ => 0
});
}
public void StaticFunc()
{
TestWithFunc(static (x, y) => (x - y) switch
{
> 0 => 1,
< 0 => -1,
_ => 0
});
}
public void Delegate()
{
TestWithDelegate((x, y) => (x - y) switch
{
> 0 => 1,
< 0 => -1,
_ => 0
});
}
public void ListOfFuncs()
{
const long x = 2, y = 5;
var testData = _testListOfFunctions!.ToArray();
for (var itemIdx = 0; itemIdx < testData.Length; itemIdx++)
{
var compareFunc = testData[itemIdx];
_ = compareFunc(x, y);
}
}
public void ListOfLocalFuncs()
{
const long x = 2, y = 5;
var testData = _testListOfLocalFunctions!.ToArray();
for (var itemIdx = 0; itemIdx < testData.Length; itemIdx++)
{
var compareFunc = testData[itemIdx];
_ = compareFunc(x, y);
}
}
public void ListOfComparers()
{
const long x = 2, y = 5;
var testData = _testListOfComparers!.ToArray();
for (var itemIdx = 0; itemIdx < testData.Length; itemIdx++)
{
var comparer = testData[itemIdx];
_ = comparer.Compare(x, y);
}
}
public void ListOfClasses()
{
const long x = 2, y = 5;
var testData = _testListOfClasses!.ToArray();
for (var itemIdx = 0; itemIdx < testData.Length; itemIdx++)
{
var comparer = testData[itemIdx];
_ = comparer.Compare(x, y);
}
}
public void ListOfStructs()
{
const long x = 2, y = 5;
var testData = _testListOfStructs!.ToArray();
for (var itemIdx = 0; itemIdx < testData.Length; itemIdx++)
{
var comparer = testData[itemIdx];
_ = comparer.Compare(x, y);
}
}
public void ListOfBoxedStructs()
{
const long x = 2, y = 5;
var testData = _testListOfBoxedStructs!.ToArray();
for (var itemIdx = 0; itemIdx < testData.Length; itemIdx++)
{
var comparer = testData[itemIdx];
_ = comparer.Compare(x, y);
}
}
public void ListOfUnboxedStructs()
{
const long x = 2, y = 5;
var testData = TestListOfUnboxedStructs<MyComparerStruct<long>, long>().ToArray();
for (var itemIdx = 0; itemIdx < testData.Length; itemIdx++)
{
var comparer = testData[itemIdx];
_ = comparer.Compare(x, y);
}
}
public void ListOfUnboxedReadOnlyStructs()
{
const long x = 2, y = 5;
var testData = TestListOfUnboxedStructs<MyComparerReadOnlyStruct<long>, long>().ToArray();
for (var itemIdx = 0; itemIdx < testData.Length; itemIdx++)
{
var comparer = testData[itemIdx];
_ = comparer.Compare(x, y);
}
}
public void ListOfDelegates()
{
const long x = 2, y = 5;
var testData = _testListOfDelegates!.ToArray();
for (var itemIdx = 0; itemIdx < testData.Length; itemIdx++)
{
var compareDelegate = testData[itemIdx];
_ = compareDelegate(x, y);
}
}
protected override Action? GetTestMethod(DelegateVsComparerPocBenchmarkType benchmarkType) => benchmarkType switch
{
DelegateVsComparerPocBenchmarkType.Comparer => Comparer,
DelegateVsComparerPocBenchmarkType.Delegate => Delegate,
DelegateVsComparerPocBenchmarkType.Func => Func,
DelegateVsComparerPocBenchmarkType.ListOfBoxedStructs => ListOfBoxedStructs,
DelegateVsComparerPocBenchmarkType.ListOfClasses => ListOfClasses,
DelegateVsComparerPocBenchmarkType.ListOfComparers => ListOfComparers,
DelegateVsComparerPocBenchmarkType.ListOfDelegates => ListOfDelegates,
DelegateVsComparerPocBenchmarkType.ListOfFuncs => ListOfFuncs,
DelegateVsComparerPocBenchmarkType.ListOfLocalFuncs => ListOfLocalFuncs,
DelegateVsComparerPocBenchmarkType.ListOfStructs => ListOfStructs,
DelegateVsComparerPocBenchmarkType.ListOfUnboxedReadOnlyStructs => ListOfUnboxedReadOnlyStructs,
DelegateVsComparerPocBenchmarkType.ListOfUnboxedStructs => ListOfUnboxedStructs,
DelegateVsComparerPocBenchmarkType.StaticFunc => StaticFunc,
_ => throw CreateUnknownBenchmarkTypeException(benchmarkType),
};
public override void Setup()
{
Console.WriteLine("******* SETTING UP COMMON TEST DATA *******");
_testObjects = Enumerable.Range(1, TestObjectCount).Select(x => (long)x);
base.Setup();
}
public override void Cleanup()
{
_testObjects = null;
base.Cleanup();
}
protected override void PrepareData<T>(T benchmarkType)
{
switch (benchmarkType)
{
case DelegateVsComparerPocBenchmarkType.ListOfBoxedStructs:
_testListOfBoxedStructs = _testObjects!.Select(_ => (IComparer<long>)new MyComparerStruct<long>());
break;
case DelegateVsComparerPocBenchmarkType.ListOfClasses:
_testListOfClasses = _testObjects!.Select(_ => new MyComparer());
break;
case DelegateVsComparerPocBenchmarkType.ListOfComparers:
_testListOfComparers = _testObjects!.Select(_ => (IComparer<long>)new MyComparer());
break;
case DelegateVsComparerPocBenchmarkType.ListOfDelegates:
_testListOfDelegates = _testObjects!.Select(_ => new Compare<long>((x, y) => new MyComparer().Compare(x, y)));
break;
case DelegateVsComparerPocBenchmarkType.ListOfFuncs:
_testListOfFunctions = _testObjects!.Select<long, Func<long, long, int>>(static _ => new MyComparer().Compare);
break;
case DelegateVsComparerPocBenchmarkType.ListOfLocalFuncs:
_testListOfLocalFunctions = GetLocalFunctions(_testObjects!);
break;
case DelegateVsComparerPocBenchmarkType.ListOfStructs:
_testListOfStructs = _testObjects!.Select(_ => new MyComparerStruct<long>());
break;
}
}
}
}
@@ -2,7 +2,7 @@
using BenchmarkDotNet.Attributes;
using FluentAssertions;
using Recyclable.CollectionsTests;
using Recyclable.Collections.TestData;
namespace Recyclable.Collections.Benchmarks.POC
{
@@ -0,0 +1,50 @@
// Ignore Spelling: Poc
using BenchmarkDotNet.Attributes;
using Collections.Benchmarks.Core;
#pragma warning disable CA1822 // Mark members as static
namespace Recyclable.Collections.Benchmarks.POC
{
public class GreaterOperatorVsNotEqualOperatorBenchmarks
{
private static readonly long _num = RecyclableDefaults.MinItemsCountForParallelization;
[GlobalSetup]
public void Setup()
{
Console.WriteLine($"*** We're comparing if {_num} is < 0 ***");
}
[Benchmark(Baseline = true)]
public void CompareWithGreater()
{
DoNothing.With(_num > 0 ? 1 : 0);
}
[Benchmark]
public void CompareWithGreaterEqual()
{
DoNothing.With(_num >= 0 ? 1 : 0);
}
[Benchmark]
public void CompareWithNotEqual()
{
DoNothing.With(_num != 0 ? 1 : 0);
}
[Benchmark]
public void CompareWithLess()
{
DoNothing.With(_num < 0 ? 1 : 0);
}
[Benchmark]
public void CompareWithEqual()
{
DoNothing.With(_num == 0 ? 0 : 1);
}
}
}
@@ -1,57 +0,0 @@
using BenchmarkDotNet.Attributes;
using System.Runtime.CompilerServices;
#pragma warning disable CA1822
namespace Recyclable.Collections.Benchmarks.POC
{
public class GreaterOperatorVsDoesntEqualOperatorBenchmarks
{
private static readonly long num = RecyclableDefaults.MinItemsCountForParallelization;
public void Setup()
{
Console.WriteLine($"*** We're comparing if {num} is < 0 ***");
}
public void Cleanup() { }
#pragma warning disable RCS1163, IDE0060
[MethodImpl(MethodImplOptions.NoInlining)]
private static void DoNothing<T>(T item)
{
}
#pragma warning restore RCS1163
[Benchmark(Baseline = true)]
public void CompareWithGreater()
{
DoNothing(num > 0 ? 1 : 0);
}
[Benchmark]
public void CompareWithGreaterEqual()
{
DoNothing(num >= 0 ? 1 : 0);
}
[Benchmark]
public void CompareWithDoesntEqual()
{
DoNothing(num != 0 ? 1 : 0);
}
[Benchmark]
public void CompareWithLess()
{
DoNothing(num < 0 ? 1 : 0);
}
[Benchmark]
public void CompareWithEqual()
{
DoNothing(num == 0 ? 0 : 1);
}
}
}
@@ -1,7 +1,7 @@
// Ignore Spelling: Poc
using BenchmarkDotNet.Attributes;
using System.Runtime.CompilerServices;
using Collections.Benchmarks.Core;
#pragma warning disable CA1822
@@ -21,36 +21,28 @@ namespace Recyclable.Collections.Benchmarks.POC
public void Cleanup() { }
#pragma warning disable RCS1163, IDE0060
[MethodImpl(MethodImplOptions.NoInlining)]
private static void DoNothing<T>(T item)
{
}
#pragma warning restore RCS1163
[Benchmark(Baseline = true)]
public void CompareWithLess()
{
DoNothing(_num < 0);
DoNothing.With(_num < 0);
}
[Benchmark]
public void CompareWithAnd()
{
DoNothing((_num & BitShift) != 0);
DoNothing.With((_num & BitShift) != 0);
}
[Benchmark]
public void CompareWithEqual()
{
DoNothing(_num == -1);
DoNothing.With(_num == -1);
}
[Benchmark]
public void CompareToZero()
{
DoNothing(_num == 0);
DoNothing.With(_num == 0);
}
}
}
@@ -0,0 +1,371 @@
// Ignore Spelling: Mul Poc
using BenchmarkDotNet.Attributes;
using Collections.Benchmarks.Core;
using System.Numerics;
using System.Runtime.Intrinsics;
using System.Runtime.Intrinsics.X86;
namespace Recyclable.Collections.Benchmarks.POC
{
[MemoryDiagnoser]
public class ModuloBenchmarks
{
public static void Run()
{
var benchmark = new ModuloBenchmarks();
benchmark.Setup();
benchmark.AddWithFor();
benchmark.AddWithForOptimized();
benchmark.DividerAndModulusWithOperator();
benchmark.MathDivRem();
benchmark.MixedApproachWithForLoopOptimized();
benchmark.MixedApproachWithSubtractWithStackalloc();
benchmark.MixedApproachWithSubtractWithWhile();
benchmark.MixedApproachWithSubtractWithWhileAsVector();
benchmark.MixedApproachWithSubtractWithWhileWithSse2();
benchmark.SubtractWithWhile();
benchmark.SubtractWithWhileWithSse2();
benchmark.XDivYMulX();
benchmark.XDivYMulXWithLocalVar();
}
private long _cutoff;
private Vector128<long> _increment;
private long _lastCaseIndex;
[GlobalSetup]
public void Setup()
{
_cutoff = checked((long)BlockSize << 4);
_increment = Vector128.Create(-BlockSize, 1L);
_lastCaseIndex = 0;
}
//[Params(123, 10, 2, int.MaxValue, int.MaxValue / 2, int.MaxValue / 3, int.MaxValue / 4, int.MaxValue / 6, int.MaxValue / 10, int.MaxValue / 15, int.MaxValue / 20)]
[Params(int.MaxValue, int.MaxValue / 2, int.MaxValue / 3, int.MaxValue / 4, int.MaxValue / 6, int.MaxValue / 8, int.MaxValue / 10, int.MaxValue / 100)]
//[Params(int.MaxValue / 10, int.MaxValue / 20, int.MaxValue / 100)]
public int BlockSize { get; set; } = int.MaxValue;
[Params(int.MaxValue, int.MaxValue / 1000, int.MaxValue / 10000)]
//[Params(int.MaxValue)]
//[Params(int.MaxValue * 100L)]
public long TestNumber { get; set; } = int.MaxValue;
private void CalculateDividerAndModulusWithOperator(long i)
{
DoNothing.With(i / BlockSize, i % BlockSize);
}
private void CalculateWithMathDivRem(long i)
{
DoNothing.With(Math.DivRem(i, BlockSize, out long remainder), remainder);
}
private void CalculateWithAddWithFor(long i)
{
int result = 0;
int remainder = 0;
int blockSize = BlockSize;
for (long iteration = 0; iteration < i; iteration++)
{
if (remainder > blockSize - 1)
{
remainder = 0;
result++;
}
remainder++;
}
DoNothing.With(result, remainder);
}
private void CalculateWithAddWithForOptimized(long i)
{
long total = 0;
int result = 0;
int blockSize = BlockSize;
while (total + blockSize <= i)
{
total += blockSize;
result++;
}
DoNothing.With(result, i - total);
}
private void CalculateWithXDivYMulX(long i)
{
DoNothing.With(i / BlockSize, i - (i / BlockSize * BlockSize));
}
private void CalculateWithXDivYMulXWithLocalVar(long i)
{
int blockSize = BlockSize;
int result = (int)(i / blockSize);
DoNothing.With(result, i - (result * blockSize));
}
private void CalculateWithSubtractWithWhile(long i)
{
int result = 0;
long remainder = i;
int blockSize = BlockSize;
while (remainder >= blockSize)
{
remainder -= blockSize;
result++;
}
DoNothing.With(result, remainder);
}
private void CalculateWithSubtractWithWhileWithSse2(long i)
{
var state = Vector128.Create(i, 0);
int blockSize = BlockSize;
var inc = _increment;
while (state.GetElement(0) >= blockSize)
{
state = Sse2.Add(state, inc);
}
DoNothing.With(state.GetElement(1), state.GetElement(0));
}
private void CalculateWithMixedApproachWithSubtractWithWhile(long i)
{
long remainder;
if (i >= _cutoff)
{
DoNothing.With(Math.DivRem(i, BlockSize, out remainder), remainder);
}
else
{
int result = 0;
int blockSize = BlockSize;
remainder = i;
while (remainder >= blockSize)
{
remainder -= blockSize;
result++;
}
DoNothing.With(result, remainder);
}
}
private void CalculateWithMixedApproachWithSubtractWithWhileAsVector(long i)
{
if (i >= _cutoff)
{
DoNothing.With(Math.DivRem(i, BlockSize, out long remainder), remainder);
}
else
{
var state = new Vector<long>(new[] { 0L, i, 0, 0 });
var increment = new Vector<long>(new[] { 1L, -BlockSize, 0, 0 });
int blockSize = BlockSize;
while (state[1] >= blockSize)
{
state += increment;
}
DoNothing.With(state[0], state[1]);
}
}
private void CalculateWithMixedApproachWithSubtractWithWhileWithSse2(long i)
{
if (i >= _cutoff)
{
DoNothing.With(Math.DivRem(i, BlockSize, out long remainder), remainder);
}
else
{
var increment = _increment;
var state = Vector128.Create(i, 0);
int blockSize = BlockSize;
while (state.GetElement(0) >= blockSize)
{
state = Sse2.Add(state, increment);
}
DoNothing.With(state.GetElement(1), state.GetElement(0));
}
}
private void CalculateWithMixedApproachWithSubtractWithStackalloc(long i)
{
if (i >= _cutoff)
{
DoNothing.With(Math.DivRem(i, BlockSize, out long remainder), remainder);
}
else
{
Span<long> state = stackalloc long[2] { i, 0 };// Vector128.Create(BlockSize, 0);
int blockSize = BlockSize;
while (state[0] >= blockSize)
{
state[0] -= blockSize;
state[1]++;
}
DoNothing.With(state[1], state[0]);
}
}
private void CalculateWithMixedApproachWithForLoopOptimized(long i)
{
long total;
if (i >= _cutoff)
{
DoNothing.With(Math.DivRem(i, BlockSize, out total), total);
}
else
{
total = 0;
int result = 0;
int blockSize = BlockSize;
while (total + blockSize <= i)
{
total += blockSize;
result++;
}
DoNothing.With(result, i - total);
}
}
[Benchmark(Baseline = true)]
public void DividerAndModulusWithOperator()
{
long testNumber = TestNumber;
for (long i = testNumber; i >= _lastCaseIndex; i--)
{
CalculateDividerAndModulusWithOperator(i);
}
}
[Benchmark]
public void MathDivRem()
{
long testNumber = TestNumber;
for (long i = testNumber; i >= _lastCaseIndex; i--)
{
CalculateWithMathDivRem(i);
}
}
[Benchmark]
public void AddWithFor()
{
long testNumber = TestNumber;
for (long i = testNumber; i >= _lastCaseIndex; i--)
{
CalculateWithAddWithFor(i);
}
}
[Benchmark(Baseline = true)]
public void AddWithForOptimized()
{
long testNumber = TestNumber;
for (long i = testNumber; i >= _lastCaseIndex; i--)
{
CalculateWithAddWithForOptimized(i);
}
}
[Benchmark]
public void XDivYMulX()
{
long testNumber = TestNumber;
for (long i = testNumber; i >= _lastCaseIndex; i--)
{
CalculateWithXDivYMulX(i);
}
}
[Benchmark]
public void XDivYMulXWithLocalVar()
{
long testNumber = TestNumber;
for (long i = testNumber; i >= _lastCaseIndex; i--)
{
CalculateWithXDivYMulXWithLocalVar(i);
}
}
[Benchmark]
public void SubtractWithWhile()
{
long testNumber = TestNumber;
for (long i = testNumber; i >= _lastCaseIndex; i--)
{
CalculateWithSubtractWithWhile(i);
}
}
[Benchmark]
public void SubtractWithWhileWithSse2()
{
long testNumber = TestNumber;
for (long i = testNumber; i >= _lastCaseIndex; i--)
{
CalculateWithSubtractWithWhileWithSse2(i);
}
}
[Benchmark(Baseline = false)]
public void MixedApproachWithSubtractWithWhile()
{
long testNumber = TestNumber;
for (long i = testNumber; i >= _lastCaseIndex; i--)
{
CalculateWithMixedApproachWithSubtractWithWhile(i);
}
}
[Benchmark(Baseline = false)]
public void MixedApproachWithSubtractWithWhileAsVector()
{
long testNumber = TestNumber;
for (long i = testNumber; i >= _lastCaseIndex; i--)
{
CalculateWithMixedApproachWithSubtractWithWhileAsVector(i);
}
}
[Benchmark(Baseline = false)]
public void MixedApproachWithSubtractWithWhileWithSse2()
{
long testNumber = TestNumber;
for (long i = testNumber; i >= _lastCaseIndex; i--)
{
CalculateWithMixedApproachWithSubtractWithWhileWithSse2(i);
}
}
[Benchmark(Baseline = false)]
public void MixedApproachWithSubtractWithStackalloc()
{
long testNumber = TestNumber;
for (long i = testNumber; i >= _lastCaseIndex; i--)
{
CalculateWithMixedApproachWithSubtractWithStackalloc(i);
}
}
[Benchmark(Baseline = false)]
public void MixedApproachWithForLoopOptimized()
{
long testNumber = TestNumber;
for (long i = testNumber; i >= _lastCaseIndex; i--)
{
CalculateWithMixedApproachWithForLoopOptimized(i);
}
}
}
}
@@ -1,376 +0,0 @@
using BenchmarkDotNet.Attributes;
using System.Numerics;
using System.Runtime.CompilerServices;
using System.Runtime.Intrinsics;
using System.Runtime.Intrinsics.X86;
#pragma warning disable xUnit1026, RCS1163, IDE0060
namespace Recyclable.Collections.Benchmarks.POC
{
[MemoryDiagnoser]
public class ModuloPocBenchmarks
{
public static void Run()
{
var benchmark = new ModuloPocBenchmarks();
benchmark.Setup();
benchmark.AddWithFor();
benchmark.AddWithForOptimized();
benchmark.DividerAndModulusWithOperator();
benchmark.MathDivRem();
benchmark.MixedApproachWithForLoopOptimized();
benchmark.MixedApproachWithSubtractWithStackalloc();
benchmark.MixedApproachWithSubtractWithWhile();
benchmark.MixedApproachWithSubtractWithWhileAsVector();
benchmark.MixedApproachWithSubtractWithWhileWithSse2();
benchmark.SubtractWithWhile();
benchmark.SubtractWithWhileWithSse2();
benchmark.XDivYMulX();
benchmark.XDivYMulXWithLocalVar();
}
private long _cutoff;
private Vector128<long> _increment;
private long _lastCaseIndex;
[GlobalSetup]
public void Setup()
{
_cutoff = checked((long)BlockSize << 4);
_increment = Vector128.Create(-BlockSize, 1L);
_lastCaseIndex = 0;
}
private static void DoNothing<T>(T result, T remainder, [CallerMemberName] string? callerName = null)
{
//Console.WriteLine($"{callerName}: result = {result}, remainder = {remainder}");
}
//[Params(123, 10, 2, int.MaxValue, int.MaxValue / 2, int.MaxValue / 3, int.MaxValue / 4, int.MaxValue / 6, int.MaxValue / 10, int.MaxValue / 15, int.MaxValue / 20)]
[Params(int.MaxValue, int.MaxValue / 2, int.MaxValue / 3, int.MaxValue / 4, int.MaxValue / 6, int.MaxValue / 8, int.MaxValue / 10, int.MaxValue / 100)]
//[Params(int.MaxValue / 10, int.MaxValue / 20, int.MaxValue / 100)]
public int BlockSize { get; set; } = int.MaxValue;
[Params(int.MaxValue, int.MaxValue / 1000, int.MaxValue / 10000)]
//[Params(int.MaxValue)]
//[Params(int.MaxValue * 100L)]
public long TestNumber { get; set; } = int.MaxValue;
private void CalculateDividerAndModulusWithOperator(long i)
{
DoNothing(i / BlockSize, i % BlockSize);
}
private void CalculateWithMathDivRem(long i)
{
DoNothing(Math.DivRem(i, BlockSize, out long remainder), remainder);
}
private void CalculateWithAddWithFor(long i)
{
int result = 0;
int remainder = 0;
int blockSize = BlockSize;
for (long iteration = 0; iteration < i; iteration++)
{
if (remainder > blockSize - 1)
{
remainder = 0;
result++;
}
remainder++;
}
DoNothing(result, remainder);
}
private void CalculateWithAddWithForOptimized(long i)
{
long total = 0;
int result = 0;
int blockSize = BlockSize;
while (total + blockSize <= i)
{
total += blockSize;
result++;
}
DoNothing(result, i - total);
}
private void CalculateWithXDivYMulX(long i)
{
DoNothing(i / BlockSize, i - (i / BlockSize * BlockSize));
}
private void CalculateWithXDivYMulXWithLocalVar(long i)
{
int blockSize = BlockSize;
int result = (int)(i / blockSize);
DoNothing(result, i - (result * blockSize));
}
private void CalculateWithSubtractWithWhile(long i)
{
int result = 0;
long remainder = i;
int blockSize = BlockSize;
while (remainder >= blockSize)
{
remainder -= blockSize;
result++;
}
DoNothing(result, remainder);
}
private void CalculateWithSubtractWithWhileWithSse2(long i)
{
var state = Vector128.Create(i, 0);
int blockSize = BlockSize;
var inc = _increment;
while (state.GetElement(0) >= blockSize)
{
state = Sse2.Add(state, inc);
}
DoNothing(state.GetElement(1), state.GetElement(0));
}
private void CalculateWithMixedApproachWithSubtractWithWhile(long i)
{
long remainder;
if (i >= _cutoff)
{
DoNothing(Math.DivRem(i, BlockSize, out remainder), remainder);
}
else
{
int result = 0;
int blockSize = BlockSize;
remainder = i;
while (remainder >= blockSize)
{
remainder -= blockSize;
result++;
}
DoNothing(result, remainder);
}
}
private void CalculateWithMixedApproachWithSubtractWithWhileAsVector(long i)
{
if (i >= _cutoff)
{
DoNothing(Math.DivRem(i, BlockSize, out long remainder), remainder);
}
else
{
var state = new Vector<long>(new[] { 0L, i, 0, 0 });
var increment = new Vector<long>(new[] { 1L, -BlockSize, 0, 0 });
int blockSize = BlockSize;
while (state[1] >= blockSize)
{
state += increment;
}
DoNothing(state[0], state[1]);
}
}
private void CalculateWithMixedApproachWithSubtractWithWhileWithSse2(long i)
{
if (i >= _cutoff)
{
DoNothing(Math.DivRem(i, BlockSize, out long remainder), remainder);
}
else
{
var increment = _increment;
var state = Vector128.Create(i, 0);
int blockSize = BlockSize;
while (state.GetElement(0) >= blockSize)
{
state = Sse2.Add(state, increment);
}
DoNothing(state.GetElement(1), state.GetElement(0));
}
}
private void CalculateWithMixedApproachWithSubtractWithStackalloc(long i)
{
if (i >= _cutoff)
{
DoNothing(Math.DivRem(i, BlockSize, out long remainder), remainder);
}
else
{
Span<long> state = stackalloc long[2] { i, 0 };// Vector128.Create(BlockSize, 0);
int blockSize = BlockSize;
while (state[0] >= blockSize)
{
state[0] -= blockSize;
state[1]++;
}
DoNothing(state[1], state[0]);
}
}
private void CalculateWithMixedApproachWithForLoopOptimized(long i)
{
long total;
if (i >= _cutoff)
{
DoNothing(Math.DivRem(i, BlockSize, out total), total);
}
else
{
total = 0;
int result = 0;
int blockSize = BlockSize;
while (total + blockSize <= i)
{
total += blockSize;
result++;
}
DoNothing(result, i - total);
}
}
[Benchmark(Baseline = true)]
public void DividerAndModulusWithOperator()
{
long testNumber = TestNumber;
for (long i = testNumber; i >= _lastCaseIndex; i--)
{
CalculateDividerAndModulusWithOperator(i);
}
}
[Benchmark]
public void MathDivRem()
{
long testNumber = TestNumber;
for (long i = testNumber; i >= _lastCaseIndex; i--)
{
CalculateWithMathDivRem(i);
}
}
[Benchmark]
public void AddWithFor()
{
long testNumber = TestNumber;
for (long i = testNumber; i >= _lastCaseIndex; i--)
{
CalculateWithAddWithFor(i);
}
}
[Benchmark(Baseline = true)]
public void AddWithForOptimized()
{
long testNumber = TestNumber;
for (long i = testNumber; i >= _lastCaseIndex; i--)
{
CalculateWithAddWithForOptimized(i);
}
}
[Benchmark]
public void XDivYMulX()
{
long testNumber = TestNumber;
for (long i = testNumber; i >= _lastCaseIndex; i--)
{
CalculateWithXDivYMulX(i);
}
}
[Benchmark]
public void XDivYMulXWithLocalVar()
{
long testNumber = TestNumber;
for (long i = testNumber; i >= _lastCaseIndex; i--)
{
CalculateWithXDivYMulXWithLocalVar(i);
}
}
[Benchmark]
public void SubtractWithWhile()
{
long testNumber = TestNumber;
for (long i = testNumber; i >= _lastCaseIndex; i--)
{
CalculateWithSubtractWithWhile(i);
}
}
[Benchmark]
public void SubtractWithWhileWithSse2()
{
long testNumber = TestNumber;
for (long i = testNumber; i >= _lastCaseIndex; i--)
{
CalculateWithSubtractWithWhileWithSse2(i);
}
}
[Benchmark(Baseline = false)]
public void MixedApproachWithSubtractWithWhile()
{
long testNumber = TestNumber;
for (long i = testNumber; i >= _lastCaseIndex; i--)
{
CalculateWithMixedApproachWithSubtractWithWhile(i);
}
}
[Benchmark(Baseline = false)]
public void MixedApproachWithSubtractWithWhileAsVector()
{
long testNumber = TestNumber;
for (long i = testNumber; i >= _lastCaseIndex; i--)
{
CalculateWithMixedApproachWithSubtractWithWhileAsVector(i);
}
}
[Benchmark(Baseline = false)]
public void MixedApproachWithSubtractWithWhileWithSse2()
{
long testNumber = TestNumber;
for (long i = testNumber; i >= _lastCaseIndex; i--)
{
CalculateWithMixedApproachWithSubtractWithWhileWithSse2(i);
}
}
[Benchmark(Baseline = false)]
public void MixedApproachWithSubtractWithStackalloc()
{
long testNumber = TestNumber;
for (long i = testNumber; i >= _lastCaseIndex; i--)
{
CalculateWithMixedApproachWithSubtractWithStackalloc(i);
}
}
[Benchmark(Baseline = false)]
public void MixedApproachWithForLoopOptimized()
{
long testNumber = TestNumber;
for (long i = testNumber; i >= _lastCaseIndex; i--)
{
CalculateWithMixedApproachWithForLoopOptimized(i);
}
}
}
}
@@ -1,142 +0,0 @@
using BenchmarkDotNet.Attributes;
using System.Numerics;
using System.Runtime.CompilerServices;
namespace Recyclable.Collections.Benchmarks.POC
{
public abstract class PocBenchmarkBase<TBenchmarkType>
{
public virtual TBenchmarkType? DataType { get; set; }
public virtual TBenchmarkType? BaseDataType { get; set; }
private Action? _testMethod;
protected Action TestMethod
{
get => _testMethod ?? throw new OperationCanceledException("Skip - No actual defined");
set => _testMethod = value;
}
private Action? _baselineMethod;
protected Action BaselineMethod
{
get => _baselineMethod ?? throw new OperationCanceledException("Skip - No baseline defined");
set => _baselineMethod = value;
}
[Benchmark(Baseline = true)]
public void Baseline() => BaselineMethod.Invoke();
[Benchmark]
public void Actual() => TestMethod.Invoke();
// 0 2 4 8 16 32 64 128 256 512 1024 2048 4096 8192 16384 32768 65536 131072 262144 524_288
// 1048576 2097152 4194304 8388608 16777216 33554432 67108864 134217728 268435456 536870912
// 1073741824 2147483648
// [Params(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 30, 32, 40, 50, 60, 80, 90, 100, 128, 256, 512, 1024, 2048, 4096, 8192, 1_000_000)]
// [Params(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 30, 32, 40, 50, 60, 80, 90, 100, 128, 256, 512, 1024, 2048, 4096, 8192, 1_000_000)]
// [Params(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 30, 32, 40, 50, 60, 80, 90, 100, 128, 256, 512, 1024, 2048, 4096, 8192, 100_000_000)]
// [Params(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 30, 32, 40, 50, 60, 80, 90, 100, 128, 256, 512, 1024, 2048, 4096, 8192, 850_000 - 1, 1_000_000, RecyclableDefaults.MaxPooledBlockSize)]
// [Params(1_000_000, 10_000_000, 100_000_000, 1_000_000_000)]
// [Params(1, 10, 64, 128, 192, 256, 512, 1024, 2048, 4096, 8192, 16384, 32768, 65536, 131072, 262144)]
// [Params(524_288, 786_432, 1_048_576)]
// [Params(262_144, 393_216, 524_288)]
// [Params(850_000_000)]
// [Params(100_000_000)]
// [Params(RecyclableDefaults.MinItemsCountForParallelization)]
// [Params(127)]
// [Params(16)]
// [Params(10, 15, 128)]
// [Params(1)]
// [Params(RecyclableDefaults.MaxPooledBlockSize)]
// [Params(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 30, 32, 40, 50, 60, 80, 90, 100, 128, 256, 512, 1024, 2048, 4096, 8192, 16384, 32768, 65536, 131072, 262144, 524288, 1048576, 10_000_000, 33_554_432, 50_000_000, 100_000_000)]
// *** [Params(RecyclableDefaults.MinPooledArrayLength - 3, RecyclableDefaults.MinPooledArrayLength - 2, RecyclableDefaults.MinPooledArrayLength - 1, RecyclableDefaults.MinPooledArrayLength, RecyclableDefaults.MinPooledArrayLength + 1, RecyclableDefaults.MinPooledArrayLength + 2, RecyclableDefaults.MinPooledArrayLength + 3)]
[Params(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 30, 32, 40, RecyclableDefaults.MinPooledArrayLength - 1, RecyclableDefaults.MinPooledArrayLength, 40, 50, 60, 70, 80, 90, 100, 128, 256, 512, 1024, 2048, 4096, 8192, 16384, 32768, 65536, 131072, RecyclableDefaults.MinItemsCountForParallelization)]
// *** [Params(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 30, 32, 40, RecyclableDefaults.MinPooledArrayLength - 1, RecyclableDefaults.MinPooledArrayLength, 40, 50, 60, 70, 80, 90, 100, 128, 256, 512, 1024, 2048, 4096, 8192, 16384, 32768, 65536, 131072, RecyclableDefaults.MinItemsCountForParallelization)]
// [Params(256, 512, 1024, 2048, 4096, 8192, 16384, 32768, 65536, 131072, RecyclableDefaults.MinItemsCountForParallelization)]
// [Params(RecyclableDefaults.MinItemsCountForParallelization, 1_048_576, 2_097_152, 4_194_304, 8_388_608, 16_777_216, 33_554_432, RecyclableDefaults.MaxPooledBlockSize)]
// *** [Params(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 30, RecyclableDefaults.MinPooledArrayLength - 1, RecyclableDefaults.MinPooledArrayLength, 40, 50, 60, 64, 70, 80, 90, 100, 127, 128)]
// [Params(1, 10, 1024, 10240, RecyclableDefaults.MinPooledArrayLength, RecyclableDefaults.MinItemsCountForParallelization)]
// [Params(RecyclableDefaults.MinItemsCountForParallelization * 3)]
// [Params(1_048_576)]
public virtual int TestObjectCount { get; set; } = 0; //8_192;//131_072; //1; //33_554_432; //524_288; //131_072;
public virtual int TestObjectCountForSlowMethods { get; private set; }
// [Params(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 20, 30, 40, 50, 60, 70, 80, 90, 100, 110, 120, 130, 140, 150, 160, 170, 180, 190, 200)]
// [Params(10, 20, 50, 100)]
// [Params(1, 10)]
public int Divider = 10;
//public int BlockSize = 1_048_576;//int.MaxValue - 1;
public int BlockSize { get; private set; }
public byte BlockSizePow2BitShift => checked((byte)(31 - BitOperations.LeadingZeroCount((uint)BlockSize)));
[MethodImpl(MethodImplOptions.NoInlining)]
protected static void DoNothing<T>(in T item)
{
_ = item;
}
protected static Exception CreateUnknownBenchmarkTypeException<T>(T benchmarkType)
{
return new InvalidOperationException($"******* UNKNOWN BENCHMARK TYPE {{{benchmarkType}}} *******");
}
protected static Exception CreateMethodNotFoundException(in string methodName, in string? className)
{
return new MethodAccessException($"******* METHOD {{{methodName}}} NOT FOUND IN CLASS {{{className}}} *******");
}
protected virtual void PrepareData<T>(T benchmarkType) { }
protected virtual Action? GetTestMethod(TBenchmarkType? benchmarkType) => null;
[GlobalCleanup]
public virtual void Cleanup()
{
_baselineMethod = null;
_testMethod = null;
GC.Collect(GC.MaxGeneration, GCCollectionMode.Forced, true, true);
}
[GlobalSetup]
public virtual void Setup()
{
Console.WriteLine($"******* SETTING UP TEST CASE FOR BENCHMARK {{{DataType}}} *******");
TestObjectCountForSlowMethods = (TestObjectCount / 2) + 1;
BlockSize = TestObjectCount switch
{
0 => 1,
> 0 and <= 10_240 => TestObjectCount,
_ => TestObjectCount / Divider > 0 ? TestObjectCount / Divider : TestObjectCount
};
if (BlockSize > 0)
{
BlockSize = checked((int)BitOperations.RoundUpToPowerOf2((uint)BlockSize));
}
Console.WriteLine($"******* BaseDataType = {BaseDataType}; default = {default(TBenchmarkType)} *******");
if (!EqualityComparer<TBenchmarkType>.Default.Equals(BaseDataType, default))
{
Console.WriteLine("******* SETTING UP BASELINE DATA *******");
PrepareData(BaseDataType);
_baselineMethod = GetTestMethod(BaseDataType);
}
//~ We don't want to prepare data if baseline data is the same is benchmark data.
//~ One would override another - waste of time & resources.
if (!EqualityComparer<TBenchmarkType>.Default.Equals(BaseDataType, DataType))
{
Console.WriteLine("******* SETTING UP TEST CASE DATA *******");
//~ If BaseDataType == null, then we'll come here only if DataType != null.
PrepareData(DataType!);
_testMethod = GetTestMethod(DataType);
}
Console.WriteLine("******* DATA PREPARED *******");
}
}
}
@@ -1,104 +1,48 @@
using BenchmarkDotNet.Attributes;
// Ignore Spelling: POC
using System.Reflection;
using BenchmarkDotNet.Attributes;
using Collections.Pooled;
using Recyclable.Collections.Benchmarks.Core;
using Recyclable.Collections.Benchmarks.POC;
using Collections.Benchmarks.Core;
namespace Recyclable.Collections.Benchmarks
namespace Recyclable.Collections.Benchmarks.POC
{
public enum RecyclableCollectionsBenchmarkSource
{
Unknown,
Array,
List,
PooledList,
RecyclableList,
RecyclableLongList,
}
[MemoryDiagnoser]
public class RecyclableBenchmarkBase<TBenchmarkType> : PocBenchmarkBase<TBenchmarkType>
public partial class RecyclableLongListBenchmarks<T> : BaselineVsActualBenchmarkBase<T>
{
protected long[]? _testObjects;
protected long[] TestObjects => _testObjects ?? throw new NullReferenceException("Something is wrong and the field is not initialized");
private int[]? _testArray;
public int[] TestObjects => _testArray ?? throw new NullReferenceException("Something is wrong and test objects are null");
protected List<long>? _testObjectsAsList;
protected List<long> TestObjectsAsList => _testObjectsAsList ?? throw new NullReferenceException("Something went wrong and the field is not initialized");
public RecyclableLongList<int> TestObjectsAsRecyclableLongList => _testRecyclableLongList ?? throw new NullReferenceException($"Something is wrong and {nameof(RecyclableLongList<int>)} is null");
private RecyclableLongList<int>? _testRecyclableLongList;
private PooledList<int>? _testPooledList;
internal PooledList<int> TestPooledList => _testPooledList ?? throw new NullReferenceException($"Something is wrong and {nameof(PooledList<int>)} is null");
protected PooledList<long>? _testObjectsAsPooledList;
public PooledList<long> TestObjectsAsPooledList => _testObjectsAsPooledList ?? throw new NullReferenceException("Something is wrong and the field is not initialized");
protected RecyclableList<long>? _testObjectsAsRecyclableList;
protected RecyclableList<long> TestObjectsAsRecyclableList => _testObjectsAsRecyclableList ?? throw new NullReferenceException("Something is wrong and the field is not initialized");
protected RecyclableLongList<long>? _testObjectsAsRecyclableLongList;
protected RecyclableLongList<long> TestObjectsAsRecyclableLongList => _testObjectsAsRecyclableLongList ?? throw new NullReferenceException("Something is wrong and the field is not initialized");
protected IEnumerable<long> TestObjectsAsIEnumerable
private static readonly MethodInfo _ensureCapacityNewFunc;
static RecyclableLongListBenchmarks()
{
get
{
for (long i = 0; i < TestObjectCount; i++)
{
yield return i;
}
}
_ensureCapacityNewFunc = typeof(RecyclableLongList<int>).GetMethod("EnsureCapacity", BindingFlags.Static | BindingFlags.NonPublic)
?? throw new NullReferenceException($"Method EnsureCapacity not found in class {nameof(RecyclableLongList<int>)}");
}
public override void Setup()
{
PrepareData(RecyclableCollectionsBenchmarkSource.Array);
Console.WriteLine("******* SETTING UP EXPECTED RESULTS DATA *******");
_testArray = DataGenerator.EnumerateTestObjects(TestObjectCount);
base.Setup();
}
protected override void PrepareData<T>(T benchmarkType)
{
Console.WriteLine($"******* PREPARING DATA FOR {benchmarkType} *******");
switch (benchmarkType)
{
case RecyclableCollectionsBenchmarkSource.Unknown:
break;
case RecyclableCollectionsBenchmarkSource.Array:
_testObjects ??= DataGenerator.EnumerateTestObjects(TestObjectCount);
break;
case RecyclableCollectionsBenchmarkSource.List:
_testObjectsAsList ??= TestObjects.ToList();
break;
case RecyclableCollectionsBenchmarkSource.PooledList:
_testObjectsAsPooledList ??= new PooledList<long>(TestObjects, ClearMode.Auto);
break;
case RecyclableCollectionsBenchmarkSource.RecyclableList:
_testObjectsAsRecyclableList ??= new(TestObjects, initialCapacity: TestObjectCount);
break;
case RecyclableCollectionsBenchmarkSource.RecyclableLongList:
_testObjectsAsRecyclableLongList ??= new(TestObjects, BlockSize, initialCapacity: base.TestObjectCount);
break;
default:
throw CreateUnknownBenchmarkTypeException(benchmarkType);
}
base.PrepareData(benchmarkType);
}
public override void Cleanup()
{
Console.WriteLine("******* GLOBAL CLEANUP *******");
// Enable this if item type is changed to reference type
//if (_testObjects != null)
//{
// Array.Fill(_testObjects, 0);
//}
_testArray = null;
_testRecyclableLongList?.Dispose();
_testRecyclableLongList = null;
_testPooledList?.Dispose();
_testPooledList = null;
_testObjects = default;
_testObjectsAsList = default;
_testObjectsAsPooledList?.Dispose();
_testObjectsAsPooledList = default;
_testObjectsAsRecyclableList?.Dispose();
_testObjectsAsRecyclableList = default;
_testObjectsAsRecyclableLongList?.Dispose();
_testObjectsAsRecyclableLongList = default;
base.Cleanup();
}
}
@@ -112,12 +56,12 @@ namespace Recyclable.Collections.Benchmarks
// var data = TestObjects;
// var dataCount = TestObjectCount;
// using var list = new RecyclableList<object>(initialCapacity: dataCount);
// for (long i = 0; i < dataCount; i++)
// for (int i = 0; i < dataCount; i++)
// {
// list.Add(data[i]);
// }
// for (long i = 0; i < list.LongCount; i++)
// for (int i = 0; i < list.LongCount; i++)
// {
// DoNothing(list[i]);
// }
@@ -129,14 +73,14 @@ namespace Recyclable.Collections.Benchmarks
// public void RecyclableLongList()
// {
// var data = TestObjects;
// long dataCount = TestObjectCount;
// int dataCount = TestObjectCount;
// using var list = new RecyclableLongList<object>(BlockSize, totalItemsCount: dataCount);
// for (long i = 0; i < dataCount; i++)
// for (int i = 0; i < dataCount; i++)
// {
// list.Add(data[i]);
// }
// for (long i = 0; i < list.LongCount; i++)
// for (int i = 0; i < list.LongCount; i++)
// {
// DoNothing(list[i]);
// }
@@ -225,7 +169,7 @@ namespace Recyclable.Collections.Benchmarks
// {
// var data = TestObjects;
// var dataCount = TestObjectCount;
// var list = new PriorityQueue<object, long>(initialCapacity: dataCount);
// var list = new PriorityQueue<object, int>(initialCapacity: dataCount);
// for (var i = 0; i < dataCount; i++)
// {
// list.Enqueue(data[i], i);
@@ -244,7 +188,7 @@ namespace Recyclable.Collections.Benchmarks
// {
// var data = TestObjects;
// var dataCount = TestObjectCount;
// var list = new RecyclableSortedList<long, object>(BlockSize);
// var list = new RecyclableSortedList<int, object>(BlockSize);
// list.BeginUpdate();
// for (var i = 0; i < dataCount; i++)
// {
@@ -266,7 +210,7 @@ namespace Recyclable.Collections.Benchmarks
// {
// var data = TestObjects;
// var dataCount = TestObjectCount;
// var list = new RecyclableSortedList<long, object>(BlockSize);
// var list = new RecyclableSortedList<int, object>(BlockSize);
// for (var i = 0; i < dataCount; i++)
// {
// list.Add(i, data[i]);
@@ -285,7 +229,7 @@ namespace Recyclable.Collections.Benchmarks
// {
// var data = TestObjects;
// var dataCount = TestObjectCount;
// var list = new SortedList<long, object>();
// var list = new SortedList<int, object>();
// for (var i = 0; i < dataCount; i++)
// {
// list.Add(i, data[i]);
@@ -1,47 +0,0 @@
using System.Reflection;
using BenchmarkDotNet.Attributes;
using Collections.Pooled;
using Recyclable.Collections.Benchmarks.Core;
namespace Recyclable.Collections.Benchmarks.POC
{
[MemoryDiagnoser]
public partial class RecyclableLongListPocBenchmarks<T> : PocBenchmarkBase<T>
{
private long[]? _testArray;
public long[] TestObjects => _testArray ?? throw new NullReferenceException("Something is wrong and test objects are null");
public RecyclableLongList<long> TestObjectsAsRecyclableLongList => _testRecyclableLongList ?? throw new NullReferenceException($"Something is wrong and {nameof(RecyclableLongList<long>)} is null");
private RecyclableLongList<long>? _testRecyclableLongList;
private PooledList<long>? _testPooledList;
internal PooledList<long> TestPooledList => _testPooledList ?? throw new NullReferenceException($"Something is wrong and {nameof(PooledList<long>)} is null");
private static readonly MethodInfo _ensureCapacityNewFunc;
static RecyclableLongListPocBenchmarks()
{
_ensureCapacityNewFunc = typeof(RecyclableLongList<long>).GetMethod("EnsureCapacity", BindingFlags.Static | BindingFlags.NonPublic)
?? throw new NullReferenceException($"Method EnsureCapacity not found in class {nameof(RecyclableLongList<long>)}");
}
public override void Setup()
{
Console.WriteLine("******* SETTING UP EXPECTED RESULTS DATA *******");
_testArray = DataGenerator.EnumerateTestObjects(TestObjectCount);
base.Setup();
}
public override void Cleanup()
{
_testArray = null;
_testRecyclableLongList?.Dispose();
_testRecyclableLongList = null;
_testPooledList?.Dispose();
_testPooledList = null;
base.Cleanup();
}
}
}
@@ -0,0 +1,360 @@
// Ignore Spelling: Poc
using BenchmarkDotNet.Attributes;
using Collections.Benchmarks.Core;
namespace Recyclable.Collections.Benchmarks.POC
{
public class RefVsInstanceMemberBenchmarks
{
public static void Run()
{
var benchmark = new RefVsInstanceMemberBenchmarks();
benchmark.ArrayInstanceMember2();
benchmark.ArrayInstanceMember3();
benchmark.ArrayInstanceMember4();
benchmark.ArrayInstanceMember5();
benchmark.ArrayInstanceMember6();
benchmark.ArrayInstanceMemberLocalVar5();
benchmark.ArrayInstanceMemberLocalVar6();
benchmark.IntInstanceMember2();
benchmark.IntInstanceMember3();
benchmark.IntInstanceMember4();
benchmark.IntInstanceMember5();
benchmark.RefToArray2();
benchmark.RefToArray3();
benchmark.RefToArray4();
benchmark.RefToArray5();
benchmark.RefToArray6();
benchmark.RefToInt2();
benchmark.RefToInt3();
}
private readonly TestCase _testCase = new();
private class TestCase
{
private int[] _items = new int[123];
private int _count = 123;
private static int Add(int count)
{
return count;
}
public int Count
{
get => _count;
set => _count = value;
}
public ref int GetCountAsRefCount2()
{
ref int count = ref _count;
count = 234;
return ref count;
}
public ref int GetCountAsRefCount3()
{
ref int count = ref _count;
count = 234;
_ = TestCase.Add(count);
return ref count;
}
public ref int GetCountAsRefCount4()
{
ref int count = ref _count;
count = 234;
_ = TestCase.Add(count);
_ = TestCase.Add(count);
return ref count;
}
public ref int GetCountAsRefCount5()
{
ref int count = ref _count;
count = 234;
_ = TestCase.Add(count);
_ = TestCase.Add(count);
_ = TestCase.Add(count);
return ref count;
}
public int GetCountAsInstanceMember2()
{
_count = 234;
return _count;
}
public int GetCountAsInstanceMember3()
{
_count = 234;
_ = TestCase.Add(_count);
return _count;
}
public int GetCountAsInstanceMember4()
{
_count = 234;
_ = TestCase.Add(_count);
_ = TestCase.Add(_count);
return _count;
}
public int GetCountAsInstanceMember5()
{
_count = 234;
_ = TestCase.Add(_count);
_ = TestCase.Add(_count);
_ = TestCase.Add(_count);
return _count;
}
public int GetLengthAsArray2()
{
_ = TestCase.Add(_items.Length);
return _items.Length;
}
public int GetLengthAsArray3()
{
_ = TestCase.Add(_items.Length);
_ = TestCase.Add(_items.Length);
return _items.Length;
}
public int GetLengthAsArray4()
{
_ = TestCase.Add(_items.Length);
_ = TestCase.Add(_items.Length);
_ = TestCase.Add(_items.Length);
return _items.Length;
}
public int GetLengthAsArray5()
{
_ = TestCase.Add(_items.Length);
_ = TestCase.Add(_items.Length);
_ = TestCase.Add(_items.Length);
_ = TestCase.Add(_items.Length);
return _items.Length;
}
public int GetLengthAsArray6()
{
_ = TestCase.Add(_items.Length);
_ = TestCase.Add(_items.Length);
_ = TestCase.Add(_items.Length);
_ = TestCase.Add(_items.Length);
_ = TestCase.Add(_items.Length);
return _items.Length;
}
public int GetLengthAsArrayLocalVar5()
{
var items = _items;
_ = TestCase.Add(items.Length);
_ = TestCase.Add(items.Length);
_ = TestCase.Add(items.Length);
_ = TestCase.Add(items.Length);
return items.Length;
}
public int GetLengthAsArrayLocalVar6()
{
var items = _items;
_ = TestCase.Add(items.Length);
_ = TestCase.Add(items.Length);
_ = TestCase.Add(items.Length);
_ = TestCase.Add(items.Length);
_ = TestCase.Add(items.Length);
return items.Length;
}
public int GetLengthAsRefArray2()
{
ref int[] items = ref _items;
_ = TestCase.Add(items.Length);
return items.Length;
}
public int GetLengthAsRefArray3()
{
ref int[] items = ref _items;
_ = TestCase.Add(items.Length);
_ = TestCase.Add(items.Length);
return items.Length;
}
public int GetLengthAsRefArray4()
{
ref int[] items = ref _items;
_ = TestCase.Add(items.Length);
_ = TestCase.Add(items.Length);
_ = TestCase.Add(items.Length);
return items.Length;
}
public int GetLengthAsRefArray5()
{
ref int[] items = ref _items;
_ = TestCase.Add(items.Length);
_ = TestCase.Add(items.Length);
_ = TestCase.Add(items.Length);
_ = TestCase.Add(items.Length);
return items.Length;
}
public int GetLengthAsRefArray6()
{
ref int[] items = ref _items;
_ = TestCase.Add(items.Length);
_ = TestCase.Add(items.Length);
_ = TestCase.Add(items.Length);
_ = TestCase.Add(items.Length);
_ = TestCase.Add(items.Length);
return items.Length;
}
}
[Benchmark]
public void RefToInt2()
{
var count = _testCase.GetCountAsRefCount2();
DoNothing.With(count);
}
[Benchmark]
public void RefToInt3()
{
var count = _testCase.GetCountAsRefCount3();
DoNothing.With(count);
}
[Benchmark]
public void RefToInt4()
{
var count = _testCase.GetCountAsRefCount4();
DoNothing.With(count);
}
[Benchmark]
public void RefToInt5()
{
var count = _testCase.GetCountAsRefCount5();
DoNothing.With(count);
}
[Benchmark(Baseline = true)]
public void IntInstanceMember2()
{
var count = _testCase.GetCountAsInstanceMember2();
DoNothing.With(count);
}
[Benchmark(Baseline = false)]
public void IntInstanceMember3()
{
var count = _testCase.GetCountAsInstanceMember3();
DoNothing.With(count);
}
[Benchmark(Baseline = false)]
public void IntInstanceMember4()
{
var count = _testCase.GetCountAsInstanceMember4();
DoNothing.With(count);
}
[Benchmark(Baseline = false)]
public void IntInstanceMember5()
{
var count = _testCase.GetCountAsInstanceMember5();
DoNothing.With(count);
}
[Benchmark]
public void RefToArray2()
{
var count = _testCase.GetLengthAsRefArray2();
DoNothing.With(count);
}
[Benchmark]
public void RefToArray3()
{
var count = _testCase.GetLengthAsRefArray3();
DoNothing.With(count);
}
[Benchmark]
public void RefToArray4()
{
var count = _testCase.GetLengthAsRefArray4();
DoNothing.With(count);
}
[Benchmark]
public void RefToArray5()
{
var count = _testCase.GetLengthAsRefArray5();
DoNothing.With(count);
}
[Benchmark]
public void RefToArray6()
{
var count = _testCase.GetLengthAsRefArray6();
DoNothing.With(count);
}
[Benchmark(Baseline = false)]
public void ArrayInstanceMember2()
{
var count = _testCase.GetLengthAsArray2();
DoNothing.With(count);
}
[Benchmark(Baseline = false)]
public void ArrayInstanceMember3()
{
var count = _testCase.GetLengthAsArray3();
DoNothing.With(count);
}
[Benchmark(Baseline = false)]
public void ArrayInstanceMember4()
{
var count = _testCase.GetLengthAsArray4();
DoNothing.With(count);
}
[Benchmark(Baseline = false)]
public void ArrayInstanceMember5()
{
var count = _testCase.GetLengthAsArray5();
DoNothing.With(count);
}
[Benchmark(Baseline = false)]
public void ArrayInstanceMember6()
{
var count = _testCase.GetLengthAsArray6();
DoNothing.With(count);
}
[Benchmark(Baseline = false)]
public void ArrayInstanceMemberLocalVar5()
{
var count = _testCase.GetLengthAsArrayLocalVar5();
DoNothing.With(count);
}
[Benchmark(Baseline = false)]
public void ArrayInstanceMemberLocalVar6()
{
var count = _testCase.GetLengthAsArrayLocalVar6();
DoNothing.With(count);
}
}
}
@@ -1,364 +0,0 @@
using BenchmarkDotNet.Attributes;
#pragma warning disable RCS1085
namespace Recyclable.Collections.Benchmarks.POC
{
public class RefVsInstanceMemberPocBenchmarks
{
public static void Run()
{
var benchmark = new RefVsInstanceMemberPocBenchmarks();
benchmark.ArrayInstanceMember2();
benchmark.ArrayInstanceMember3();
benchmark.ArrayInstanceMember4();
benchmark.ArrayInstanceMember5();
benchmark.ArrayInstanceMember6();
benchmark.ArrayInstanceMemberLocalVar5();
benchmark.ArrayInstanceMemberLocalVar6();
benchmark.IntInstanceMember2();
benchmark.IntInstanceMember3();
benchmark.IntInstanceMember4();
benchmark.IntInstanceMember5();
benchmark.RefToArray2();
benchmark.RefToArray3();
benchmark.RefToArray4();
benchmark.RefToArray5();
benchmark.RefToArray6();
benchmark.RefToInt2();
benchmark.RefToInt3();
}
private readonly TestCase _testCase = new();
private static void DoNothing(int count)
{
_ = count;
}
private class TestCase
{
private int[] _items = new int[123];
private int _count = 123;
private static int Add(int count)
{
return count;
}
public int Count
{
get => _count;
set => _count = value;
}
public ref int GetCountAsRefCount2()
{
ref int count = ref _count;
count = 234;
return ref count;
}
public ref int GetCountAsRefCount3()
{
ref int count = ref _count;
count = 234;
_ = TestCase.Add(count);
return ref count;
}
public ref int GetCountAsRefCount4()
{
ref int count = ref _count;
count = 234;
_ = TestCase.Add(count);
_ = TestCase.Add(count);
return ref count;
}
public ref int GetCountAsRefCount5()
{
ref int count = ref _count;
count = 234;
_ = TestCase.Add(count);
_ = TestCase.Add(count);
_ = TestCase.Add(count);
return ref count;
}
public int GetCountAsInstanceMember2()
{
_count = 234;
return _count;
}
public int GetCountAsInstanceMember3()
{
_count = 234;
_ = TestCase.Add(_count);
return _count;
}
public int GetCountAsInstanceMember4()
{
_count = 234;
_ = TestCase.Add(_count);
_ = TestCase.Add(_count);
return _count;
}
public int GetCountAsInstanceMember5()
{
_count = 234;
_ = TestCase.Add(_count);
_ = TestCase.Add(_count);
_ = TestCase.Add(_count);
return _count;
}
public int GetLengthAsArray2()
{
_ = TestCase.Add(_items.Length);
return _items.Length;
}
public int GetLengthAsArray3()
{
_ = TestCase.Add(_items.Length);
_ = TestCase.Add(_items.Length);
return _items.Length;
}
public int GetLengthAsArray4()
{
_ = TestCase.Add(_items.Length);
_ = TestCase.Add(_items.Length);
_ = TestCase.Add(_items.Length);
return _items.Length;
}
public int GetLengthAsArray5()
{
_ = TestCase.Add(_items.Length);
_ = TestCase.Add(_items.Length);
_ = TestCase.Add(_items.Length);
_ = TestCase.Add(_items.Length);
return _items.Length;
}
public int GetLengthAsArray6()
{
_ = TestCase.Add(_items.Length);
_ = TestCase.Add(_items.Length);
_ = TestCase.Add(_items.Length);
_ = TestCase.Add(_items.Length);
_ = TestCase.Add(_items.Length);
return _items.Length;
}
public int GetLengthAsArrayLocalVar5()
{
var items = _items;
_ = TestCase.Add(items.Length);
_ = TestCase.Add(items.Length);
_ = TestCase.Add(items.Length);
_ = TestCase.Add(items.Length);
return items.Length;
}
public int GetLengthAsArrayLocalVar6()
{
var items = _items;
_ = TestCase.Add(items.Length);
_ = TestCase.Add(items.Length);
_ = TestCase.Add(items.Length);
_ = TestCase.Add(items.Length);
_ = TestCase.Add(items.Length);
return items.Length;
}
public int GetLengthAsRefArray2()
{
ref int[] items = ref _items;
_ = TestCase.Add(items.Length);
return items.Length;
}
public int GetLengthAsRefArray3()
{
ref int[] items = ref _items;
_ = TestCase.Add(items.Length);
_ = TestCase.Add(items.Length);
return items.Length;
}
public int GetLengthAsRefArray4()
{
ref int[] items = ref _items;
_ = TestCase.Add(items.Length);
_ = TestCase.Add(items.Length);
_ = TestCase.Add(items.Length);
return items.Length;
}
public int GetLengthAsRefArray5()
{
ref int[] items = ref _items;
_ = TestCase.Add(items.Length);
_ = TestCase.Add(items.Length);
_ = TestCase.Add(items.Length);
_ = TestCase.Add(items.Length);
return items.Length;
}
public int GetLengthAsRefArray6()
{
ref int[] items = ref _items;
_ = TestCase.Add(items.Length);
_ = TestCase.Add(items.Length);
_ = TestCase.Add(items.Length);
_ = TestCase.Add(items.Length);
_ = TestCase.Add(items.Length);
return items.Length;
}
}
[Benchmark]
public void RefToInt2()
{
var count = _testCase.GetCountAsRefCount2();
DoNothing(count);
}
[Benchmark]
public void RefToInt3()
{
var count = _testCase.GetCountAsRefCount3();
DoNothing(count);
}
[Benchmark]
public void RefToInt4()
{
var count = _testCase.GetCountAsRefCount4();
DoNothing(count);
}
[Benchmark]
public void RefToInt5()
{
var count = _testCase.GetCountAsRefCount5();
DoNothing(count);
}
[Benchmark(Baseline = true)]
public void IntInstanceMember2()
{
var count = _testCase.GetCountAsInstanceMember2();
DoNothing(count);
}
[Benchmark(Baseline = false)]
public void IntInstanceMember3()
{
var count = _testCase.GetCountAsInstanceMember3();
DoNothing(count);
}
[Benchmark(Baseline = false)]
public void IntInstanceMember4()
{
var count = _testCase.GetCountAsInstanceMember4();
DoNothing(count);
}
[Benchmark(Baseline = false)]
public void IntInstanceMember5()
{
var count = _testCase.GetCountAsInstanceMember5();
DoNothing(count);
}
[Benchmark]
public void RefToArray2()
{
var count = _testCase.GetLengthAsRefArray2();
DoNothing(count);
}
[Benchmark]
public void RefToArray3()
{
var count = _testCase.GetLengthAsRefArray3();
DoNothing(count);
}
[Benchmark]
public void RefToArray4()
{
var count = _testCase.GetLengthAsRefArray4();
DoNothing(count);
}
[Benchmark]
public void RefToArray5()
{
var count = _testCase.GetLengthAsRefArray5();
DoNothing(count);
}
[Benchmark]
public void RefToArray6()
{
var count = _testCase.GetLengthAsRefArray6();
DoNothing(count);
}
[Benchmark(Baseline = false)]
public void ArrayInstanceMember2()
{
var count = _testCase.GetLengthAsArray2();
DoNothing(count);
}
[Benchmark(Baseline = false)]
public void ArrayInstanceMember3()
{
var count = _testCase.GetLengthAsArray3();
DoNothing(count);
}
[Benchmark(Baseline = false)]
public void ArrayInstanceMember4()
{
var count = _testCase.GetLengthAsArray4();
DoNothing(count);
}
[Benchmark(Baseline = false)]
public void ArrayInstanceMember5()
{
var count = _testCase.GetLengthAsArray5();
DoNothing(count);
}
[Benchmark(Baseline = false)]
public void ArrayInstanceMember6()
{
var count = _testCase.GetLengthAsArray6();
DoNothing(count);
}
[Benchmark(Baseline = false)]
public void ArrayInstanceMemberLocalVar5()
{
var count = _testCase.GetLengthAsArrayLocalVar5();
DoNothing(count);
}
[Benchmark(Baseline = false)]
public void ArrayInstanceMemberLocalVar6()
{
var count = _testCase.GetLengthAsArrayLocalVar6();
DoNothing(count);
}
}
}
@@ -1,6 +1,7 @@
// Ignore Spelling: Poc
using BenchmarkDotNet.Attributes;
using Collections.Benchmarks.Core;
namespace Recyclable.Collections.Benchmarks.POC
{
@@ -11,7 +12,7 @@ namespace Recyclable.Collections.Benchmarks.POC
WithTypecasting,
}
public class RoundBenchmarks : PocBenchmarkBase<RoundBenchmarkType>
public class RoundBenchmarks : BaselineVsActualBenchmarkBase<RoundBenchmarkType>
{
[Params(RoundBenchmarkType.MathFloor)]
public override RoundBenchmarkType BaseDataType { get => base.BaseDataType; set => base.BaseDataType = value; }
@@ -23,17 +24,17 @@ namespace Recyclable.Collections.Benchmarks.POC
public void RoundWithMathFloor()
{
DoNothing((long)Math.Floor(TestObjectCount * OptimalParallelSearchStep));
DoNothing.With((long)Math.Floor(TestObjectCount * OptimalParallelSearchStep));
}
public void RoundWithMathRound()
{
DoNothing((long)Math.Round(TestObjectCount * OptimalParallelSearchStep, 0));
DoNothing.With((long)Math.Round(TestObjectCount * OptimalParallelSearchStep, 0));
}
public void RoundWithTypeCasting()
{
DoNothing((long)(TestObjectCount * OptimalParallelSearchStep));
DoNothing.With((long)(TestObjectCount * OptimalParallelSearchStep));
}
protected override Action GetTestMethod(RoundBenchmarkType benchmarkType) => benchmarkType switch
@@ -1,10 +1,13 @@
// Ignore Spelling: Poc
using BenchmarkDotNet.Attributes;
using Collections.Benchmarks.Core;
namespace Recyclable.Collections.Benchmarks.POC
{
static class RoundUpToPowerOf2Alternatives
{
private static readonly int[] PowersOfTwo =
private static readonly int[] _powersOfTwo =
{
1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024,
2048, 4096, 8192, 16384, 32768, 65536, 131072, 262144, 524288, 1048576,
@@ -19,14 +22,14 @@ namespace Recyclable.Collections.Benchmarks.POC
}
// Find the smallest power of 2 greater than or equal to value using a lookup table
int index = Array.BinarySearch(PowersOfTwo, value);
int index = Array.BinarySearch(_powersOfTwo, value);
if (index < 0)
{
// If value is not a power of 2, use the next power of 2 from the table
index = ~index;
}
return PowersOfTwo[index];
return _powersOfTwo[index];
}
public static int RightBitShifting(int value)
@@ -74,7 +77,7 @@ namespace Recyclable.Collections.Benchmarks.POC
IsPowOf2_GreaterEqual,
}
public class RoundUpToPowerOf2vsOtherBenchmarks : PocBenchmarkBase<RoundUpToPowerOf2BenchmarkType>
public class RoundUpToPowerOf2vsOtherBenchmarks : BaselineVsActualBenchmarkBase<RoundUpToPowerOf2BenchmarkType>
{
// [Params(-850_000, 850_000)]
[Params(-int.MaxValue, int.MaxValue)]
@@ -89,42 +92,44 @@ namespace Recyclable.Collections.Benchmarks.POC
private void BitOperations()
{
DoNothing(System.Numerics.BitOperations.RoundUpToPowerOf2((uint)base.TestObjectCount));
DoNothing.With(System.Numerics.BitOperations.RoundUpToPowerOf2((uint)base.TestObjectCount));
}
private void RightBitShifting()
{
DoNothing(RoundUpToPowerOf2Alternatives.RightBitShifting(TestObjectCount));
DoNothing.With(RoundUpToPowerOf2Alternatives.RightBitShifting(TestObjectCount));
}
private void LeftBitShifting()
{
DoNothing(RoundUpToPowerOf2Alternatives.LeftBitShifting(TestObjectCount));
DoNothing.With(RoundUpToPowerOf2Alternatives.LeftBitShifting(TestObjectCount));
}
private void BinarySearch()
{
DoNothing(RoundUpToPowerOf2Alternatives.BinarySearch(TestObjectCount));
DoNothing.With(RoundUpToPowerOf2Alternatives.BinarySearch(TestObjectCount));
}
private void IsPowOf2()
{
DoNothing((TestObjectCount & (TestObjectCount - 1)) == 0 && TestObjectCount > 0);
DoNothing.With((TestObjectCount & (TestObjectCount - 1)) == 0 && TestObjectCount > 0);
}
private void IsPowOf2_GreaterThanFirst()
{
DoNothing(TestObjectCount > 0 && (TestObjectCount & (TestObjectCount - 1)) == 0);
DoNothing.With(TestObjectCount > 0 && (TestObjectCount & (TestObjectCount - 1)) == 0);
}
private void IsPowOf2_WithIf()
{
DoNothing(TestObjectCount > 0 ? (TestObjectCount & (TestObjectCount - 1)) == 0 : false);
#pragma warning disable IDE0075 // This is intentional
DoNothing.With(TestObjectCount > 0 ? (TestObjectCount & (TestObjectCount - 1)) == 0 : false);
#pragma warning restore IDE0075
}
private void IsPowOf2_GreaterEqual()
{
DoNothing(TestObjectCount >= 0 && TestObjectCount != 0 && (TestObjectCount & (TestObjectCount - 1)) == 0);
DoNothing.With(TestObjectCount >= 0 && TestObjectCount != 0 && (TestObjectCount & (TestObjectCount - 1)) == 0);
}
protected override Action? GetTestMethod(RoundUpToPowerOf2BenchmarkType benchmarkType) => benchmarkType switch
@@ -1,64 +0,0 @@
using System.Runtime.CompilerServices;
using BenchmarkDotNet.Attributes;
namespace Recyclable.Collections.Benchmarks.POC
{
public enum SpanConstructorVsTypecastingPocBenchmarkType
{
Unknown,
Constructor,
TypeCasting,
}
[MemoryDiagnoser]
public class SpanConstructorVsTypecastingPocBenchmarks : PocBenchmarkBase<SpanConstructorVsTypecastingPocBenchmarkType>
{
private int[]? TestData { get; set; }
[MethodImpl(MethodImplOptions.NoOptimization | MethodImplOptions.NoInlining)]
private void DoNothing(ReadOnlySpan<int> span) { }
[Params(SpanConstructorVsTypecastingPocBenchmarkType.TypeCasting)]
public override SpanConstructorVsTypecastingPocBenchmarkType BaseDataType { get => base.BaseDataType; set => base.BaseDataType = value; }
[Params(SpanConstructorVsTypecastingPocBenchmarkType.Constructor)]
public override SpanConstructorVsTypecastingPocBenchmarkType DataType { get => base.DataType; set => base.DataType = value; }
[Params(8)]
public override int TestObjectCount { get => base.TestObjectCount; set => base.TestObjectCount = value; }
public static void Run()
{
var benchmark = new SpanConstructorVsTypecastingPocBenchmarks();
benchmark.Setup();
benchmark.Constructor();
benchmark.TypeCasting();
benchmark.Cleanup();
}
public void Constructor()
{
ReadOnlySpan<int> span = new(TestData);
DoNothing(span);
}
public void TypeCasting()
{
ReadOnlySpan<int> span = TestData;
DoNothing(span);
}
public override void Setup()
{
TestData = new int[TestObjectCount];
base.Setup();
}
protected override Action? GetTestMethod(SpanConstructorVsTypecastingPocBenchmarkType benchmarkType) => benchmarkType switch
{
SpanConstructorVsTypecastingPocBenchmarkType.Constructor => Constructor,
SpanConstructorVsTypecastingPocBenchmarkType.TypeCasting => TypeCasting,
_ => throw CreateUnknownBenchmarkTypeException(benchmarkType),
};
}
}
@@ -0,0 +1,63 @@
// Ignore Spelling: Poc
using BenchmarkDotNet.Attributes;
using Collections.Benchmarks.Core;
namespace Recyclable.Collections.Benchmarks.POC
{
public enum SpanConstructorVsTypecastingBenchmarkType
{
Unknown,
Constructor,
TypeCasting,
}
[MemoryDiagnoser]
public class SpanConstructorVsTypecastingBenchmarks : BaselineVsActualBenchmarkBase<SpanConstructorVsTypecastingBenchmarkType>
{
private int[]? TestData { get; set; }
[Params(SpanConstructorVsTypecastingBenchmarkType.TypeCasting)]
public override SpanConstructorVsTypecastingBenchmarkType BaseDataType { get => base.BaseDataType; set => base.BaseDataType = value; }
[Params(SpanConstructorVsTypecastingBenchmarkType.Constructor)]
public override SpanConstructorVsTypecastingBenchmarkType DataType { get => base.DataType; set => base.DataType = value; }
[Params(8)]
public override int TestObjectCount { get => base.TestObjectCount; set => base.TestObjectCount = value; }
public static void Run()
{
var benchmark = new SpanConstructorVsTypecastingBenchmarks();
benchmark.Setup();
benchmark.Constructor();
benchmark.TypeCasting();
benchmark.Cleanup();
}
public void Constructor()
{
ReadOnlySpan<int> span = new(TestData);
DoNothing.With(span);
}
public void TypeCasting()
{
ReadOnlySpan<int> span = TestData;
DoNothing.With(span);
}
public override void Setup()
{
TestData = new int[TestObjectCount];
base.Setup();
}
protected override Action? GetTestMethod(SpanConstructorVsTypecastingBenchmarkType benchmarkType) => benchmarkType switch
{
SpanConstructorVsTypecastingBenchmarkType.Constructor => Constructor,
SpanConstructorVsTypecastingBenchmarkType.TypeCasting => TypeCasting,
_ => throw CreateUnknownBenchmarkTypeException(benchmarkType),
};
}
}
@@ -1,6 +1,7 @@
// Ignore Spelling: Poc
using BenchmarkDotNet.Attributes;
using Collections.Benchmarks.Core;
namespace Recyclable.Collections.Benchmarks.POC
{
@@ -14,7 +15,7 @@ namespace Recyclable.Collections.Benchmarks.POC
SpanSet
}
public class SpanVsArrayBenchmarks : RecyclableBenchmarkBase<SpanVsArrayBenchmarkType>
public class SpanVsArrayBenchmarks : DataDrivenBenchmarksBase<SpanVsArrayBenchmarkType>
{
// [Params(SpanVsArrayBenchmarkType.ArrayGetWithVar, SpanVsArrayBenchmarkType.SpanGet)]
// [Params(SpanVsArrayBenchmarkType.ArraySetWithVar, SpanVsArrayBenchmarkType.SpanSet)]
@@ -46,7 +47,7 @@ namespace Recyclable.Collections.Benchmarks.POC
var dataCount = TestObjectCount;
for (int i = 0; i < dataCount; i++)
{
DoNothing(data[i]);
DoNothing.With(data[i]);
}
}
@@ -55,7 +56,7 @@ namespace Recyclable.Collections.Benchmarks.POC
var dataCount = TestObjectCount;
for (int i = 0; i < dataCount; i++)
{
DoNothing(_testObjects![i]);
DoNothing.With(_testObjects![i]);
}
}
@@ -65,7 +66,7 @@ namespace Recyclable.Collections.Benchmarks.POC
Span<int> data = new(_testObjects, 0, dataCount);
for (int i = 0; i < dataCount; i++)
{
DoNothing(data[i]);
DoNothing.With(data[i]);
}
}
+15 -16
View File
@@ -1,6 +1,5 @@
using BenchmarkDotNet.Configs;
using BenchmarkDotNet.Running;
using Recyclable.Collections.Benchmarks.POC;
#pragma warning disable RCS1036, RCS1213, IDE0051
@@ -31,7 +30,7 @@ namespace Recyclable.Collections.Benchmarks
foreach (var _ in Enumerable.Range(1, 1000))
{
// benchmark.RecyclableList_Create_WithCapacity();
//benchmark.RecyclableList_Create_WithCapacity();
}
benchmark.Cleanup();
@@ -39,26 +38,26 @@ namespace Recyclable.Collections.Benchmarks
static void RunPocBenchmarks()
{
_ = BenchmarkRunner.Run<BoolOrComparePocBenchmarks>(BenchmarkConfig);
_ = BenchmarkRunner.Run<DelegateVsComparerPocBenchmarks>(BenchmarkConfig);
_ = BenchmarkRunner.Run<ModuloPocBenchmarks>(BenchmarkConfig);
_ = BenchmarkRunner.Run<TaskRunVsTaskFactoryStartNewBenchmarks>(BenchmarkConfig);
_ = BenchmarkRunner.Run<RefVsInstanceMemberPocBenchmarks>(BenchmarkConfig);
_ = BenchmarkRunner.Run<RoundBenchmarks>(BenchmarkConfig);
_ = BenchmarkRunner.Run<SpanVsArrayBenchmarks>(BenchmarkConfig);
_ = BenchmarkRunner.Run<LessOperatorVsAndOperatorBenchmarks>(BenchmarkConfig);
_ = BenchmarkRunner.Run<EqualVsContainsInConsecutiveOrderBenchmarks>(BenchmarkConfig);
_ = BenchmarkRunner.Run<RoundUpToPowerOf2vsOtherBenchmarks>(BenchmarkConfig);
_ = BenchmarkRunner.Run<GreaterOperatorVsDoesntEqualOperatorBenchmarks>(BenchmarkConfig);
_ = BenchmarkRunner.Run<SpanConstructorVsTypecastingPocBenchmarks>(BenchmarkConfig);
//_ = BenchmarkRunner.Run<BoolOrCompareBenchmarks>(BenchmarkConfig);
//_ = BenchmarkRunner.Run<DelegateVsComparerBenchmarks>(BenchmarkConfig);
//_ = BenchmarkRunner.Run<ModuloBenchmarks>(BenchmarkConfig);
//_ = BenchmarkRunner.Run<TaskRunVsTaskFactoryStartNewBenchmarks>(BenchmarkConfig);
//_ = BenchmarkRunner.Run<RefVsInstanceMemberBenchmarks>(BenchmarkConfig);
//_ = BenchmarkRunner.Run<RoundBenchmarks>(BenchmarkConfig);
//_ = BenchmarkRunner.Run<SpanVsArrayBenchmarks>(BenchmarkConfig);
//_ = BenchmarkRunner.Run<LessOperatorVsAndOperatorBenchmarks>(BenchmarkConfig);
//_ = BenchmarkRunner.Run<EqualVsContainsInConsecutiveOrderBenchmarks>(BenchmarkConfig);
//_ = BenchmarkRunner.Run<RoundUpToPowerOf2vsOtherBenchmarks>(BenchmarkConfig);
//_ = BenchmarkRunner.Run<GreaterOperatorVsNotEqualOperatorBenchmarks>(BenchmarkConfig);
//_ = BenchmarkRunner.Run<SpanConstructorVsTypecastingBenchmarks>(BenchmarkConfig);
//ArraySizeLimitBenchmarks.Run();
}
static void Main()
{
RunRecyclableCollectionsBenchmarks();
// RunPocBenchmarks();
// RunRecyclableCollectionsBenchmarks();
RunPocBenchmarks();
// RunSelectedBenchmarks();
// RunAssemblyBenchmarks();
}
@@ -10,7 +10,7 @@
</PropertyGroup>
<ItemGroup>
<PackageReference Include="BenchmarkDotNet" Version="0.13.5" />
<PackageReference Include="Collections.Benchmarks.Core" Version="0.0.3" />
<PackageReference Include="Collections.Pooled" Version="1.0.82" />
</ItemGroup>
@@ -5,7 +5,7 @@
<Nullable>enable</Nullable>
<GeneratePackageOnBuild>true</GeneratePackageOnBuild>
<PackageId>Recyclable.Collections</PackageId>
<PackageVersion>0.0.6</PackageVersion>
<PackageVersion>0.0.6.1</PackageVersion>
<Authors>Marek Lemańczyk</Authors>
<Company>N/A</Company>
<Product>Recyclable.Collections</Product>
@@ -17,11 +17,14 @@
<PackageLicenseFile>LICENSE.md</PackageLicenseFile>
<PackageReadmeFile>README.md</PackageReadmeFile>
<RepositoryType>git</RepositoryType>
<PackageReleaseNotes>List&lt;T&gt; compatibility pack added for RecyclableList&lt;T&gt;. Various performance improvements and fixes.</PackageReleaseNotes>
<PackageReleaseNotes>List&lt;T&gt; compatibility code moved to Recyclable.Collections.Compatibility.List package. Cleanup.</PackageReleaseNotes>
<Platforms>AnyCPU;x64</Platforms>
</PropertyGroup>
<ItemGroup>
<None Include="..\logo.png" Pack="true" PackagePath="" Link="logo.png">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Include="..\LICENSE.md" Pack="true" PackagePath="" Link="LICENSE.md">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
@@ -31,7 +34,6 @@
</ItemGroup>
<ItemGroup>
<PackageReference Include="Microsoft.Extensions.ObjectPool" Version="7.0.5" />
<PackageReference Include="morelinq" Version="3.4.2" />
<PackageReference Include="Microsoft.Extensions.ObjectPool" Version="7.0.12" />
</ItemGroup>
</Project>
@@ -1,272 +0,0 @@
using System.Numerics;
namespace Recyclable.Collections
{
[Obsolete("It'll be moved to Recyclable.Collections.Compatibility.List NuGet package in the next release.")]
public static class zRecyclableListCompatibilityListFind
{
public static bool Exists<T>(this RecyclableList<T> list, Predicate<T> match)
{
int sourceItemsCount = list._count;
if (sourceItemsCount == 0)
{
return false;
}
ReadOnlySpan<T> sourceSpan = list._memoryBlock;
for (var itemIndex = 0; itemIndex < sourceItemsCount; itemIndex++)
{
if (match(sourceSpan[itemIndex]))
{
return true;
}
}
return false;
}
public static T? Find<T>(this RecyclableList<T> list, Predicate<T> match)
{
int sourceItemsCount = list._count;
if (sourceItemsCount == 0)
{
return default;
}
ReadOnlySpan<T> sourceSpan = list._memoryBlock;
for (var itemIndex = 0; itemIndex < sourceItemsCount; itemIndex++)
{
if (match(sourceSpan[itemIndex]))
{
return sourceSpan[itemIndex];
}
}
return default;
}
public static RecyclableList<T> FindAll<T>(this RecyclableList<T> list, Predicate<T> match)
{
int sourceItemsCount = list._count;
if (sourceItemsCount == 0)
{
return new();
}
ReadOnlySpan<T> sourceSpan = list._memoryBlock;
RecyclableList<T> result = new(sourceItemsCount >> 3);
Span<T> resultSpan = result._memoryBlock;
int capacity = result._capacity,
resultItemsCount = 0;
for (var itemIndex = 0; itemIndex < sourceItemsCount; itemIndex++)
{
if (match(sourceSpan[itemIndex]))
{
if (resultItemsCount + 1 > capacity)
{
capacity = checked((int)BitOperations.RoundUpToPowerOf2((uint)resultItemsCount + 1));
_ = RecyclableListHelpers<T>.EnsureCapacity(result, resultItemsCount, capacity);
resultSpan = result._memoryBlock;
}
resultSpan[resultItemsCount++] = sourceSpan[itemIndex];
}
}
result._capacity = capacity;
result._count = resultItemsCount;
return result;
}
public static RecyclableList<int> FindAllIndexes<T>(this RecyclableList<T> list, Predicate<T> match)
{
int sourceItemsCount = list._count;
if (sourceItemsCount == 0)
{
return new();
}
ReadOnlySpan<T> sourceSpan = list._memoryBlock;
RecyclableList<int> result = new(sourceItemsCount >> 3);
Span<int> resultSpan = result._memoryBlock;
int capacity = result._capacity,
resultItemsCount = 0;
for (var itemIndex = 0; itemIndex < sourceItemsCount; itemIndex++)
{
if (match(sourceSpan[itemIndex]))
{
if (resultItemsCount + 1 > capacity)
{
capacity = checked((int)BitOperations.RoundUpToPowerOf2((uint)resultItemsCount + 1));
_ = RecyclableListHelpers<int>.EnsureCapacity(result, resultItemsCount, capacity);
resultSpan = result._memoryBlock;
}
resultSpan[resultItemsCount++] = itemIndex;
}
}
result._capacity = capacity;
result._count = resultItemsCount;
return result;
}
public static int FindIndex<T>(this RecyclableList<T> list, int startIndex, int count, Predicate<T> match)
{
int sourceItemsCount = list._count;
if (sourceItemsCount == 0 || startIndex >= sourceItemsCount)
{
return RecyclableDefaults.ItemNotFoundIndex;
}
sourceItemsCount = Math.Min(sourceItemsCount, startIndex + sourceItemsCount);
ReadOnlySpan<T> sourceSpan = list._memoryBlock;
for (var itemIndex = startIndex; itemIndex < sourceItemsCount; itemIndex++)
{
if (match(sourceSpan[itemIndex]))
{
return itemIndex;
}
}
return RecyclableDefaults.ItemNotFoundIndex;
}
public static int FindIndex<T>(this RecyclableList<T> list, int startIndex, Predicate<T> match)
{
int sourceItemsCount = list._count;
if (sourceItemsCount == 0 || startIndex >= sourceItemsCount)
{
return RecyclableDefaults.ItemNotFoundIndex;
}
sourceItemsCount = Math.Min(sourceItemsCount, startIndex + sourceItemsCount);
ReadOnlySpan<T> sourceSpan = list._memoryBlock;
for (var itemIndex = startIndex; itemIndex < sourceItemsCount; itemIndex++)
{
if (match(sourceSpan[itemIndex]))
{
return itemIndex;
}
}
return RecyclableDefaults.ItemNotFoundIndex;
}
public static int FindIndex<T>(this RecyclableList<T> list, Predicate<T> match)
{
int sourceItemsCount = list._count;
if (sourceItemsCount == 0)
{
return RecyclableDefaults.ItemNotFoundIndex;
}
ReadOnlySpan<T> sourceSpan = list._memoryBlock;
for (var itemIndex = 0; itemIndex < sourceItemsCount; itemIndex++)
{
if (match(sourceSpan[itemIndex]))
{
return itemIndex;
}
}
return RecyclableDefaults.ItemNotFoundIndex;
}
public static T? FindLast<T>(this RecyclableList<T> list, Predicate<T> match)
{
if (list._count == 0)
{
return default;
}
ReadOnlySpan<T> sourceSpan = list._memoryBlock;
for (var itemIndex = list._count - 1; itemIndex >= 0; itemIndex--)
{
if (match(sourceSpan[itemIndex]))
{
return sourceSpan[itemIndex];
}
}
return default;
}
public static int FindLastIndex<T>(this RecyclableList<T> list, int startIndex, int count, Predicate<T> match)
{
if (count == 0)
{
if (startIndex != -1)
{
ThrowHelper.ThrowArgumentOutOfRangeException_Index();
}
}
else if (count < 0 || startIndex - count + 1 < 0)
{
ThrowHelper.ThrowArgumentOutOfRangeException_Count();
}
if (startIndex < 0)
{
return RecyclableDefaults.ItemNotFoundIndex;
}
int sourceItemsCount = count; // startIndex - count + 1 >= 0 ? count : startIndex + 1;
if (sourceItemsCount == 0)
{
return RecyclableDefaults.ItemNotFoundIndex;
}
int lastItemIndex = startIndex - sourceItemsCount;
ReadOnlySpan<T> sourceSpan = list._memoryBlock;
for (var itemIndex = startIndex; itemIndex > lastItemIndex; itemIndex--)
{
if (match(sourceSpan[itemIndex]))
{
return itemIndex;
}
}
return RecyclableDefaults.ItemNotFoundIndex;
}
public static int FindLastIndex<T>(this RecyclableList<T> list, int startIndex, Predicate<T> match)
{
if (list._count == 0 || startIndex < 0)
{
return RecyclableDefaults.ItemNotFoundIndex;
}
ReadOnlySpan<T> sourceSpan = list._memoryBlock;
for (var itemIndex = startIndex; itemIndex >= 0; itemIndex--)
{
if (match(sourceSpan[itemIndex]))
{
return itemIndex;
}
}
return RecyclableDefaults.ItemNotFoundIndex;
}
public static int FindLastIndex<T>(this RecyclableList<T> list, Predicate<T> match)
{
if (list._count == 0)
{
return RecyclableDefaults.ItemNotFoundIndex;
}
ReadOnlySpan<T> sourceSpan = list._memoryBlock;
for (var itemIndex = list._count - 1; itemIndex >= 0; itemIndex--)
{
if (match(sourceSpan[itemIndex]))
{
return itemIndex;
}
}
return RecyclableDefaults.ItemNotFoundIndex;
}
}
}
@@ -1,26 +0,0 @@
namespace Recyclable.Collections
{
[Obsolete("It'll be moved to Recyclable.Collections.Compatibility.List NuGet package in the next release.")]
public static class zRecyclableListCompatibilityListIndexOf
{
public static int IndexOf<T>(this RecyclableList<T> list, T item, int index) => list._count != 0
? Array.IndexOf(list._memoryBlock, item, index, list._count - index)
: RecyclableDefaults.ItemNotFoundIndex;
public static int IndexOf<T>(this RecyclableList<T> list, T item, int index, int count) => list._count != 0
? Array.IndexOf(list._memoryBlock, item, index, count)
: RecyclableDefaults.ItemNotFoundIndex;
public static int LastIndexOf<T>(this RecyclableList<T> list, T item) => list._count != 0
? Array.LastIndexOf(list._memoryBlock, item, list._count - 1)
: RecyclableDefaults.ItemNotFoundIndex;
public static int LastIndexOf<T>(this RecyclableList<T> list, T item, int index) => list._count != 0
? Array.LastIndexOf(list._memoryBlock, item, index)
: RecyclableDefaults.ItemNotFoundIndex;
public static int LastIndexOf<T>(this RecyclableList<T> list, T item, int index, int count) => list._count != 0
? Array.LastIndexOf(list._memoryBlock, item, index, count)
: RecyclableDefaults.ItemNotFoundIndex;
}
}
@@ -1,358 +0,0 @@
using System.Collections;
using System.Numerics;
using System.Runtime.CompilerServices;
namespace Recyclable.Collections
{
[Obsolete("It'll be moved to Recyclable.Collections.Compatibility.List NuGet package in the next release.")]
public static class zRecyclableListCompatibilityListInsertRange
{
private static void InsertRangeEnumerated<T>(this RecyclableList<T> list, int index, IEnumerable<T> items, int growByCount)
{
var enumerator = items.GetEnumerator();
if (!enumerator.MoveNext())
{
return;
}
int capacity = list._capacity,
added = 0,
available = capacity - list._count,
i,
movingBlockLength = list._count - index;
T[] memoryBlock = list._memoryBlock;
if (available > 0)
{
Array.Copy(memoryBlock, index, memoryBlock, capacity - movingBlockLength, movingBlockLength);
}
Span<T> memorySpan = memoryBlock;
do
{
if (index + available + movingBlockLength > capacity)
{
var capacityBeforeIncrease = capacity;
capacity = checked((int)BitOperations.RoundUpToPowerOf2((uint)(capacity + growByCount)));
_ = RecyclableListHelpers<T>.EnsureCapacity(list, memoryBlock.Length, capacity);
memorySpan = memoryBlock = list._memoryBlock;
available = capacity - index - movingBlockLength;
Array.Copy(memoryBlock, capacityBeforeIncrease - movingBlockLength, memoryBlock, capacity - movingBlockLength, movingBlockLength);
}
for (i = 0; i < available; i++)
{
memorySpan[index++] = enumerator.Current;
if (!enumerator.MoveNext())
{
added++;
break;
}
}
added += i;
}
while (i == available);
if (i != available)
{
Array.Copy(memoryBlock, capacity - movingBlockLength, memoryBlock, index, movingBlockLength);
if (RecyclableList<T>._needsClearing)
{
Array.Clear(memoryBlock, capacity - movingBlockLength, movingBlockLength);
}
}
list._count += added;
list._capacity = capacity;
}
private static void InsertRangeWithKnownCount<T>(this RecyclableList<T> list, int index, IEnumerable<T> items, int currentItemsCount, int requiredAdditionalCapacity)
{
list._capacity = RecyclableListHelpers<T>.EnsureCapacity(list, currentItemsCount, checked((int)BitOperations.RoundUpToPowerOf2((uint)(currentItemsCount + requiredAdditionalCapacity))));
Array.Copy(list._memoryBlock, index, list._memoryBlock, index + requiredAdditionalCapacity, list._count - index);
Span<T> memorySpan = list._memoryBlock;
foreach (var item in items)
{
memorySpan[index++] = item;
}
list._count += requiredAdditionalCapacity;
list._version++;
}
[MethodImpl(MethodImplOptions.NoInlining | MethodImplOptions.AggressiveOptimization)]
public static void InsertRange<T>(this RecyclableList<T> list, int index, in Array items)
{
if (list._capacity < list._count + items.Length)
{
list._capacity = RecyclableListHelpers<T>.EnsureCapacity(list, list._count, checked((int)BitOperations.RoundUpToPowerOf2((uint)(list._count + items.Length))));
}
T[] memoryBlock = list._memoryBlock;
Array.Copy(memoryBlock, index, memoryBlock, index + items.Length, list._count - index);
Array.Copy(items, items.GetLowerBound(0), memoryBlock, index, items.Length);
list._count += items.Length;
list._version++;
}
[MethodImpl(MethodImplOptions.NoInlining | MethodImplOptions.AggressiveOptimization)]
public static void InsertRange<T>(this RecyclableList<T> list, int index, in T[] items)
{
if (list._capacity < list._count + items.Length)
{
list._capacity = RecyclableListHelpers<T>.EnsureCapacity(list, list._count, checked((int)BitOperations.RoundUpToPowerOf2((uint)(list._count + items.Length))));
}
T[] memoryBlock = list._memoryBlock;
Array.Copy(memoryBlock, index, memoryBlock, index + items.Length, list._count - index);
new ReadOnlySpan<T>(items).CopyTo(new Span<T>(memoryBlock, index, items.Length));
list._count += items.Length;
list._version++;
}
[MethodImpl(MethodImplOptions.NoInlining | MethodImplOptions.AggressiveOptimization)]
public static void InsertRange<T>(this RecyclableList<T> list, int index, ReadOnlySpan<T> items)
{
if (list._capacity < list._count + items.Length)
{
list._capacity = RecyclableListHelpers<T>.EnsureCapacity(list, list._count, checked((int)BitOperations.RoundUpToPowerOf2((uint)(list._count + items.Length))));
}
T[] memoryBlock = list._memoryBlock;
Array.Copy(memoryBlock, index, memoryBlock, index + items.Length, list._count - index);
items.CopyTo(new Span<T>(memoryBlock, index, items.Length));
list._count += items.Length;
list._version++;
}
[MethodImpl(MethodImplOptions.NoInlining | MethodImplOptions.AggressiveOptimization)]
public static void InsertRange<T>(this RecyclableList<T> list, int index, Span<T> items)
{
if (list._capacity < list._count + items.Length)
{
list._capacity = RecyclableListHelpers<T>.EnsureCapacity(list, list._count, checked((int)BitOperations.RoundUpToPowerOf2((uint)(list._count + items.Length))));
}
T[] memoryBlock = list._memoryBlock;
Array.Copy(memoryBlock, index, memoryBlock, index + items.Length, list._count - index);
items.CopyTo(new Span<T>(memoryBlock, index, items.Length));
list._count += items.Length;
list._version++;
}
[MethodImpl(MethodImplOptions.NoInlining | MethodImplOptions.AggressiveOptimization)]
public static void InsertRange<T>(this RecyclableList<T> list, int index, List<T> items)
{
if (list._capacity < list._count + items.Count)
{
list._capacity = RecyclableListHelpers<T>.EnsureCapacity(list, list._count, checked((int)BitOperations.RoundUpToPowerOf2((uint)(list._count + items.Count))));
}
T[] memoryBlock = list._memoryBlock;
Array.Copy(memoryBlock, index, memoryBlock, index + items.Count, list._count - index);
items.CopyTo(memoryBlock, index);
list._count += items.Count;
list._version++;
}
[MethodImpl(MethodImplOptions.NoInlining | MethodImplOptions.AggressiveOptimization)]
public static void InsertRange<T>(this RecyclableList<T> list, int index, ICollection items)
{
if (list._capacity < list._count + items.Count)
{
list._capacity = RecyclableListHelpers<T>.EnsureCapacity(list, list._count, checked((int)BitOperations.RoundUpToPowerOf2((uint)(list._count + items.Count))));
}
T[] memoryBlock = list._memoryBlock;
Array.Copy(memoryBlock, index, memoryBlock, index + items.Count, list._count - index);
items.CopyTo(list._memoryBlock, index);
list._count += items.Count;
list._version++;
}
[MethodImpl(MethodImplOptions.NoInlining | MethodImplOptions.AggressiveOptimization)]
public static void InsertRange<T>(this RecyclableList<T> list, int index, ICollection<T> items)
{
if (list._capacity < list._count + items.Count)
{
list._capacity = RecyclableListHelpers<T>.EnsureCapacity(list, list._count, checked((int)BitOperations.RoundUpToPowerOf2((uint)(list._count + items.Count))));
}
T[] memoryBlock = list._memoryBlock;
Array.Copy(memoryBlock, index, memoryBlock, index + items.Count, list._count - index);
items.CopyTo(memoryBlock, index);
list._count += items.Count;
list._version++;
}
[MethodImpl(MethodImplOptions.NoInlining | MethodImplOptions.AggressiveOptimization)]
public static void InsertRange<T>(this RecyclableList<T> list, int index, RecyclableList<T> items)
{
if (list._capacity < list._count + items._count)
{
list._capacity = RecyclableListHelpers<T>.EnsureCapacity(list, list._count, checked((int)BitOperations.RoundUpToPowerOf2((uint)(list._count + items._count))));
}
T[] memoryBlock = list._memoryBlock;
Array.Copy(memoryBlock, index, memoryBlock, index + items.Count, list._count - index);
new ReadOnlySpan<T>(items._memoryBlock, 0, items._count).CopyTo(new(list._memoryBlock, index, items._count));
list._count += items._count;
list._version++;
}
[MethodImpl(MethodImplOptions.NoInlining | MethodImplOptions.AggressiveOptimization)]
public static void InsertRange<T>(this RecyclableList<T> list, int index, RecyclableLongList<T> items)
{
if (items._longCount == 0)
{
return;
}
int oldCount = list._count;
long sourceItemsCount = items._longCount;
if (oldCount + sourceItemsCount > int.MaxValue)
{
ThrowHelper.ThrowArgumentOutOfRangeException(nameof(items), $"The total number of items in source and target table exceeds the maximum capacity of {nameof(RecyclableList<T>)}, equal {int.MaxValue}. Please consider using {nameof(RecyclableLongList<T>)}, instead");
}
int targetCapacity = oldCount + (int)sourceItemsCount;
if (list._capacity < targetCapacity)
{
list._capacity = RecyclableListHelpers<T>.EnsureCapacity(list, oldCount, checked((int)BitOperations.RoundUpToPowerOf2((uint)targetCapacity)));
}
T[] memoryBlock = list._memoryBlock;
Array.Copy(memoryBlock, index, memoryBlock, index + items.Count, oldCount - index);
Span<T> targetSpan = new(list._memoryBlock, index, list._capacity - index),
itemsSpan;
int blockIndex,
sourceBlockSize = items._blockSize,
lastBlockIndex = (int)(sourceItemsCount >> items._blockSizePow2BitShift) - 1;
for (blockIndex = 0; blockIndex <= lastBlockIndex; blockIndex++)
{
itemsSpan = new(items._memoryBlocks[blockIndex], 0, sourceBlockSize);
itemsSpan.CopyTo(targetSpan);
targetSpan = targetSpan[sourceBlockSize..];
}
if (blockIndex == 0)
{
itemsSpan = new(items._memoryBlocks[blockIndex], 0, (int)sourceItemsCount);
itemsSpan.CopyTo(targetSpan);
}
else if (blockIndex <= items._lastBlockWithData)
{
itemsSpan = new(items._memoryBlocks[blockIndex], 0, items._nextItemIndex > 0 ? items._nextItemIndex : sourceBlockSize);
itemsSpan.CopyTo(targetSpan);
}
list._count = targetCapacity;
list._version++;
}
public static IEnumerator InsertRange<T>(this RecyclableList<T> list, int index, IEnumerable source, int growByCount = RecyclableDefaults.MinPooledArrayLength)
{
int targetItemIndex = list._count;
Span<T> memorySpan;
int i;
var enumerator = source.GetEnumerator();
int capacity = list._capacity;
memorySpan = list._memoryBlock;
if (enumerator.MoveNext())
{
int available = capacity - targetItemIndex;
do
{
if (targetItemIndex + growByCount > capacity)
{
capacity = RecyclableListHelpers<T>.EnsureCapacity(list, targetItemIndex, checked((int)BitOperations.RoundUpToPowerOf2((uint)(targetItemIndex + growByCount))));
memorySpan = list._memoryBlock;
available = capacity - targetItemIndex;
}
for (i = 0; i < available; i++)
{
memorySpan[targetItemIndex++] = (T)enumerator.Current;
if (!enumerator.MoveNext())
{
break;
}
}
}
while (i >= available);
}
list._capacity = capacity;
list._count = targetItemIndex;
return enumerator;
}
public static void InsertRange<T>(this RecyclableList<T> list, int index, IReadOnlyList<T> items)
{
int sourceItemsCount = items.Count;
if (list._capacity < list._count + sourceItemsCount)
{
list._capacity = RecyclableListHelpers<T>.EnsureCapacity(list, list._count, checked((int)BitOperations.RoundUpToPowerOf2((uint)(list._count + sourceItemsCount))));
}
Span<T> memorySpan = new(list._memoryBlock, list._count, sourceItemsCount);
for (var sourceItemIndex = 0; sourceItemIndex < sourceItemsCount; sourceItemIndex++)
{
memorySpan[sourceItemIndex] = items[sourceItemIndex];
}
list._count += sourceItemsCount;
}
[MethodImpl(MethodImplOptions.NoInlining | MethodImplOptions.AggressiveOptimization)]
public static void InsertRange<T>(this RecyclableList<T> list, int index, IEnumerable<T> items, int growByCount = RecyclableDefaults.MinPooledArrayLength)
{
if (items is RecyclableList<T> sourceRecyclableList)
{
InsertRange(list, index, sourceRecyclableList);
}
else if (items is RecyclableLongList<T> sourceRecyclableLongList)
{
InsertRange(list, index, sourceRecyclableLongList);
}
else if (items is T[] sourceArray)
{
InsertRange(list, index, sourceArray);
}
else if (items is Array sourceArrayWithObjects)
{
InsertRange(list, index, sourceArrayWithObjects);
}
else if (items is List<T> sourceList)
{
InsertRange(list, index, sourceList);
}
else if (items is ICollection<T> sourceICollection)
{
InsertRange(list, index, sourceICollection);
}
else if (items is ICollection sourceICollectionWithObjects)
{
InsertRange(list, index, sourceICollectionWithObjects);
}
else if (items is IReadOnlyList<T> sourceIReadOnlyList)
{
InsertRange(list, index, sourceIReadOnlyList);
}
else if (items.TryGetNonEnumeratedCount(out var requiredAdditionalCapacity) && requiredAdditionalCapacity != 0)
{
InsertRangeWithKnownCount(list, index, items, list._count, requiredAdditionalCapacity);
}
else
{
InsertRangeEnumerated(list, index, items, growByCount);
}
}
}
}
@@ -1,214 +0,0 @@
using System.Collections.ObjectModel;
using System.Numerics;
using Recyclable.Collections.Pools;
namespace Recyclable.Collections
{
[Obsolete("It'll be moved to Recyclable.Collections.Compatibility.List NuGet package in the next release.")]
public static class zRecyclableListCompatibilityList
{
public static ReadOnlyCollection<T> AsReadOnly<T>(this RecyclableList<T> list) => new(list);
public static int BinarySearch<T>(this RecyclableList<T> list, T item)
=> Array.BinarySearch(list._memoryBlock, 0, list._count, item);
public static int BinarySearch<T>(this RecyclableList<T> list, T item, IComparer<T>? comparer)
=> Array.BinarySearch(list._memoryBlock, 0, list._count, item, comparer);
public static int BinarySearch<T>(this RecyclableList<T> list, int index, int count, T item, IComparer<T>? comparer)
=> Array.BinarySearch(list._memoryBlock, index, count, item, comparer);
public static RecyclableList<TOutput> ConvertAll<T, TOutput>(this RecyclableList<T> list, Converter<T, TOutput> converter)
{
int itemsCount = list._count;
if (itemsCount == 0)
{
return new();
}
RecyclableList<TOutput> result = new(itemsCount);
TOutput[] resultSpan = result._memoryBlock;
ReadOnlySpan<T> sourceSpan = list._memoryBlock;
for (int bufferIndex = 0; bufferIndex < itemsCount; bufferIndex++)
{
resultSpan[bufferIndex] = converter(sourceSpan[bufferIndex]);
}
result._count = itemsCount;
return result;
}
public static void CopyTo<T>(this RecyclableList<T> list, T[] array) => Array.Copy(list._memoryBlock, array, list._count);
public static void CopyTo<T>(this RecyclableList<T> list, int index, T[] array, int arrayIndex, int count) => Array.Copy(list._memoryBlock, index, array, arrayIndex, count);
public static void ForEach<T>(this RecyclableList<T> list, Action<T> action)
{
int sourceItemsCount = list._count;
if (sourceItemsCount == 0)
{
return;
}
ReadOnlySpan<T> sourceSpan = list._memoryBlock;
for (var itemIndex = 0; itemIndex < sourceItemsCount; itemIndex++)
{
action(sourceSpan[itemIndex]);
}
}
public static RecyclableList<T> GetRange<T>(this RecyclableList<T> list, int index, int count)
{
int sourceItemsCount = index + count <= list._count ? count : list._count - index;
if (sourceItemsCount <= 0)
{
return new();
}
ReadOnlySpan<T> sourceSpan = list._memoryBlock;
RecyclableList<T> result = new(sourceItemsCount);
Span<T> targetSpan = result._memoryBlock;
int resultItemsCount = 0;
sourceItemsCount += index;
for (var itemIndex = index; itemIndex < sourceItemsCount; itemIndex++)
{
targetSpan[resultItemsCount++] = sourceSpan[itemIndex];
}
result._count = resultItemsCount;
return result;
}
public static int RemoveAll<T>(this RecyclableList<T> list, Predicate<T> match)
{
using var allIndexes = list.FindAllIndexes(match);
int foundItemsCount = allIndexes._count;
if (foundItemsCount == 0)
{
return foundItemsCount;
}
for (int removed = 0; removed < foundItemsCount; removed++)
{
var indexToRemove = allIndexes[removed] - removed;
Array.Copy(list._memoryBlock, indexToRemove + 1, list._memoryBlock, indexToRemove, list._count - indexToRemove - removed - 1);
}
if (RecyclableList<T>._needsClearing)
{
Array.Clear(list._memoryBlock, list._count - foundItemsCount, foundItemsCount);
}
list._count -= foundItemsCount;
list._version++;
return foundItemsCount;
}
public static void RemoveRange<T>(this RecyclableList<T> list, int index, int count)
{
int oldCount = list._count;
count = count - index + 1 <= oldCount ? count : oldCount - index + 1;
if (count == 0)
{
return;
}
if (index + count < oldCount)
{
Array.Copy(list._memoryBlock, index + count, list._memoryBlock, index, oldCount - count - index);
}
if (RecyclableList<T>._needsClearing)
{
Array.Clear(list._memoryBlock, oldCount - count, count);
}
list._count -= count;
list._version++;
}
public static void Reverse<T>(this RecyclableList<T> list)
{
Array.Reverse(list._memoryBlock, 0, list._count);
list._version++;
}
public static void Reverse<T>(this RecyclableList<T> list, int index, int count)
{
Array.Reverse(list._memoryBlock, index, count);
list._version++;
}
public static void Sort<T>(this RecyclableList<T> list)
{
Array.Sort(list._memoryBlock, 0, list._count);
list._version++;
}
public static void Sort<T>(this RecyclableList<T> list, Comparison<T> comparison)
{
Array.Sort(list._memoryBlock, 0, list._count, new ComparisonToComparerAdapter<T>(comparison));
list._version++;
}
public static void Sort<T>(this RecyclableList<T> list, IComparer<T>? comparer)
{
Array.Sort(list._memoryBlock, 0, list._count, comparer);
list._version++;
}
public static void Sort<T>(this RecyclableList<T> list, int index, int count, IComparer<T>? comparer)
{
Array.Sort(list._memoryBlock, index, count, comparer);
list._version++;
}
public static T[] ToArray<T>(this RecyclableList<T> list)
{
T[] result = new T[list._count];
new ReadOnlySpan<T>(list._memoryBlock, 0, list._count).CopyTo(result);
return result;
}
public static void TrimExcess<T>(this RecyclableList<T> list)
{
var requiredCapacity = list._count >= RecyclableDefaults.InitialCapacity ? list._count : RecyclableDefaults.InitialCapacity;
T[] oldMemoryBlock = list._memoryBlock;
T[] result = requiredCapacity >= RecyclableDefaults.MinPooledArrayLength && BitOperations.IsPow2(requiredCapacity)
? RecyclableArrayPool<T>.RentShared(requiredCapacity)
: new T[requiredCapacity];
new ReadOnlySpan<T>(oldMemoryBlock, 0, list._count).CopyTo(result);
if (oldMemoryBlock.Length >= RecyclableDefaults.MinPooledArrayLength)
{
RecyclableArrayPool<T>.ReturnShared(oldMemoryBlock, RecyclableList<T>._needsClearing);
}
list._memoryBlock = result;
list._capacity = requiredCapacity;
}
public static bool TrueForAll<T>(this RecyclableList<T> list, Predicate<T> match)
{
int sourceItemsCount = list._count;
if (sourceItemsCount == 0)
{
return false;
}
ReadOnlySpan<T> sourceSpan = list._memoryBlock;
for (var itemIndex = 0; itemIndex < sourceItemsCount; itemIndex++)
{
if (!match(sourceSpan[itemIndex]))
{
return false;
}
}
return true;
}
}
}
@@ -1,33 +0,0 @@
using System.Collections;
namespace Recyclable.CollectionsTests
{
public class CustomIList<T> : IList<T>
{
protected List<T> _list;
public CustomIList()
{
_list = new List<T>();
}
public CustomIList(IEnumerable<T> items)
{
_list = new List<T>(items);
}
public T this[int index] { get => _list[index]; set => _list[index] = value; }
public int Count => _list.Count;
public bool IsReadOnly => false;
public void Add(T item) => _list.Add(item);
public void Clear() => _list.Clear();
public bool Contains(T item) => _list.Contains(item);
public void CopyTo(T[] array, int arrayIndex) => _list.CopyTo(0, array, arrayIndex, _list.Count);
public IEnumerator<T> GetEnumerator() => _list.GetEnumerator();
public int IndexOf(T item) => _list.IndexOf(item);
public void Insert(int index, T item) => _list.Insert(index, item);
public bool Remove(T item) => _list.Remove(item);
public void RemoveAt(int index) => _list.RemoveAt(index);
IEnumerator IEnumerable.GetEnumerator() => _list.GetEnumerator();
}
}
@@ -1,17 +0,0 @@
using System.Collections;
namespace Recyclable.CollectionsTests
{
public class EnumerableWithoutCount<T> : IEnumerable<T>
{
private readonly IEnumerable<T> _testData;
public EnumerableWithoutCount(IEnumerable<T> testData)
{
_testData = testData;
}
public IEnumerator<T> GetEnumerator() => _testData.GetEnumerator();
IEnumerator IEnumerable.GetEnumerator() => _testData.GetEnumerator();
}
}
@@ -9,20 +9,19 @@
</PropertyGroup>
<ItemGroup>
<PackageReference Include="FluentAssertions" Version="6.11.0" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.6.2" />
<PackageReference Include="morelinq" Version="3.4.2" />
<PackageReference Include="FluentAssertions" Version="6.12.0" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.7.2" />
<PackageReference Include="coverlet.collector" Version="6.0.0">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="Open.Numeric.Primes" Version="3.0.0" />
<PackageReference Include="xunit" Version="2.4.2" />
<PackageReference Include="xunit.runner.console" Version="2.5.0">
<PackageReference Include="Recyclable.Collections.TestData" Version="0.0.2" />
<PackageReference Include="xunit" Version="2.5.3" />
<PackageReference Include="xunit.runner.console" Version="2.5.3">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.5">
<PackageReference Include="xunit.runner.visualstudio" Version="2.5.3">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
File diff suppressed because it is too large. Load diff
@@ -1,282 +0,0 @@
using MoreLinq;
using Open.Numeric.Primes;
using Recyclable.Collections;
using System.Numerics;
namespace Recyclable.CollectionsTests
{
public static class RecyclableLongListTestData
{
private static readonly object[] _sourceRefData = Enumerable.Range(1, 100).Cast<object>().ToArray();
public static object[] SourceRefData => _sourceRefData;
public static IEnumerable<long> CreateTestData(long itemsCount)
{
for (long index = 1; index <= itemsCount; index++)
{
yield return index;
}
}
public static IEnumerable<object> CreateRefTestData(long itemsCount)
{
for (long index = 1; index <= itemsCount; index++)
{
yield return index;
}
}
public static readonly IEnumerable<long> ItemsCountVariants = new long[]
{
//RecyclableDefaults.MinPooledArrayLength - 5, RecyclableDefaults.MinPooledArrayLength - 1, RecyclableDefaults.MinPooledArrayLength, RecyclableDefaults.MinPooledArrayLength + 1, RecyclableDefaults.MinPooledArrayLength + 5, 127, 128, 129, RecyclableDefaults.MinItemsCountForParallelization
0, 1, 2, 3, 7, 10, 16, RecyclableDefaults.MinPooledArrayLength - 5, RecyclableDefaults.MinPooledArrayLength - 1, RecyclableDefaults.MinPooledArrayLength, RecyclableDefaults.MinPooledArrayLength + 1, RecyclableDefaults.MinPooledArrayLength + 5, RecyclableDefaults.MinPooledArrayLength * 100
};
public static readonly IEnumerable<object[]> ItemsCountTestCases = ItemsCountVariants.Select(x => new object[] { (int)x });
public static readonly IEnumerable<int> BlockSizeVariants = new int[]
{
1, 2, 4, 16, RecyclableDefaults.MinPooledArrayLength - 5, (int)BitOperations.RoundUpToPowerOf2(RecyclableDefaults.MinPooledArrayLength)
};
private static bool IsValidBlockSize(long itemsCount, long blockSize) => itemsCount is < 1024 || blockSize is > 8;
private static IEnumerable<object[]> GetTargetDataVariants()
{
foreach (var itemsCount in ItemsCountVariants)
{
foreach (var targetBlockSize in BlockSizeVariants)
{
if (!IsValidBlockSize(itemsCount, targetBlockSize))
{
continue;
}
yield return new object[] { itemsCount, targetBlockSize };
}
}
}
public static IEnumerable<object[]> TargetDataVariants => GetTargetDataVariants();
private static IEnumerable<object[]> CombineSourceDataWithBlockSize(IEnumerable<object[]> sourceData)
{
foreach (var testData in sourceData)
{
foreach (var targetBlockSize in BlockSizeVariants)
{
if (!IsValidBlockSize((long)testData[2], targetBlockSize))
{
continue;
}
yield return new object[] { testData[0], testData[1], testData[2], targetBlockSize };
}
}
}
private static IEnumerable<object[]> CreateSourceDataVariants(long itemsCount, bool refType)
{
GC.Collect(GC.MaxGeneration, GCCollectionMode.Forced, true, true);
switch (refType)
{
case false:
long[] testData = CreateTestData(itemsCount).ToArray();
yield return new object[] { $"Array[{itemsCount}]", testData, itemsCount };
yield return new object[] { $"ICollection[{itemsCount}]", testData, itemsCount };
yield return new object[] { $"ICollection<T>[{itemsCount}]", testData, itemsCount };
yield return new object[] { $"IEnumerable[{itemsCount}]", testData, itemsCount };
yield return new object[] { $"IEnumerable<T>[{itemsCount}] without non-enumerated count", new EnumerableWithoutCount<long>(testData), itemsCount };
yield return new object[] { $"IList<T>[{itemsCount}]", new CustomIList<long>(testData), itemsCount };
yield return new object[] { $"IReadOnlyList<T>[{itemsCount}])", testData, itemsCount };
yield return new object[] { $"List<T>[{itemsCount}]", testData.ToList(), itemsCount };
yield return new object[] { $"ReadOnlySpan<T>[{itemsCount}]", testData, itemsCount };
yield return new object[] { $"RecyclableList<T>[{itemsCount}]", testData.ToRecyclableList(), itemsCount };
foreach (var sourceBlockSize in BlockSizeVariants)
{
if (!IsValidBlockSize(itemsCount, sourceBlockSize))
{
continue;
}
yield return new object[]
{
$"RecyclableLongList<T>[itemsCount: {itemsCount}, minBlockSize: {sourceBlockSize}]",
testData.ToRecyclableLongList(sourceBlockSize),
itemsCount
};
}
yield return new object[] { $"Span<T>[{itemsCount}]", testData, itemsCount };
yield return new object[] { $"T[{itemsCount}]", testData, itemsCount };
break;
case true:
IEnumerable<object> testRefData = CreateRefTestData(itemsCount).ToArray();
yield return new object[] { $"Array[{itemsCount}]", testRefData, itemsCount };
yield return new object[] { $"ICollection(itemsCount: {itemsCount}", testRefData, itemsCount };
yield return new object[] { $"ICollection<T>(itemsCount: {itemsCount}", testRefData, itemsCount };
yield return new object[] { $"IEnumerable(itemsCount: {itemsCount})", testRefData, itemsCount };
yield return new object[] { $"IEnumerable<T>(itemsCount: {itemsCount}) without non-enumerated count", new EnumerableWithoutCount<object>(testRefData), itemsCount };
yield return new object[] { $"IList<T>(itemsCount: {itemsCount})", new CustomIList<object>(testRefData), itemsCount };
yield return new object[] { $"IReadOnlyList<T>(itemsCount: {itemsCount})", testRefData, itemsCount };
yield return new object[] { $"List<T>(itemsCount: {itemsCount}", testRefData.ToList(), itemsCount };
yield return new object[] { $"ReadOnlySpan<T>[{itemsCount}]", testRefData, itemsCount };
yield return new object[] { $"RecyclableList<T>(itemsCount: {itemsCount})", testRefData.ToRecyclableList(), itemsCount };
foreach (var sourceBlockSize in BlockSizeVariants)
{
if (!IsValidBlockSize(itemsCount, sourceBlockSize))
{
continue;
}
yield return new object[]
{
$"RecyclableLongList<T>(itemsCount: {itemsCount}, minBlockSize: {sourceBlockSize})",
testRefData.ToRecyclableLongList(sourceBlockSize),
itemsCount
};
}
yield return new object[] { $"Span<T>[{itemsCount}]", testRefData, itemsCount };
yield return new object[] { $"T[{itemsCount}]", testRefData, itemsCount };
break;
}
}
private static IEnumerable<object[]> CreateSourceDataVariants(bool refType)
{
foreach (var itemsCount in ItemsCountVariants)
{
foreach (var variant in CreateSourceDataVariants(itemsCount, refType))
{
yield return variant;
}
}
}
public static IEnumerable<object[]> EmptySourceDataVariants => CreateSourceDataVariants(0, false);
public static IEnumerable<object[]> SourceDataVariants => CreateSourceDataVariants(false);
public static IEnumerable<object[]> SourceDataWithItemIndexVariants
{
get
{
foreach (var testCase in CreateSourceDataVariants(false).Where(testCase => (long)testCase[2] > 0))
{
var itemIndexes = CreateItemIndexVariants((long)testCase[2], RecyclableDefaults.BlockSize).ToArray();
yield return new object[] { testCase[0], testCase[1], testCase[2], itemIndexes };
}
}
}
public static IEnumerable<object[]> SourceRefDataWithItemIndexVariants
{
get
{
IEnumerable<object[]> testCases = CreateSourceDataVariants(true).Where(testCase => (long)testCase[2] > 0);
foreach (var testCase in testCases)
{
var itemIndexes = CreateItemIndexVariants((long)testCase[2], RecyclableDefaults.BlockSize).ToArray();
yield return new object[] { testCase[0], testCase[1], testCase[2], itemIndexes };
}
}
}
public static IEnumerable<object[]> SourceDataWithBlockSizeVariants => CombineSourceDataWithBlockSize(SourceDataVariants);
public static IEnumerable<object[]> SourceRefDataVariants => CreateSourceDataVariants(true);
public static IEnumerable<object[]> SourceRefDataWithBlockSizeVariants { get; } = CombineSourceDataWithBlockSize(SourceRefDataVariants);
private static IEnumerable<long> _initialItemIndexVariants => new long[] { 0, 1, 2, 3, 4, 5 };
private static IEnumerable<long> CreateItemIndexVariants(long itemsCount, int blockSize)
{
IEnumerable<long> primes = _initialItemIndexVariants.Concat(
_initialItemIndexVariants.SelectMany(index => new long[] { blockSize - index, blockSize + index })
//new long[] { blockSize - 3, blockSize - 2, blockSize - 1, blockSize, blockSize + 1, blockSize + 2, blockSize + 3 }
).ToArray();
IEnumerable<long> second = Prime.Numbers.StartingAt(7)
.TakeUntil(prime =>
prime > ((blockSize * 2) - 1) ||
prime >= itemsCount
);
primes = primes.Concat(second).ToArray();
primes = primes.Concat(
primes.Select(index => itemsCount - index - 1)
)
.Where(index => itemsCount > 0 && index >= 0 && index < itemsCount).ToArray()
.Distinct().ToArray();
return primes;
//IEnumerable<long> CreateItemIndexVariants()
//{
//if (itemsCount > 0)
//{
// yield return 0;
//}
//foreach (long prime in primes)
//{
// yield return prime;
// long index = itemsCount - prime;
// if (index >= 0)
// {
// yield return index;
// }
//}
//for (long index = itemsCount - (blockSize * 2) - 1; index < itemsCount; index++)
//{
// if (index >= 0)
// {
// yield return index;
// }
//}
//if ((blockSize / 16 * 16) + 1 < itemsCount)
//{
// yield return (blockSize / 16 * 16) + 1;
//}
//}
//return CreateItemIndexVariants();
}
public static IEnumerable<object[]> CombineSourceRefDataWithBlockSizeWithItemIndex(bool refType)
{
IEnumerable<object[]> sourceData = refType switch
{
false => SourceDataWithBlockSizeVariants,
true => SourceRefDataWithBlockSizeVariants
};
foreach (var testCase in sourceData)
{
long itemsCount = (long)testCase[2];
if (itemsCount == 0)
{
continue;
}
long[] itemIndexes = CreateItemIndexVariants(itemsCount, (int)testCase[3])
.Where(_ => IsValidBlockSize((long)testCase[2], (int)testCase[3]))
.ToArray();
yield return new object[] { testCase[0], testCase[1], (long)testCase[2], (int)testCase[3], itemIndexes };
}
}
public static IEnumerable<object[]> SourceDataWithBlockSizeWithItemIndexVariants { get; } = CombineSourceRefDataWithBlockSizeWithItemIndex(false);
public static IEnumerable<object[]> SourceRefDataWithBlockSizeWithItemIndexVariants { get; } = CombineSourceRefDataWithBlockSizeWithItemIndex(true);
}
}
@@ -1,5 +1,6 @@
using FluentAssertions;
using Recyclable.Collections;
using Recyclable.Collections.TestData;
using Recyclable.Collections.Linq;
using System.Collections;
using System.Numerics;
BIN
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB