diff --git a/LICENSE.md b/LICENSE.md index b345ef8..0da7cad 100644 --- a/LICENSE.md +++ b/LICENSE.md @@ -3,7 +3,7 @@ The project & source code is free for educational & 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 diff --git a/Recyclable.Collections.Benchmarks/.gitattributes b/Recyclable.Collections.Benchmarks/.gitattributes new file mode 100644 index 0000000..1ff0c42 --- /dev/null +++ b/Recyclable.Collections.Benchmarks/.gitattributes @@ -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 diff --git a/Recyclable.Collections.Benchmarks/.gitignore b/Recyclable.Collections.Benchmarks/.gitignore new file mode 100644 index 0000000..da47c84 --- /dev/null +++ b/Recyclable.Collections.Benchmarks/.gitignore @@ -0,0 +1,6 @@ +################################################################################ +# This .gitignore file was automatically created by Microsoft(R) Visual Studio. +################################################################################ + +/bin +/obj diff --git a/Recyclable.Collections.Benchmarks/Benchmarks/BinarySearch_BestAndWorstCases.cs b/Recyclable.Collections.Benchmarks/Benchmarks/BinarySearch_BestAndWorstCases.cs deleted file mode 100644 index 3f5abd3..0000000 --- a/Recyclable.Collections.Benchmarks/Benchmarks/BinarySearch_BestAndWorstCases.cs +++ /dev/null @@ -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)])); - // } - // } - } -} diff --git a/Recyclable.Collections.Benchmarks/Benchmarks/Contains_FirstItems.cs b/Recyclable.Collections.Benchmarks/Benchmarks/Contains_FirstItems.cs index 07c1901..7ea92b7 100644 --- a/Recyclable.Collections.Benchmarks/Benchmarks/Contains_FirstItems.cs +++ b/Recyclable.Collections.Benchmarks/Benchmarks/Contains_FirstItems.cs @@ -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])); } } } diff --git a/Recyclable.Collections.Benchmarks/Benchmarks/Contains_LastItems.cs b/Recyclable.Collections.Benchmarks/Benchmarks/Contains_LastItems.cs index 30a5dfe..aac5aa9 100644 --- a/Recyclable.Collections.Benchmarks/Benchmarks/Contains_LastItems.cs +++ b/Recyclable.Collections.Benchmarks/Benchmarks/Contains_LastItems.cs @@ -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)])); } } } diff --git a/Recyclable.Collections.Benchmarks/Benchmarks/ConvertAll.cs b/Recyclable.Collections.Benchmarks/Benchmarks/ConvertAll.cs deleted file mode 100644 index 55ec249..0000000 --- a/Recyclable.Collections.Benchmarks/Benchmarks/ConvertAll.cs +++ /dev/null @@ -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 converted = list.ConvertAll(static (item) => (long)item); - DoNothing(converted); - } - - // public void RecyclableLongList_ConvertAll() - // { - // var data = TestObjects; - // var list = TestObjectsAsRecyclableLongList; - // var dataCount = TestObjectCountForSlowMethods; - // using RecyclableList converted = list.ConvertAll(static (item) => (long)item); - // DoNothing(converted); - // } - } -} diff --git a/Recyclable.Collections.Benchmarks/Benchmarks/Count.cs b/Recyclable.Collections.Benchmarks/Benchmarks/Count.cs index 7c30a64..3567a66 100644 --- a/Recyclable.Collections.Benchmarks/Benchmarks/Count.cs +++ b/Recyclable.Collections.Benchmarks/Benchmarks/Count.cs @@ -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); } } } diff --git a/Recyclable.Collections.Benchmarks/Benchmarks/Create.cs b/Recyclable.Collections.Benchmarks/Benchmarks/Create.cs index d10adf0..f4c69bc 100644 --- a/Recyclable.Collections.Benchmarks/Benchmarks/Create.cs +++ b/Recyclable.Collections.Benchmarks/Benchmarks/Create.cs @@ -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(); - DoNothing(list); + DoNothing.With(list); } public void PooledList_Create() { using var list = new PooledList(ClearMode.Auto); - DoNothing(list); + DoNothing.With(list); } public void RecyclableList_Create() { using var list = new RecyclableList(); - DoNothing(list); + DoNothing.With(list); } public void RecyclableLongList_Create() { using var list = new RecyclableLongList(); - DoNothing(list); + DoNothing.With(list); } } } diff --git a/Recyclable.Collections.Benchmarks/Benchmarks/Create_WithCapacity.cs b/Recyclable.Collections.Benchmarks/Benchmarks/Create_WithCapacity.cs index cb5b584..8994574 100644 --- a/Recyclable.Collections.Benchmarks/Benchmarks/Create_WithCapacity.cs +++ b/Recyclable.Collections.Benchmarks/Benchmarks/Create_WithCapacity.cs @@ -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(TestObjectCount); - DoNothing(list); + DoNothing.With(list); } public void PooledList_Create_WithCapacity() { using var list = new PooledList(capacity: TestObjectCount, ClearMode.Auto); - DoNothing(list); + DoNothing.With(list); } public void RecyclableList_Create_WithCapacity() { using var list = new RecyclableList(TestObjectCount); - DoNothing(list); + DoNothing.With(list); } public void RecyclableLongList_Create_WithCapacity() { using var list = new RecyclableLongList(minBlockSize: BlockSize, initialCapacity: TestObjectCount); - DoNothing(list); + DoNothing.With(list); } } } diff --git a/Recyclable.Collections.Benchmarks/Benchmarks/Exists_BestAndWorstCases.cs b/Recyclable.Collections.Benchmarks/Benchmarks/Exists_BestAndWorstCases.cs deleted file mode 100644 index f2d7b3f..0000000 --- a/Recyclable.Collections.Benchmarks/Benchmarks/Exists_BestAndWorstCases.cs +++ /dev/null @@ -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)])); - // } - // } - } -} diff --git a/Recyclable.Collections.Benchmarks/Benchmarks/FindAll_BestAndWorstCases.cs b/Recyclable.Collections.Benchmarks/Benchmarks/FindAll_BestAndWorstCases.cs deleted file mode 100644 index fb4443c..0000000 --- a/Recyclable.Collections.Benchmarks/Benchmarks/FindAll_BestAndWorstCases.cs +++ /dev/null @@ -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(); - // } - // } - } -} diff --git a/Recyclable.Collections.Benchmarks/Benchmarks/FindLastIndex_BestAndWorstCases.cs b/Recyclable.Collections.Benchmarks/Benchmarks/FindLastIndex_BestAndWorstCases.cs deleted file mode 100644 index b7338e1..0000000 --- a/Recyclable.Collections.Benchmarks/Benchmarks/FindLastIndex_BestAndWorstCases.cs +++ /dev/null @@ -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)])); - // } - // } - } -} diff --git a/Recyclable.Collections.Benchmarks/Benchmarks/FindLast_BestAndWorstCases.cs b/Recyclable.Collections.Benchmarks/Benchmarks/FindLast_BestAndWorstCases.cs deleted file mode 100644 index ef7ac79..0000000 --- a/Recyclable.Collections.Benchmarks/Benchmarks/FindLast_BestAndWorstCases.cs +++ /dev/null @@ -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)])); - // } - // } - } -} diff --git a/Recyclable.Collections.Benchmarks/Benchmarks/Find_BestAndWorstCases.cs b/Recyclable.Collections.Benchmarks/Benchmarks/Find_BestAndWorstCases.cs deleted file mode 100644 index 4f677da..0000000 --- a/Recyclable.Collections.Benchmarks/Benchmarks/Find_BestAndWorstCases.cs +++ /dev/null @@ -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)])); - // } - // } - } -} diff --git a/Recyclable.Collections.Benchmarks/Benchmarks/ForEach.cs b/Recyclable.Collections.Benchmarks/Benchmarks/ForEach.cs index b3df02a..2599620 100644 --- a/Recyclable.Collections.Benchmarks/Benchmarks/ForEach.cs +++ b/Recyclable.Collections.Benchmarks/Benchmarks/ForEach.cs @@ -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)TestObjectsAsRecyclableList) + foreach (var item in (IRecyclableVersionedList)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)TestObjectsAsRecyclableLongList) + foreach (var item in (IRecyclableVersionedLongList)TestObjectsAsRecyclableLongList) { - DoNothing(item); + DoNothing.With(item); } } } diff --git a/Recyclable.Collections.Benchmarks/Benchmarks/GetItem..cs b/Recyclable.Collections.Benchmarks/Benchmarks/GetItem..cs index 4f03945..030897f 100644 --- a/Recyclable.Collections.Benchmarks/Benchmarks/GetItem..cs +++ b/Recyclable.Collections.Benchmarks/Benchmarks/GetItem..cs @@ -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(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(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++]); } } } diff --git a/Recyclable.Collections.Benchmarks/Benchmarks/IndexOf_BestAndWorstCases.cs b/Recyclable.Collections.Benchmarks/Benchmarks/IndexOf_BestAndWorstCases.cs index e1d182c..092d56e 100644 --- a/Recyclable.Collections.Benchmarks/Benchmarks/IndexOf_BestAndWorstCases.cs +++ b/Recyclable.Collections.Benchmarks/Benchmarks/IndexOf_BestAndWorstCases.cs @@ -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)])); } } } diff --git a/Recyclable.Collections.Benchmarks/Benchmarks/IndexOf_FirstItems.cs b/Recyclable.Collections.Benchmarks/Benchmarks/IndexOf_FirstItems.cs index f552702..e79089b 100644 --- a/Recyclable.Collections.Benchmarks/Benchmarks/IndexOf_FirstItems.cs +++ b/Recyclable.Collections.Benchmarks/Benchmarks/IndexOf_FirstItems.cs @@ -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])); } } } diff --git a/Recyclable.Collections.Benchmarks/Benchmarks/IndexOf_LastItems.cs b/Recyclable.Collections.Benchmarks/Benchmarks/IndexOf_LastItems.cs index 1b7681f..4034e11 100644 --- a/Recyclable.Collections.Benchmarks/Benchmarks/IndexOf_LastItems.cs +++ b/Recyclable.Collections.Benchmarks/Benchmarks/IndexOf_LastItems.cs @@ -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)])); } } } diff --git a/Recyclable.Collections.Benchmarks/Benchmarks/LongCount.cs b/Recyclable.Collections.Benchmarks/Benchmarks/LongCount.cs index 9640ecd..90ba5de 100644 --- a/Recyclable.Collections.Benchmarks/Benchmarks/LongCount.cs +++ b/Recyclable.Collections.Benchmarks/Benchmarks/LongCount.cs @@ -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); } } } diff --git a/Recyclable.Collections.Benchmarks/Benchmarks/RecyclableCollections.Benchmarks.cs b/Recyclable.Collections.Benchmarks/Benchmarks/RecyclableCollections.Benchmarks.cs index 55f0b46..2397c26 100644 --- a/Recyclable.Collections.Benchmarks/Benchmarks/RecyclableCollections.Benchmarks.cs +++ b/Recyclable.Collections.Benchmarks/Benchmarks/RecyclableCollections.Benchmarks.cs @@ -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 { - 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 - { 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; } } diff --git a/Recyclable.Collections.Benchmarks/Benchmarks/Remove_FirstItems.cs b/Recyclable.Collections.Benchmarks/Benchmarks/Remove_FirstItems.cs index 1640951..5637a05 100644 --- a/Recyclable.Collections.Benchmarks/Benchmarks/Remove_FirstItems.cs +++ b/Recyclable.Collections.Benchmarks/Benchmarks/Remove_FirstItems.cs @@ -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])); } } } diff --git a/Recyclable.Collections.Benchmarks/Benchmarks/Remove_LastItems.cs b/Recyclable.Collections.Benchmarks/Benchmarks/Remove_LastItems.cs index d971c7a..ec05cab 100644 --- a/Recyclable.Collections.Benchmarks/Benchmarks/Remove_LastItems.cs +++ b/Recyclable.Collections.Benchmarks/Benchmarks/Remove_LastItems.cs @@ -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])); } } } diff --git a/Recyclable.Collections.Benchmarks/Core/DataGenerator.cs b/Recyclable.Collections.Benchmarks/Core/DataGenerator.cs deleted file mode 100644 index faaaf4e..0000000 --- a/Recyclable.Collections.Benchmarks/Core/DataGenerator.cs +++ /dev/null @@ -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 resultSpan = result; - for (int i = 0; i < testObjectCount; i++) - { - resultSpan[i] = i; - } - - return result; - } - } -} \ No newline at end of file diff --git a/Recyclable.Collections.Benchmarks/POC/ArraySizeLimitPoc.Benchmarks.cs b/Recyclable.Collections.Benchmarks/POC/ArraySizeLimitBenchmarks.cs similarity index 82% rename from Recyclable.Collections.Benchmarks/POC/ArraySizeLimitPoc.Benchmarks.cs rename to Recyclable.Collections.Benchmarks/POC/ArraySizeLimitBenchmarks.cs index e46231a..29b5532 100644 --- a/Recyclable.Collections.Benchmarks/POC/ArraySizeLimitPoc.Benchmarks.cs +++ b/Recyclable.Collections.Benchmarks/POC/ArraySizeLimitBenchmarks.cs @@ -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 + public class ArraySizeLimitBenchmarks : BaselineVsActualBenchmarkBase { 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.Shared.Rent(TestObjectCount); - DoNothing(arr); + DoNothing.With(arr); } [Benchmark(OperationsPerInvoke = 1)] diff --git a/Recyclable.Collections.Benchmarks/POC/BoolOrCompareBenchmarks.cs b/Recyclable.Collections.Benchmarks/POC/BoolOrCompareBenchmarks.cs new file mode 100644 index 0000000..59441ec --- /dev/null +++ b/Recyclable.Collections.Benchmarks/POC/BoolOrCompareBenchmarks.cs @@ -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 + { + [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), + }; + } +} \ No newline at end of file diff --git a/Recyclable.Collections.Benchmarks/POC/BoolOrComparePoc.Benchmarks.cs b/Recyclable.Collections.Benchmarks/POC/BoolOrComparePoc.Benchmarks.cs deleted file mode 100644 index 755b2a0..0000000 --- a/Recyclable.Collections.Benchmarks/POC/BoolOrComparePoc.Benchmarks.cs +++ /dev/null @@ -1,63 +0,0 @@ -using BenchmarkDotNet.Attributes; - -namespace Recyclable.Collections.Benchmarks.POC -{ - public enum BoolOrComparePocBenchmarkType - { - Bool, - Compare, - } - - [MemoryDiagnoser] - public class BoolOrComparePocBenchmarks : PocBenchmarkBase - { - [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), - }; - } -} \ No newline at end of file diff --git a/Recyclable.Collections.Benchmarks/POC/DelegateVsComparerBenchmarks.cs b/Recyclable.Collections.Benchmarks/POC/DelegateVsComparerBenchmarks.cs new file mode 100644 index 0000000..2e14bb3 --- /dev/null +++ b/Recyclable.Collections.Benchmarks/POC/DelegateVsComparerBenchmarks.cs @@ -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 + { + [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 x, T y); + + public readonly struct MyComparerReadOnlyStruct : IComparer + { + public int Compare(T? x, T? y) => Comparer.Default.Compare(x, y); + } + + private struct MyComparerStruct : IComparer + { + public readonly int Compare(T? x, T? y) => Comparer.Default.Compare(x, y); + } + + private class MyComparer : IComparer + { + 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 _comparer = Comparer.Default; + private IEnumerable? _testObjects; + private IEnumerable>? _testListOfFunctions; + private IEnumerable>? _testListOfComparers; + private IEnumerable>? _testListOfDelegates; + private IEnumerable>? _testListOfLocalFunctions; + private IEnumerable? _testListOfClasses; + private IEnumerable>? _testListOfStructs; + private IEnumerable>? _testListOfBoxedStructs; + private IEnumerable TestListOfUnboxedStructs() where TComparer : IComparer, new() + { + foreach (var _ in _testObjects!) + { + yield return new TComparer(); + } + } + + private static IEnumerable> GetLocalFunctions(IEnumerable 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 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 compareFunc) + { + var testData = _testObjects!.ToArray(); + for (var itemIdx = 0; itemIdx < testData.Length - 1; itemIdx++) + { + _ = compareFunc(testData[itemIdx], testData[itemIdx + 1]); + } + } + + private void TestWithFunc(Func 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, 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, 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 benchmarkType) + { + switch (benchmarkType) + { + case DelegateVsComparerBenchmarkType.ListOfBoxedStructs: + _testListOfBoxedStructs = _testObjects!.Select(_ => (IComparer)new MyComparerStruct()); + break; + case DelegateVsComparerBenchmarkType.ListOfClasses: + _testListOfClasses = _testObjects!.Select(_ => new MyComparer()); + break; + case DelegateVsComparerBenchmarkType.ListOfComparers: + _testListOfComparers = _testObjects!.Select(_ => (IComparer)new MyComparer()); + break; + case DelegateVsComparerBenchmarkType.ListOfDelegates: + _testListOfDelegates = _testObjects!.Select(_ => new Compare((x, y) => new MyComparer().Compare(x, y))); + break; + case DelegateVsComparerBenchmarkType.ListOfFuncs: + _testListOfFunctions = _testObjects!.Select>(static _ => new MyComparer().Compare); + break; + case DelegateVsComparerBenchmarkType.ListOfLocalFuncs: + _testListOfLocalFunctions = GetLocalFunctions(_testObjects!); + break; + case DelegateVsComparerBenchmarkType.ListOfStructs: + _testListOfStructs = _testObjects!.Select(_ => new MyComparerStruct()); + break; + } + } + } +} diff --git a/Recyclable.Collections.Benchmarks/POC/DelegateVsComparerPoc.Benchmarks.cs b/Recyclable.Collections.Benchmarks/POC/DelegateVsComparerPoc.Benchmarks.cs deleted file mode 100644 index fea010f..0000000 --- a/Recyclable.Collections.Benchmarks/POC/DelegateVsComparerPoc.Benchmarks.cs +++ /dev/null @@ -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 - { - [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 x, T y); - - public readonly struct MyComparerReadOnlyStruct : IComparer - { - public int Compare(T? x, T? y) => Comparer.Default.Compare(x, y); - } - - private struct MyComparerStruct : IComparer - { - public readonly int Compare(T? x, T? y) => Comparer.Default.Compare(x, y); - } - - private class MyComparer : IComparer - { - 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 _comparer = Comparer.Default; - private IEnumerable? _testObjects; - private IEnumerable>? _testListOfFunctions; - private IEnumerable>? _testListOfComparers; - private IEnumerable>? _testListOfDelegates; - private IEnumerable>? _testListOfLocalFunctions; - private IEnumerable? _testListOfClasses; - private IEnumerable>? _testListOfStructs; - private IEnumerable>? _testListOfBoxedStructs; - private IEnumerable TestListOfUnboxedStructs() where TComparer : IComparer, new() - { - foreach (var _ in _testObjects!) - { - yield return new TComparer(); - } - } - - private static IEnumerable> GetLocalFunctions(IEnumerable 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 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 compareFunc) - { - var testData = _testObjects!.ToArray(); - for (var itemIdx = 0; itemIdx < testData.Length - 1; itemIdx++) - { - _ = compareFunc(testData[itemIdx], testData[itemIdx + 1]); - } - } - - private void TestWithFunc(Func 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, 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, 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 benchmarkType) - { - switch (benchmarkType) - { - case DelegateVsComparerPocBenchmarkType.ListOfBoxedStructs: - _testListOfBoxedStructs = _testObjects!.Select(_ => (IComparer)new MyComparerStruct()); - break; - case DelegateVsComparerPocBenchmarkType.ListOfClasses: - _testListOfClasses = _testObjects!.Select(_ => new MyComparer()); - break; - case DelegateVsComparerPocBenchmarkType.ListOfComparers: - _testListOfComparers = _testObjects!.Select(_ => (IComparer)new MyComparer()); - break; - case DelegateVsComparerPocBenchmarkType.ListOfDelegates: - _testListOfDelegates = _testObjects!.Select(_ => new Compare((x, y) => new MyComparer().Compare(x, y))); - break; - case DelegateVsComparerPocBenchmarkType.ListOfFuncs: - _testListOfFunctions = _testObjects!.Select>(static _ => new MyComparer().Compare); - break; - case DelegateVsComparerPocBenchmarkType.ListOfLocalFuncs: - _testListOfLocalFunctions = GetLocalFunctions(_testObjects!); - break; - case DelegateVsComparerPocBenchmarkType.ListOfStructs: - _testListOfStructs = _testObjects!.Select(_ => new MyComparerStruct()); - break; - } - } - } -} diff --git a/Recyclable.Collections.Benchmarks/POC/EqualVsContainsInConsecutiveOrderBenchmarks.cs b/Recyclable.Collections.Benchmarks/POC/EqualVsContainsInConsecutiveOrderBenchmarks.cs index aaeab5b..5bc3541 100644 --- a/Recyclable.Collections.Benchmarks/POC/EqualVsContainsInConsecutiveOrderBenchmarks.cs +++ b/Recyclable.Collections.Benchmarks/POC/EqualVsContainsInConsecutiveOrderBenchmarks.cs @@ -2,7 +2,7 @@ using BenchmarkDotNet.Attributes; using FluentAssertions; -using Recyclable.CollectionsTests; +using Recyclable.Collections.TestData; namespace Recyclable.Collections.Benchmarks.POC { diff --git a/Recyclable.Collections.Benchmarks/POC/GreaterOperatorVsNotEqualOperatorBenchmarks.cs b/Recyclable.Collections.Benchmarks/POC/GreaterOperatorVsNotEqualOperatorBenchmarks.cs new file mode 100644 index 0000000..2bf5241 --- /dev/null +++ b/Recyclable.Collections.Benchmarks/POC/GreaterOperatorVsNotEqualOperatorBenchmarks.cs @@ -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); + } + } +} diff --git a/Recyclable.Collections.Benchmarks/POC/GreaterOperatorvsDoesntEqualOperator.Benchmarks.cs b/Recyclable.Collections.Benchmarks/POC/GreaterOperatorvsDoesntEqualOperator.Benchmarks.cs deleted file mode 100644 index fbaac50..0000000 --- a/Recyclable.Collections.Benchmarks/POC/GreaterOperatorvsDoesntEqualOperator.Benchmarks.cs +++ /dev/null @@ -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 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); - } - } -} diff --git a/Recyclable.Collections.Benchmarks/POC/LessOperatorvsAndOperatorBenchmarks.cs b/Recyclable.Collections.Benchmarks/POC/LessOperatorvsAndOperatorBenchmarks.cs index 2f89dcb..b0ad3d7 100644 --- a/Recyclable.Collections.Benchmarks/POC/LessOperatorvsAndOperatorBenchmarks.cs +++ b/Recyclable.Collections.Benchmarks/POC/LessOperatorvsAndOperatorBenchmarks.cs @@ -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 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); } } } diff --git a/Recyclable.Collections.Benchmarks/POC/ModuloBenchmarks.cs b/Recyclable.Collections.Benchmarks/POC/ModuloBenchmarks.cs new file mode 100644 index 0000000..a2ee40e --- /dev/null +++ b/Recyclable.Collections.Benchmarks/POC/ModuloBenchmarks.cs @@ -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 _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(new[] { 0L, i, 0, 0 }); + var increment = new Vector(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 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); + } + } + } +} \ No newline at end of file diff --git a/Recyclable.Collections.Benchmarks/POC/ModuloPoc.Benchmarks.cs b/Recyclable.Collections.Benchmarks/POC/ModuloPoc.Benchmarks.cs deleted file mode 100644 index 7416e5d..0000000 --- a/Recyclable.Collections.Benchmarks/POC/ModuloPoc.Benchmarks.cs +++ /dev/null @@ -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 _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 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(new[] { 0L, i, 0, 0 }); - var increment = new Vector(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 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); - } - } - } -} \ No newline at end of file diff --git a/Recyclable.Collections.Benchmarks/POC/PocBenchmarkBase.cs b/Recyclable.Collections.Benchmarks/POC/PocBenchmarkBase.cs deleted file mode 100644 index 368112a..0000000 --- a/Recyclable.Collections.Benchmarks/POC/PocBenchmarkBase.cs +++ /dev/null @@ -1,142 +0,0 @@ -using BenchmarkDotNet.Attributes; -using System.Numerics; -using System.Runtime.CompilerServices; - -namespace Recyclable.Collections.Benchmarks.POC -{ - public abstract class PocBenchmarkBase - { - 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(in T item) - { - _ = item; - } - - protected static Exception CreateUnknownBenchmarkTypeException(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 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.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.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 *******"); - } - } -} diff --git a/Recyclable.Collections.Benchmarks/POC/RecyclableLongListPos.Benchmarks.IndexOf.txt b/Recyclable.Collections.Benchmarks/POC/RecyclableLongListBenchmarks.IndexOf.txt similarity index 100% rename from Recyclable.Collections.Benchmarks/POC/RecyclableLongListPos.Benchmarks.IndexOf.txt rename to Recyclable.Collections.Benchmarks/POC/RecyclableLongListBenchmarks.IndexOf.txt diff --git a/Recyclable.Collections.Benchmarks/RecyclableBenchmarkBase.cs b/Recyclable.Collections.Benchmarks/POC/RecyclableLongListBenchmarks.cs similarity index 53% rename from Recyclable.Collections.Benchmarks/RecyclableBenchmarkBase.cs rename to Recyclable.Collections.Benchmarks/POC/RecyclableLongListBenchmarks.cs index 3dbfcd2..5ef2929 100644 --- a/Recyclable.Collections.Benchmarks/RecyclableBenchmarkBase.cs +++ b/Recyclable.Collections.Benchmarks/POC/RecyclableLongListBenchmarks.cs @@ -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 : PocBenchmarkBase + public partial class RecyclableLongListBenchmarks : BaselineVsActualBenchmarkBase { - 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? _testObjectsAsList; - protected List TestObjectsAsList => _testObjectsAsList ?? throw new NullReferenceException("Something went wrong and the field is not initialized"); + public RecyclableLongList TestObjectsAsRecyclableLongList => _testRecyclableLongList ?? throw new NullReferenceException($"Something is wrong and {nameof(RecyclableLongList)} is null"); + private RecyclableLongList? _testRecyclableLongList; + private PooledList? _testPooledList; + internal PooledList TestPooledList => _testPooledList ?? throw new NullReferenceException($"Something is wrong and {nameof(PooledList)} is null"); - protected PooledList? _testObjectsAsPooledList; - public PooledList TestObjectsAsPooledList => _testObjectsAsPooledList ?? throw new NullReferenceException("Something is wrong and the field is not initialized"); - protected RecyclableList? _testObjectsAsRecyclableList; - protected RecyclableList TestObjectsAsRecyclableList => _testObjectsAsRecyclableList ?? throw new NullReferenceException("Something is wrong and the field is not initialized"); - protected RecyclableLongList? _testObjectsAsRecyclableLongList; - protected RecyclableLongList TestObjectsAsRecyclableLongList => _testObjectsAsRecyclableLongList ?? throw new NullReferenceException("Something is wrong and the field is not initialized"); - protected IEnumerable TestObjectsAsIEnumerable + private static readonly MethodInfo _ensureCapacityNewFunc; + + static RecyclableLongListBenchmarks() { - get - { - for (long i = 0; i < TestObjectCount; i++) - { - yield return i; - } - } + _ensureCapacityNewFunc = typeof(RecyclableLongList).GetMethod("EnsureCapacity", BindingFlags.Static | BindingFlags.NonPublic) + ?? throw new NullReferenceException($"Method EnsureCapacity not found in class {nameof(RecyclableLongList)}"); + } 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 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(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(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(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(initialCapacity: dataCount); + // var list = new PriorityQueue(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(BlockSize); + // var list = new RecyclableSortedList(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(BlockSize); + // var list = new RecyclableSortedList(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(); + // var list = new SortedList(); // for (var i = 0; i < dataCount; i++) // { // list.Add(i, data[i]); diff --git a/Recyclable.Collections.Benchmarks/POC/RecyclableLongListPoc.Benchmarks.cs b/Recyclable.Collections.Benchmarks/POC/RecyclableLongListPoc.Benchmarks.cs deleted file mode 100644 index b9dfec1..0000000 --- a/Recyclable.Collections.Benchmarks/POC/RecyclableLongListPoc.Benchmarks.cs +++ /dev/null @@ -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 : PocBenchmarkBase - { - private long[]? _testArray; - public long[] TestObjects => _testArray ?? throw new NullReferenceException("Something is wrong and test objects are null"); - - public RecyclableLongList TestObjectsAsRecyclableLongList => _testRecyclableLongList ?? throw new NullReferenceException($"Something is wrong and {nameof(RecyclableLongList)} is null"); - private RecyclableLongList? _testRecyclableLongList; - private PooledList? _testPooledList; - internal PooledList TestPooledList => _testPooledList ?? throw new NullReferenceException($"Something is wrong and {nameof(PooledList)} is null"); - - private static readonly MethodInfo _ensureCapacityNewFunc; - - static RecyclableLongListPocBenchmarks() - { - _ensureCapacityNewFunc = typeof(RecyclableLongList).GetMethod("EnsureCapacity", BindingFlags.Static | BindingFlags.NonPublic) - ?? throw new NullReferenceException($"Method EnsureCapacity not found in class {nameof(RecyclableLongList)}"); - - } - - 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(); - } - } -} diff --git a/Recyclable.Collections.Benchmarks/POC/RefVsInstanceMemberBenchmarks.cs b/Recyclable.Collections.Benchmarks/POC/RefVsInstanceMemberBenchmarks.cs new file mode 100644 index 0000000..fd3ca00 --- /dev/null +++ b/Recyclable.Collections.Benchmarks/POC/RefVsInstanceMemberBenchmarks.cs @@ -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); + } + } +} diff --git a/Recyclable.Collections.Benchmarks/POC/RefVsInstanceMemberPoc.Benchmarks.cs b/Recyclable.Collections.Benchmarks/POC/RefVsInstanceMemberPoc.Benchmarks.cs deleted file mode 100644 index 4219f49..0000000 --- a/Recyclable.Collections.Benchmarks/POC/RefVsInstanceMemberPoc.Benchmarks.cs +++ /dev/null @@ -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); - } - } -} diff --git a/Recyclable.Collections.Benchmarks/POC/RoundBenchmarks.cs b/Recyclable.Collections.Benchmarks/POC/RoundBenchmarks.cs index e1d133b..dd8f60e 100644 --- a/Recyclable.Collections.Benchmarks/POC/RoundBenchmarks.cs +++ b/Recyclable.Collections.Benchmarks/POC/RoundBenchmarks.cs @@ -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 + public class RoundBenchmarks : BaselineVsActualBenchmarkBase { [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 diff --git a/Recyclable.Collections.Benchmarks/POC/RoundUpToPowerOf2vsOthers.cs b/Recyclable.Collections.Benchmarks/POC/RoundUpToPowerOf2Alternatives.cs similarity index 75% rename from Recyclable.Collections.Benchmarks/POC/RoundUpToPowerOf2vsOthers.cs rename to Recyclable.Collections.Benchmarks/POC/RoundUpToPowerOf2Alternatives.cs index 96906d9..51325db 100644 --- a/Recyclable.Collections.Benchmarks/POC/RoundUpToPowerOf2vsOthers.cs +++ b/Recyclable.Collections.Benchmarks/POC/RoundUpToPowerOf2Alternatives.cs @@ -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 + public class RoundUpToPowerOf2vsOtherBenchmarks : BaselineVsActualBenchmarkBase { // [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 diff --git a/Recyclable.Collections.Benchmarks/POC/SpanConstructorVsTypecasting.Benchmarks.cs b/Recyclable.Collections.Benchmarks/POC/SpanConstructorVsTypecasting.Benchmarks.cs deleted file mode 100644 index bee88e7..0000000 --- a/Recyclable.Collections.Benchmarks/POC/SpanConstructorVsTypecasting.Benchmarks.cs +++ /dev/null @@ -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 - { - private int[]? TestData { get; set; } - - [MethodImpl(MethodImplOptions.NoOptimization | MethodImplOptions.NoInlining)] - private void DoNothing(ReadOnlySpan 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 span = new(TestData); - DoNothing(span); - } - - public void TypeCasting() - { - ReadOnlySpan 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), - }; - } -} \ No newline at end of file diff --git a/Recyclable.Collections.Benchmarks/POC/SpanConstructorVsTypecastingBenchmarks.cs b/Recyclable.Collections.Benchmarks/POC/SpanConstructorVsTypecastingBenchmarks.cs new file mode 100644 index 0000000..8d81157 --- /dev/null +++ b/Recyclable.Collections.Benchmarks/POC/SpanConstructorVsTypecastingBenchmarks.cs @@ -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 + { + 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 span = new(TestData); + DoNothing.With(span); + } + + public void TypeCasting() + { + ReadOnlySpan 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), + }; + } +} \ No newline at end of file diff --git a/Recyclable.Collections.Benchmarks/POC/SpanVsArrayBenchmarks.cs b/Recyclable.Collections.Benchmarks/POC/SpanVsArrayBenchmarks.cs index 944d396..f8dbdfb 100644 --- a/Recyclable.Collections.Benchmarks/POC/SpanVsArrayBenchmarks.cs +++ b/Recyclable.Collections.Benchmarks/POC/SpanVsArrayBenchmarks.cs @@ -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 + public class SpanVsArrayBenchmarks : DataDrivenBenchmarksBase { // [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 data = new(_testObjects, 0, dataCount); for (int i = 0; i < dataCount; i++) { - DoNothing(data[i]); + DoNothing.With(data[i]); } } diff --git a/Recyclable.Collections.Benchmarks/Program.cs b/Recyclable.Collections.Benchmarks/Program.cs index a754215..ea7a441 100644 --- a/Recyclable.Collections.Benchmarks/Program.cs +++ b/Recyclable.Collections.Benchmarks/Program.cs @@ -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(BenchmarkConfig); - _ = BenchmarkRunner.Run(BenchmarkConfig); - _ = BenchmarkRunner.Run(BenchmarkConfig); - _ = BenchmarkRunner.Run(BenchmarkConfig); - _ = BenchmarkRunner.Run(BenchmarkConfig); - _ = BenchmarkRunner.Run(BenchmarkConfig); - _ = BenchmarkRunner.Run(BenchmarkConfig); - _ = BenchmarkRunner.Run(BenchmarkConfig); - _ = BenchmarkRunner.Run(BenchmarkConfig); - _ = BenchmarkRunner.Run(BenchmarkConfig); - _ = BenchmarkRunner.Run(BenchmarkConfig); - _ = BenchmarkRunner.Run(BenchmarkConfig); + //_ = BenchmarkRunner.Run(BenchmarkConfig); + //_ = BenchmarkRunner.Run(BenchmarkConfig); + //_ = BenchmarkRunner.Run(BenchmarkConfig); + //_ = BenchmarkRunner.Run(BenchmarkConfig); + //_ = BenchmarkRunner.Run(BenchmarkConfig); + //_ = BenchmarkRunner.Run(BenchmarkConfig); + //_ = BenchmarkRunner.Run(BenchmarkConfig); + //_ = BenchmarkRunner.Run(BenchmarkConfig); + //_ = BenchmarkRunner.Run(BenchmarkConfig); + //_ = BenchmarkRunner.Run(BenchmarkConfig); + //_ = BenchmarkRunner.Run(BenchmarkConfig); + //_ = BenchmarkRunner.Run(BenchmarkConfig); //ArraySizeLimitBenchmarks.Run(); } static void Main() { - RunRecyclableCollectionsBenchmarks(); - // RunPocBenchmarks(); + // RunRecyclableCollectionsBenchmarks(); + RunPocBenchmarks(); // RunSelectedBenchmarks(); // RunAssemblyBenchmarks(); } diff --git a/Recyclable.Collections.Benchmarks/Recyclable.Collections.Benchmarks.csproj b/Recyclable.Collections.Benchmarks/Recyclable.Collections.Benchmarks.csproj index 1bd552a..ae4917a 100644 --- a/Recyclable.Collections.Benchmarks/Recyclable.Collections.Benchmarks.csproj +++ b/Recyclable.Collections.Benchmarks/Recyclable.Collections.Benchmarks.csproj @@ -10,7 +10,7 @@ - + diff --git a/Recyclable.Collections/Recyclable.Collections.csproj b/Recyclable.Collections/Recyclable.Collections.csproj index 3decd82..f6ba18c 100644 --- a/Recyclable.Collections/Recyclable.Collections.csproj +++ b/Recyclable.Collections/Recyclable.Collections.csproj @@ -5,7 +5,7 @@ enable true Recyclable.Collections - 0.0.6 + 0.0.6.1 Marek Lemańczyk N/A Recyclable.Collections @@ -17,11 +17,14 @@ LICENSE.md README.md git - List<T> compatibility pack added for RecyclableList<T>. Various performance improvements and fixes. + List<T> compatibility code moved to Recyclable.Collections.Compatibility.List package. Cleanup. AnyCPU;x64 + + PreserveNewest + Always @@ -31,7 +34,6 @@ - - + diff --git a/Recyclable.Collections/RecyclableList.Compatibility.List.Find.cs b/Recyclable.Collections/RecyclableList.Compatibility.List.Find.cs deleted file mode 100644 index 00871d0..0000000 --- a/Recyclable.Collections/RecyclableList.Compatibility.List.Find.cs +++ /dev/null @@ -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(this RecyclableList list, Predicate match) - { - int sourceItemsCount = list._count; - if (sourceItemsCount == 0) - { - return false; - } - - ReadOnlySpan sourceSpan = list._memoryBlock; - for (var itemIndex = 0; itemIndex < sourceItemsCount; itemIndex++) - { - if (match(sourceSpan[itemIndex])) - { - return true; - } - } - - return false; - } - - public static T? Find(this RecyclableList list, Predicate match) - { - int sourceItemsCount = list._count; - if (sourceItemsCount == 0) - { - return default; - } - - ReadOnlySpan sourceSpan = list._memoryBlock; - for (var itemIndex = 0; itemIndex < sourceItemsCount; itemIndex++) - { - if (match(sourceSpan[itemIndex])) - { - return sourceSpan[itemIndex]; - } - } - - return default; - } - - public static RecyclableList FindAll(this RecyclableList list, Predicate match) - { - int sourceItemsCount = list._count; - if (sourceItemsCount == 0) - { - return new(); - } - - ReadOnlySpan sourceSpan = list._memoryBlock; - RecyclableList result = new(sourceItemsCount >> 3); - Span 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.EnsureCapacity(result, resultItemsCount, capacity); - resultSpan = result._memoryBlock; - } - - resultSpan[resultItemsCount++] = sourceSpan[itemIndex]; - } - } - - result._capacity = capacity; - result._count = resultItemsCount; - return result; - } - public static RecyclableList FindAllIndexes(this RecyclableList list, Predicate match) - { - int sourceItemsCount = list._count; - if (sourceItemsCount == 0) - { - return new(); - } - - ReadOnlySpan sourceSpan = list._memoryBlock; - RecyclableList result = new(sourceItemsCount >> 3); - Span 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.EnsureCapacity(result, resultItemsCount, capacity); - resultSpan = result._memoryBlock; - } - - resultSpan[resultItemsCount++] = itemIndex; - } - } - - result._capacity = capacity; - result._count = resultItemsCount; - return result; - } - - public static int FindIndex(this RecyclableList list, int startIndex, int count, Predicate match) - { - int sourceItemsCount = list._count; - if (sourceItemsCount == 0 || startIndex >= sourceItemsCount) - { - return RecyclableDefaults.ItemNotFoundIndex; - } - - sourceItemsCount = Math.Min(sourceItemsCount, startIndex + sourceItemsCount); - ReadOnlySpan sourceSpan = list._memoryBlock; - for (var itemIndex = startIndex; itemIndex < sourceItemsCount; itemIndex++) - { - if (match(sourceSpan[itemIndex])) - { - return itemIndex; - } - } - - return RecyclableDefaults.ItemNotFoundIndex; - } - - public static int FindIndex(this RecyclableList list, int startIndex, Predicate match) - { - int sourceItemsCount = list._count; - if (sourceItemsCount == 0 || startIndex >= sourceItemsCount) - { - return RecyclableDefaults.ItemNotFoundIndex; - } - - sourceItemsCount = Math.Min(sourceItemsCount, startIndex + sourceItemsCount); - ReadOnlySpan sourceSpan = list._memoryBlock; - for (var itemIndex = startIndex; itemIndex < sourceItemsCount; itemIndex++) - { - if (match(sourceSpan[itemIndex])) - { - return itemIndex; - } - } - - return RecyclableDefaults.ItemNotFoundIndex; - } - - public static int FindIndex(this RecyclableList list, Predicate match) - { - int sourceItemsCount = list._count; - if (sourceItemsCount == 0) - { - return RecyclableDefaults.ItemNotFoundIndex; - } - - ReadOnlySpan sourceSpan = list._memoryBlock; - for (var itemIndex = 0; itemIndex < sourceItemsCount; itemIndex++) - { - if (match(sourceSpan[itemIndex])) - { - return itemIndex; - } - } - - return RecyclableDefaults.ItemNotFoundIndex; - } - - public static T? FindLast(this RecyclableList list, Predicate match) - { - if (list._count == 0) - { - return default; - } - - ReadOnlySpan 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(this RecyclableList list, int startIndex, int count, Predicate 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 sourceSpan = list._memoryBlock; - for (var itemIndex = startIndex; itemIndex > lastItemIndex; itemIndex--) - { - if (match(sourceSpan[itemIndex])) - { - return itemIndex; - } - } - - return RecyclableDefaults.ItemNotFoundIndex; - } - - public static int FindLastIndex(this RecyclableList list, int startIndex, Predicate match) - { - if (list._count == 0 || startIndex < 0) - { - return RecyclableDefaults.ItemNotFoundIndex; - } - - ReadOnlySpan sourceSpan = list._memoryBlock; - for (var itemIndex = startIndex; itemIndex >= 0; itemIndex--) - { - if (match(sourceSpan[itemIndex])) - { - return itemIndex; - } - } - - return RecyclableDefaults.ItemNotFoundIndex; - } - - public static int FindLastIndex(this RecyclableList list, Predicate match) - { - if (list._count == 0) - { - return RecyclableDefaults.ItemNotFoundIndex; - } - - ReadOnlySpan sourceSpan = list._memoryBlock; - for (var itemIndex = list._count - 1; itemIndex >= 0; itemIndex--) - { - if (match(sourceSpan[itemIndex])) - { - return itemIndex; - } - } - - return RecyclableDefaults.ItemNotFoundIndex; - } - } -} diff --git a/Recyclable.Collections/RecyclableList.Compatibility.List.IndexOf.cs b/Recyclable.Collections/RecyclableList.Compatibility.List.IndexOf.cs deleted file mode 100644 index 09aa8d4..0000000 --- a/Recyclable.Collections/RecyclableList.Compatibility.List.IndexOf.cs +++ /dev/null @@ -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(this RecyclableList list, T item, int index) => list._count != 0 - ? Array.IndexOf(list._memoryBlock, item, index, list._count - index) - : RecyclableDefaults.ItemNotFoundIndex; - - public static int IndexOf(this RecyclableList list, T item, int index, int count) => list._count != 0 - ? Array.IndexOf(list._memoryBlock, item, index, count) - : RecyclableDefaults.ItemNotFoundIndex; - - public static int LastIndexOf(this RecyclableList list, T item) => list._count != 0 - ? Array.LastIndexOf(list._memoryBlock, item, list._count - 1) - : RecyclableDefaults.ItemNotFoundIndex; - - public static int LastIndexOf(this RecyclableList list, T item, int index) => list._count != 0 - ? Array.LastIndexOf(list._memoryBlock, item, index) - : RecyclableDefaults.ItemNotFoundIndex; - - public static int LastIndexOf(this RecyclableList list, T item, int index, int count) => list._count != 0 - ? Array.LastIndexOf(list._memoryBlock, item, index, count) - : RecyclableDefaults.ItemNotFoundIndex; - } -} diff --git a/Recyclable.Collections/RecyclableList.Compatibility.List.InsertRange.cs b/Recyclable.Collections/RecyclableList.Compatibility.List.InsertRange.cs deleted file mode 100644 index 27a1107..0000000 --- a/Recyclable.Collections/RecyclableList.Compatibility.List.InsertRange.cs +++ /dev/null @@ -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(this RecyclableList list, int index, IEnumerable 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 memorySpan = memoryBlock; - do - { - if (index + available + movingBlockLength > capacity) - { - var capacityBeforeIncrease = capacity; - capacity = checked((int)BitOperations.RoundUpToPowerOf2((uint)(capacity + growByCount))); - _ = RecyclableListHelpers.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._needsClearing) - { - Array.Clear(memoryBlock, capacity - movingBlockLength, movingBlockLength); - } - } - - list._count += added; - list._capacity = capacity; - } - - private static void InsertRangeWithKnownCount(this RecyclableList list, int index, IEnumerable items, int currentItemsCount, int requiredAdditionalCapacity) - { - list._capacity = RecyclableListHelpers.EnsureCapacity(list, currentItemsCount, checked((int)BitOperations.RoundUpToPowerOf2((uint)(currentItemsCount + requiredAdditionalCapacity)))); - - Array.Copy(list._memoryBlock, index, list._memoryBlock, index + requiredAdditionalCapacity, list._count - index); - Span 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(this RecyclableList list, int index, in Array items) - { - if (list._capacity < list._count + items.Length) - { - list._capacity = RecyclableListHelpers.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(this RecyclableList list, int index, in T[] items) - { - if (list._capacity < list._count + items.Length) - { - list._capacity = RecyclableListHelpers.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(items).CopyTo(new Span(memoryBlock, index, items.Length)); - list._count += items.Length; - list._version++; - } - - [MethodImpl(MethodImplOptions.NoInlining | MethodImplOptions.AggressiveOptimization)] - public static void InsertRange(this RecyclableList list, int index, ReadOnlySpan items) - { - if (list._capacity < list._count + items.Length) - { - list._capacity = RecyclableListHelpers.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(memoryBlock, index, items.Length)); - list._count += items.Length; - list._version++; - } - - [MethodImpl(MethodImplOptions.NoInlining | MethodImplOptions.AggressiveOptimization)] - public static void InsertRange(this RecyclableList list, int index, Span items) - { - if (list._capacity < list._count + items.Length) - { - list._capacity = RecyclableListHelpers.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(memoryBlock, index, items.Length)); - list._count += items.Length; - list._version++; - } - - [MethodImpl(MethodImplOptions.NoInlining | MethodImplOptions.AggressiveOptimization)] - public static void InsertRange(this RecyclableList list, int index, List items) - { - if (list._capacity < list._count + items.Count) - { - list._capacity = RecyclableListHelpers.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(this RecyclableList list, int index, ICollection items) - { - if (list._capacity < list._count + items.Count) - { - list._capacity = RecyclableListHelpers.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(this RecyclableList list, int index, ICollection items) - { - if (list._capacity < list._count + items.Count) - { - list._capacity = RecyclableListHelpers.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(this RecyclableList list, int index, RecyclableList items) - { - if (list._capacity < list._count + items._count) - { - list._capacity = RecyclableListHelpers.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(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(this RecyclableList list, int index, RecyclableLongList 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)}, equal {int.MaxValue}. Please consider using {nameof(RecyclableLongList)}, instead"); - } - - int targetCapacity = oldCount + (int)sourceItemsCount; - if (list._capacity < targetCapacity) - { - list._capacity = RecyclableListHelpers.EnsureCapacity(list, oldCount, checked((int)BitOperations.RoundUpToPowerOf2((uint)targetCapacity))); - } - - T[] memoryBlock = list._memoryBlock; - Array.Copy(memoryBlock, index, memoryBlock, index + items.Count, oldCount - index); - Span 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(this RecyclableList list, int index, IEnumerable source, int growByCount = RecyclableDefaults.MinPooledArrayLength) - { - int targetItemIndex = list._count; - Span 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.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(this RecyclableList list, int index, IReadOnlyList items) - { - int sourceItemsCount = items.Count; - if (list._capacity < list._count + sourceItemsCount) - { - list._capacity = RecyclableListHelpers.EnsureCapacity(list, list._count, checked((int)BitOperations.RoundUpToPowerOf2((uint)(list._count + sourceItemsCount)))); - } - - Span 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(this RecyclableList list, int index, IEnumerable items, int growByCount = RecyclableDefaults.MinPooledArrayLength) - { - if (items is RecyclableList sourceRecyclableList) - { - InsertRange(list, index, sourceRecyclableList); - } - else if (items is RecyclableLongList 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 sourceList) - { - InsertRange(list, index, sourceList); - } - else if (items is ICollection sourceICollection) - { - InsertRange(list, index, sourceICollection); - } - else if (items is ICollection sourceICollectionWithObjects) - { - InsertRange(list, index, sourceICollectionWithObjects); - } - else if (items is IReadOnlyList 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); - } - } - } -} \ No newline at end of file diff --git a/Recyclable.Collections/RecyclableList.Compatibility.List.cs b/Recyclable.Collections/RecyclableList.Compatibility.List.cs deleted file mode 100644 index ba3e662..0000000 --- a/Recyclable.Collections/RecyclableList.Compatibility.List.cs +++ /dev/null @@ -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 AsReadOnly(this RecyclableList list) => new(list); - - public static int BinarySearch(this RecyclableList list, T item) - => Array.BinarySearch(list._memoryBlock, 0, list._count, item); - - public static int BinarySearch(this RecyclableList list, T item, IComparer? comparer) - => Array.BinarySearch(list._memoryBlock, 0, list._count, item, comparer); - - public static int BinarySearch(this RecyclableList list, int index, int count, T item, IComparer? comparer) - => Array.BinarySearch(list._memoryBlock, index, count, item, comparer); - - public static RecyclableList ConvertAll(this RecyclableList list, Converter converter) - { - int itemsCount = list._count; - if (itemsCount == 0) - { - return new(); - } - - RecyclableList result = new(itemsCount); - TOutput[] resultSpan = result._memoryBlock; - ReadOnlySpan sourceSpan = list._memoryBlock; - for (int bufferIndex = 0; bufferIndex < itemsCount; bufferIndex++) - { - resultSpan[bufferIndex] = converter(sourceSpan[bufferIndex]); - } - - result._count = itemsCount; - return result; - } - - public static void CopyTo(this RecyclableList list, T[] array) => Array.Copy(list._memoryBlock, array, list._count); - - public static void CopyTo(this RecyclableList list, int index, T[] array, int arrayIndex, int count) => Array.Copy(list._memoryBlock, index, array, arrayIndex, count); - - public static void ForEach(this RecyclableList list, Action action) - { - int sourceItemsCount = list._count; - if (sourceItemsCount == 0) - { - return; - } - - ReadOnlySpan sourceSpan = list._memoryBlock; - for (var itemIndex = 0; itemIndex < sourceItemsCount; itemIndex++) - { - action(sourceSpan[itemIndex]); - } - } - - public static RecyclableList GetRange(this RecyclableList list, int index, int count) - { - int sourceItemsCount = index + count <= list._count ? count : list._count - index; - if (sourceItemsCount <= 0) - { - return new(); - } - - ReadOnlySpan sourceSpan = list._memoryBlock; - RecyclableList result = new(sourceItemsCount); - Span 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(this RecyclableList list, Predicate 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._needsClearing) - { - Array.Clear(list._memoryBlock, list._count - foundItemsCount, foundItemsCount); - } - - list._count -= foundItemsCount; - list._version++; - return foundItemsCount; - } - - public static void RemoveRange(this RecyclableList 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._needsClearing) - { - Array.Clear(list._memoryBlock, oldCount - count, count); - } - - list._count -= count; - list._version++; - } - - public static void Reverse(this RecyclableList list) - { - Array.Reverse(list._memoryBlock, 0, list._count); - list._version++; - } - - public static void Reverse(this RecyclableList list, int index, int count) - { - Array.Reverse(list._memoryBlock, index, count); - list._version++; - } - - public static void Sort(this RecyclableList list) - { - Array.Sort(list._memoryBlock, 0, list._count); - list._version++; - } - - public static void Sort(this RecyclableList list, Comparison comparison) - { - Array.Sort(list._memoryBlock, 0, list._count, new ComparisonToComparerAdapter(comparison)); - list._version++; - } - - public static void Sort(this RecyclableList list, IComparer? comparer) - { - Array.Sort(list._memoryBlock, 0, list._count, comparer); - list._version++; - } - - public static void Sort(this RecyclableList list, int index, int count, IComparer? comparer) - { - Array.Sort(list._memoryBlock, index, count, comparer); - list._version++; - } - - public static T[] ToArray(this RecyclableList list) - { - T[] result = new T[list._count]; - new ReadOnlySpan(list._memoryBlock, 0, list._count).CopyTo(result); - return result; - } - - public static void TrimExcess(this RecyclableList list) - { - var requiredCapacity = list._count >= RecyclableDefaults.InitialCapacity ? list._count : RecyclableDefaults.InitialCapacity; - - T[] oldMemoryBlock = list._memoryBlock; - T[] result = requiredCapacity >= RecyclableDefaults.MinPooledArrayLength && BitOperations.IsPow2(requiredCapacity) - ? RecyclableArrayPool.RentShared(requiredCapacity) - : new T[requiredCapacity]; - - new ReadOnlySpan(oldMemoryBlock, 0, list._count).CopyTo(result); - - if (oldMemoryBlock.Length >= RecyclableDefaults.MinPooledArrayLength) - { - RecyclableArrayPool.ReturnShared(oldMemoryBlock, RecyclableList._needsClearing); - } - - list._memoryBlock = result; - list._capacity = requiredCapacity; - } - - public static bool TrueForAll(this RecyclableList list, Predicate match) - { - int sourceItemsCount = list._count; - if (sourceItemsCount == 0) - { - return false; - } - - ReadOnlySpan sourceSpan = list._memoryBlock; - for (var itemIndex = 0; itemIndex < sourceItemsCount; itemIndex++) - { - if (!match(sourceSpan[itemIndex])) - { - return false; - } - } - - return true; - } - } -} diff --git a/Recyclable.CollectionsTests/CustomIList.cs b/Recyclable.CollectionsTests/CustomIList.cs deleted file mode 100644 index 81acead..0000000 --- a/Recyclable.CollectionsTests/CustomIList.cs +++ /dev/null @@ -1,33 +0,0 @@ -using System.Collections; - -namespace Recyclable.CollectionsTests -{ - public class CustomIList : IList - { - protected List _list; - - public CustomIList() - { - _list = new List(); - } - - public CustomIList(IEnumerable items) - { - _list = new List(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 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(); - } -} \ No newline at end of file diff --git a/Recyclable.CollectionsTests/EnumerableWithoutCount.cs b/Recyclable.CollectionsTests/EnumerableWithoutCount.cs deleted file mode 100644 index 34df3e9..0000000 --- a/Recyclable.CollectionsTests/EnumerableWithoutCount.cs +++ /dev/null @@ -1,17 +0,0 @@ -using System.Collections; - -namespace Recyclable.CollectionsTests -{ - public class EnumerableWithoutCount : IEnumerable - { - private readonly IEnumerable _testData; - - public EnumerableWithoutCount(IEnumerable testData) - { - _testData = testData; - } - - public IEnumerator GetEnumerator() => _testData.GetEnumerator(); - IEnumerator IEnumerable.GetEnumerator() => _testData.GetEnumerator(); - } -} \ No newline at end of file diff --git a/Recyclable.CollectionsTests/Recyclable.CollectionsTests.csproj b/Recyclable.CollectionsTests/Recyclable.CollectionsTests.csproj index 2be9788..bd758b7 100644 --- a/Recyclable.CollectionsTests/Recyclable.CollectionsTests.csproj +++ b/Recyclable.CollectionsTests/Recyclable.CollectionsTests.csproj @@ -9,20 +9,19 @@ - - - + + all runtime; build; native; contentfiles; analyzers; buildtransitive - - - + + + all runtime; build; native; contentfiles; analyzers; buildtransitive - + all runtime; build; native; contentfiles; analyzers; buildtransitive diff --git a/Recyclable.CollectionsTests/RecyclableListTests.cs b/Recyclable.CollectionsTests/RecyclableListTests.cs index 9271a24..828ab17 100644 --- a/Recyclable.CollectionsTests/RecyclableListTests.cs +++ b/Recyclable.CollectionsTests/RecyclableListTests.cs @@ -1,9 +1,8 @@ using FluentAssertions; using Recyclable.Collections; +using Recyclable.Collections.TestData; using Recyclable.Collections.Linq; -using Recyclable.Collections.Pools; using System.Collections; -using System.Numerics; #pragma warning disable xUnit1026, RCS1163, IDE0060, RCS1235 @@ -501,22 +500,6 @@ namespace Recyclable.CollectionsTests } } - [Theory] - [MemberData(nameof(RecyclableLongListTestData.SourceDataVariants), MemberType = typeof(RecyclableLongListTestData))] - public void ConvertAllShouldConvertAllItems(string testCase, IEnumerable testData, int itemsCount) - { - // Prepare - using var list = new RecyclableList(testData, itemsCount); - var expectedData = testData.ToList().ConvertAll(item => item + 0.1); - - // Act - using var actual = list.ConvertAll(item => item + 0.1); - - // Validate - _ = actual.Count.Should().Be(itemsCount); - _ = actual.Should().Equal(expectedData); - } - [Theory] [MemberData(nameof(RecyclableLongListTestData.SourceDataVariants), MemberType = typeof(RecyclableLongListTestData))] public void CopyToShouldCopyAllItemsInTheCorrectOrder(string testCase, IEnumerable testData, int itemsCount) @@ -535,24 +518,6 @@ namespace Recyclable.CollectionsTests _ = copiedItems.Should().Equal(expectedData); } - [Theory] - [MemberData(nameof(RecyclableLongListTestData.SourceDataVariants), MemberType = typeof(RecyclableLongListTestData))] - public void CopyToShouldCopyAllItemsInTheCorrectOrderWhenFromStart(string testCase, IEnumerable testData, int itemsCount) - { - // Prepare - using var list = new RecyclableList(testData, itemsCount); - long[] copiedItems = new long[itemsCount]; - - // Act - list.CopyTo(copiedItems); - - // Validate - long[] expectedData = new long[itemsCount]; - testData.ToList().CopyTo(expectedData); - - _ = copiedItems.Should().Equal(testData); - } - [Theory] [MemberData(nameof(RecyclableLongListTestData.SourceRefDataVariants), MemberType = typeof(RecyclableLongListTestData))] public void DisposeShouldClearItemsWhenReferenceType(string testCase, IEnumerable testData, int itemsCount) @@ -632,373 +597,6 @@ namespace Recyclable.CollectionsTests _ = yieldedItems.Should().Equal(expectedData); } - [Theory] - [MemberData(nameof(RecyclableLongListTestData.SourceDataWithItemIndexVariants), MemberType = typeof(RecyclableLongListTestData))] - public void ExistsShouldFindAllItems(string testCase, IEnumerable testData, int itemsCount, in long[] itemIndexes) - { - _ = testData.Any().Should().BeTrue("we need items on the list that we can look for"); - - // Prepare - using var list = new RecyclableList(testData, itemsCount); - var expectedData = testData.ToList(); - - foreach (var itemIndex in itemIndexes) - { - var expectedItem = expectedData[(int)itemIndex]; - var expected = expectedData.Exists(item => item == expectedItem); - - // Act - var actual = list.Exists(item => item == expectedItem); - - // Validate - _ = actual.Should().Be(expected); - } - } - - [Theory] - [MemberData(nameof(RecyclableLongListTestData.SourceDataWithItemIndexVariants), MemberType = typeof(RecyclableLongListTestData))] - public void ExistsShouldNotFindNonExistingItems(string testCase, IEnumerable testData, int itemsCount, in long[] itemIndexes) - { - _ = testData.Any().Should().BeTrue("we need items on the list that we can look for"); - - // Prepare - using var list = new RecyclableList(testData, itemsCount); - var expectedData = testData.ToList(); - - foreach (var itemIndex in itemIndexes) - { - var expectedItem = expectedData[(int)itemIndex]; - var expected = expectedData.Exists(item => item == -expectedItem); - - // Act - var actual = list.Exists(item => item == -expectedItem); - - // Validate - _ = actual.Should().Be(expected); - } - } - - [Theory] - [MemberData(nameof(RecyclableLongListTestData.SourceDataWithItemIndexVariants), MemberType = typeof(RecyclableLongListTestData))] - public void FindAllIndexesShouldReturnCorrectIndexes(string testCase, IEnumerable testData, int itemsCount, in long[] itemIndexes) - { - //* There is no equivalent of .FindAllIndexes in List, so no comparison here. - - // Prepare - using var list = new RecyclableList(testData, itemsCount); - - foreach (var itemIndex in itemIndexes) - { - // Act - using var actual = list.FindAllIndexes(item => item == itemIndex + 1); - - // Validate - _ = actual.Count.Should().Be(1); - if (itemsCount > 0) - { - _ = actual.Count.Should().Be(1); - _ = actual.Should().AllSatisfy(x => x.Should().Be((int)itemIndex)); - } - } - } - - [Theory] - [MemberData(nameof(RecyclableLongListTestData.ItemsCountTestCases), MemberType = typeof(RecyclableLongListTestData))] - public void FindAllShouldReturnCorrectIndexes(int itemsCount) - { - const int expectedItem = 1; - - // Prepare - var testData = Enumerable.Range(0, itemsCount).Select(value => value % 2 == 0 ? expectedItem : -expectedItem); - using var list = new RecyclableList(testData, itemsCount); - - // Act - using var actual = list.FindAll(x => x == expectedItem); - - // Validate - var expectedData = testData.ToList().FindAll(x => x == expectedItem); - - _ = actual.Count.Should().Be(expectedData.Count); - _ = actual.Should().Equal(expectedData); - if (expectedData.Count > 0) - { - _ = actual.Should().AllSatisfy(x => x.Should().Be(expectedItem)).And.Equal(expectedData); - } - } - - [Theory] - [MemberData(nameof(RecyclableLongListTestData.ItemsCountTestCases), MemberType = typeof(RecyclableLongListTestData))] - public void FindAllShouldNotFindNonExistingItems(int itemsCount) - { - const int expectedItem = 1; - - // Prepare - var testData = Enumerable.Range(0, itemsCount).Select(_ => expectedItem); - using var list = new RecyclableList(testData, itemsCount); - - // Act - using var foundItems = list.FindAll(x => x == -expectedItem); - - // Validate - var expectedData = testData.ToList().FindAll(x => x == -expectedItem); - - _ = foundItems.Count.Should().Be(expectedData.Count); - _ = foundItems.Should().Equal(expectedData); - } - - [Theory] - [MemberData(nameof(RecyclableLongListTestData.SourceDataWithItemIndexVariants), MemberType = typeof(RecyclableLongListTestData))] - public void FindIndexShouldReturnCorrectIndexes(string testCase, IEnumerable testData, int itemsCount, in long[] itemIndexes) - { - // Prepare - using var list = new RecyclableList(testData, itemsCount); - var expectedData = testData.ToList(); - - foreach (var itemIndex in itemIndexes) - { - var expectedItem = expectedData[(int)itemIndex]; - - // Act - var actual = list.FindIndex(item => item == expectedItem); - - // Validate - var expected = expectedData.FindIndex(item => item == expectedItem); - - _ = actual.Should().Be((int)itemIndex).And.Be(expected); - } - } - - [Theory] - [MemberData(nameof(RecyclableLongListTestData.SourceDataWithItemIndexVariants), MemberType = typeof(RecyclableLongListTestData))] - public void FindIndexShouldReturnCorrectIndexesWhenConstrainedCount(string testCase, IEnumerable testData, int itemsCount, in long[] itemIndexes) - { - // Prepare - using var list = new RecyclableList(testData, itemsCount); - var expectedData = testData.ToList(); - - foreach (var itemIndex in itemIndexes) - { - var expectedItem = expectedData[(int)itemIndex]; - var expected = expectedData.FindIndex((int)itemIndex, (int)(itemsCount - itemIndex), item => item == expectedItem); - - // Act - var actual = list.FindIndex((int)itemIndex, (int)(itemsCount - itemIndex), item => item == expectedItem); - - // Validate - _ = actual.Should().Be((int)itemIndex).And.Be(expected); - } - } - - [Theory] - [MemberData(nameof(RecyclableLongListTestData.SourceDataWithItemIndexVariants), MemberType = typeof(RecyclableLongListTestData))] - public void FindIndexShouldReturnCorrectIndexesWhenConstrainedIndex(string testCase, IEnumerable testData, int itemsCount, in long[] itemIndexes) - { - // Prepare - using var list = new RecyclableList(testData, itemsCount); - var expectedData = testData.ToList(); - - foreach (var itemIndex in itemIndexes) - { - var expectedItem = expectedData[(int)itemIndex]; - var expected = expectedData.FindIndex(Math.Min(1, (int)itemIndex), item => item == expectedItem); - - // Act - var actual = list.FindIndex(Math.Min(1, (int)itemIndex), item => item == expectedItem); - - // Validate - _ = actual.Should().Be((int)itemIndex).And.Be(expected); - } - } - - [Theory] - [MemberData(nameof(RecyclableLongListTestData.SourceDataWithItemIndexVariants), MemberType = typeof(RecyclableLongListTestData))] - public void FindLastIndexShouldReturnCorrectIndexes(string testCase, IEnumerable testData, int itemsCount, in long[] itemIndexes) - { - // Prepare - using var list = new RecyclableList(testData, itemsCount); - var expectedData = testData.ToList(); - - foreach (var itemIndex in itemIndexes) - { - var expectedItem = expectedData[(int)itemIndex]; - var expected = expectedData.FindLastIndex(x => x == expectedItem); - - // Act - var actual = list.FindLastIndex(x => x == expectedItem); - - // Validate - _ = actual.Should().Be((int)itemIndex).And.Be(expected); - } - } - - [Theory] - [MemberData(nameof(RecyclableLongListTestData.SourceDataWithItemIndexVariants), MemberType = typeof(RecyclableLongListTestData))] - public void FindLastIndexShouldReturnCorrectIndexesWhenConstrainedCount(string testCase, IEnumerable testData, int itemsCount, in long[] itemIndexes) - { - // Prepare - using var list = new RecyclableList(testData, itemsCount); - var expectedData = testData.ToList(); - - foreach (var itemIndex in itemIndexes) - { - var expectedItem = expectedData[(int)itemIndex]; - - // Act & Validate - var expected = expectedData.FindLastIndex(itemsCount - 1, itemsCount, x => x == expectedItem); - _ = list.FindLastIndex(itemsCount - 1, itemsCount, x => x == expectedItem).Should().Be((int)itemIndex).And.Be(expected); - } - } - - [Theory] - [MemberData(nameof(RecyclableLongListTestData.SourceDataWithItemIndexVariants), MemberType = typeof(RecyclableLongListTestData))] - public void FindLastIndexShouldReturnCorrectIndexesWhenConstrainedIndex(string testCase, IEnumerable testData, int itemsCount, in long[] itemIndexes) - { - // Prepare - using var list = new RecyclableList(testData, itemsCount); - var expectedData = testData.ToList(); - - foreach (var itemIndex in itemIndexes) - { - var expectedItem = expectedData[(int)itemIndex]; - var expected = expectedData.FindLastIndex(itemsCount - 1, x => x == expectedItem); - - // Act - var actual = list.FindLastIndex(itemsCount - 1, x => x == expectedItem); - - // Validate - _ = actual.Should().Be((int)itemIndex).And.Be(expected); - } - } - - [Theory] - [MemberData(nameof(RecyclableLongListTestData.SourceDataWithItemIndexVariants), MemberType = typeof(RecyclableLongListTestData))] - public void FindLastIndexShouldThrowArgumentOutOfRange(string testCase, IEnumerable testData, int itemsCount, in long[] itemIndexes) - { - // Prepare - using var list = new RecyclableList(testData, itemsCount); - var expectedData = testData.ToList(); - - foreach (var itemIndex in itemIndexes) - { - var expectedItem = expectedData[(int)itemIndex]; - int expected = int.MinValue; - - // Act & Validate - if (itemsCount - 1 != -1) - { - Assert.Throws(() => expected = expectedData.FindLastIndex(itemsCount - 1, itemsCount + 3, x => x == expectedItem)); - Assert.Throws(() => _ = list.FindLastIndex(itemsCount - 1, itemsCount + 3, x => x == expectedItem).Should().Be((int)itemIndex).And.Be(expected)); - } - else - { - expected = expectedData.FindLastIndex(itemsCount - 1, itemsCount + 3, x => x == expectedItem); - _ = list.FindLastIndex(itemsCount - 1, itemsCount + 3, x => x == expectedItem).Should().Be((int)itemIndex).And.Be(expected); - } - } - } - - [Theory] - [MemberData(nameof(RecyclableLongListTestData.SourceDataWithItemIndexVariants), MemberType = typeof(RecyclableLongListTestData))] - public void FindLastShouldReturnCorrectItem(string testCase, IEnumerable testData, int itemsCount, in long[] itemIndexes) - { - // Prepare - using var list = new RecyclableList(testData, itemsCount); - var expectedData = testData.ToList(); - - foreach (var itemIndex in itemIndexes) - { - var expectedItem = expectedData[(int)itemIndex]; - var expected = expectedData.FindLast(item => item == expectedItem); - - // Act - var actual = list.FindLast(item => item == expectedItem); - - // Validate - _ = actual.Should().Be(expectedData[(int)itemIndex]).And.Be(expected); - } - } - - [Theory] - [MemberData(nameof(RecyclableLongListTestData.SourceDataWithItemIndexVariants), MemberType = typeof(RecyclableLongListTestData))] - public void FindShouldFindAllItems(string testCase, IEnumerable testData, int itemsCount, in long[] itemIndexes) - { - _ = testData.Any().Should().BeTrue("we need items on the list that we can look for"); - - // Prepare - using var list = new RecyclableList(testData, itemsCount); - var expectedData = testData.ToList(); - - foreach (var itemIndex in itemIndexes) - { - long expectedItem = expectedData[(int)itemIndex]; - var expected = expectedData.Find(item => item == expectedItem); - - // Act - var actual = list.Find(item => item == expectedData[(int)itemIndex]); - - // Validate - _ = actual.Should().Be(expectedData[(int)itemIndex]); - } - } - - [Theory] - [MemberData(nameof(RecyclableLongListTestData.SourceDataWithItemIndexVariants), MemberType = typeof(RecyclableLongListTestData))] - public void FindShouldNotFindNonExistingItems(string testCase, IEnumerable testData, int itemsCount, in long[] itemIndexes) - { - _ = testData.Any().Should().BeTrue("we need items on the list that we can look for"); - - // Prepare - using var list = new RecyclableList(testData, itemsCount); - var expectedData = testData.ToList(); - - foreach (var itemIndex in itemIndexes) - { - var expected = expectedData.Find(item => item == -expectedData[(int)itemIndex]); - - // Act - var actual = list.Find(item => item == -expectedData[(int)itemIndex]); - - // Validate - actual.Should().Be(0).And.Be(expected); - } - } - - [Theory] - [MemberData(nameof(RecyclableLongListTestData.SourceDataVariants), MemberType = typeof(RecyclableLongListTestData))] - public void ForEachShouldGiveItemsInCorrectOrder(string testCase, IEnumerable testData, int itemsCount) - { - // Prepare - using var list = new RecyclableList(testData, itemsCount); - var expectedData = testData.ToList(); - var expected = new List(itemsCount); - expectedData.ForEach(expected.Add); - - // Act - var yieldedItems = new List(itemsCount); - list.ForEach(yieldedItems.Add); - - // Validate - _ = yieldedItems.Should().Equal(testData).And.Equal(expected); - } - - [Theory] - [MemberData(nameof(RecyclableLongListTestData.EmptySourceDataVariants), MemberType = typeof(RecyclableLongListTestData))] - public void ForEachShouldDoNothingWhenEmptyList(string testCase, IEnumerable testData, int itemsCount) - { - // Prepare - using var list = new RecyclableList(testData, itemsCount); - var expectedData = testData.ToList(); - var expected = new List(itemsCount); - expectedData.ForEach(expected.Add); - - // Act - var yieldedItems = new List(itemsCount); - list.ForEach(item => yieldedItems.Add(item)); - - // Validate - _ = yieldedItems.Should().BeEmpty().And.Equal(expected); - } - [Theory] [MemberData(nameof(RecyclableLongListTestData.SourceDataVariants), MemberType = typeof(RecyclableLongListTestData))] public void GetByIndexShouldReturnCorrectItem(string testCase, IEnumerable testData, int itemsCount) @@ -1019,30 +617,6 @@ namespace Recyclable.CollectionsTests } } - [Theory] - [MemberData(nameof(RecyclableLongListTestData.SourceDataWithItemIndexVariants), MemberType = typeof(RecyclableLongListTestData))] - public void GetRangeShouldReturnCorrectItems(string testCase, IEnumerable testData, int itemsCount, in long[] itemIndexes) - { - _ = testData.Any().Should().BeTrue("we need items on the list that we can look for"); - - // Prepare - using var list = new RecyclableList(testData, itemsCount); - var expectedData = testData.ToList(); - - foreach (var itemIndex in itemIndexes) - { - int startingIndex = (int)Math.Min(1, itemIndex); - var expectedRangeItems = expectedData.GetRange(startingIndex, (int)itemIndex); - - // Act - using var rangeItems = list.GetRange(startingIndex, (int)itemIndex); - - // Validate - _ = rangeItems.Count.Should().Be(expectedRangeItems.Count); - _ = rangeItems.Should().Equal(expectedRangeItems); - } - } - [Fact] public void IndexOfShouldNotFindAnythingWhenListEmpty() { @@ -1097,122 +671,6 @@ namespace Recyclable.CollectionsTests } } - [Theory] - [MemberData(nameof(RecyclableLongListTestData.SourceDataWithItemIndexVariants), MemberType = typeof(RecyclableLongListTestData))] - public void IndexOfShouldReturnCorrectIndexesWhenConstrainedCount(string testCase, IEnumerable testData, int itemsCount, in long[] itemIndexes) - { - // Prepare - using var list = new RecyclableList(testData, itemsCount); - var expectedData = testData.ToList(); - - foreach (var itemIndex in itemIndexes) - { - var expected = expectedData.IndexOf(expectedData[(int)itemIndex], (int)itemIndex, (int)(itemsCount - itemIndex)); - - // Act - var actual = list.IndexOf(expectedData[(int)itemIndex], (int)itemIndex, (int)(itemsCount - itemIndex)); - - // Validate - _ = actual.Should().Be((int)itemIndex).And.Be(expected); - } - } - - [Theory] - [MemberData(nameof(RecyclableLongListTestData.SourceDataWithItemIndexVariants), MemberType = typeof(RecyclableLongListTestData))] - public void IndexOfShouldReturnCorrectIndexesWhenConstrainedIndex(string testCase, IEnumerable testData, int itemsCount, in long[] itemIndexes) - { - // Prepare - using var list = new RecyclableList(testData, itemsCount); - var expectedData = testData.ToList(); - - foreach (var itemIndex in itemIndexes) - { - var expected = expectedData.IndexOf(expectedData[(int)itemIndex], (int)itemIndex); - - // Act - var actual = list.IndexOf(expectedData[(int)itemIndex], (int)itemIndex); - - // Validate - _ = actual.Should().Be((int)itemIndex).And.Be(expected); - } - } - - [Theory] - [MemberData(nameof(RecyclableLongListTestData.SourceDataWithItemIndexVariants), MemberType = typeof(RecyclableLongListTestData))] - public void LastIndexOfShouldReturnCorrectIndexes(string testCase, IEnumerable testData, int itemsCount, in long[] itemIndexes) - { - // Prepare - using var list = new RecyclableList(testData, itemsCount); - var expectedData = testData.ToList(); - - foreach (var itemIndex in itemIndexes) - { - var expected = expectedData.LastIndexOf(expectedData[(int)itemIndex]); - - // Act - var actual = list.LastIndexOf(expectedData[(int)itemIndex]); - - // Validate - _ = actual.Should().Be((int)itemIndex).And.Be(expected); - } - } - - [Theory] - [MemberData(nameof(RecyclableLongListTestData.SourceDataWithItemIndexVariants), MemberType = typeof(RecyclableLongListTestData))] - public void LastIndexOfShouldReturnCorrectIndexesWhenConstrainedCount(string testCase, IEnumerable testData, int itemsCount, in long[] itemIndexes) - { - // Prepare - using var list = new RecyclableList(testData, itemsCount); - var expectedData = testData.ToList(); - - foreach (var itemIndex in itemIndexes) - { - var expected = expectedData.LastIndexOf(expectedData[(int)itemIndex], itemsCount - 1, itemsCount); - - // Act - var actual = list.LastIndexOf(expectedData[(int)itemIndex], itemsCount - 1, itemsCount); - - // Validate - _ = actual.Should().Be((int)itemIndex).And.Be(expected); - } - } - - [Theory] - [MemberData(nameof(RecyclableLongListTestData.SourceDataWithItemIndexVariants), MemberType = typeof(RecyclableLongListTestData))] - public void LastIndexOfShouldReturnCorrectIndexesWhenConstrainedIndex(string testCase, IEnumerable testData, int itemsCount, in long[] itemIndexes) - { - // Prepare - using var list = new RecyclableList(testData, itemsCount); - var expectedData = testData.ToList(); - - foreach (var itemIndex in itemIndexes) - { - var expected = expectedData.LastIndexOf(expectedData[(int)itemIndex], itemsCount - 1); - - // Act - var actual = list.LastIndexOf(expectedData[(int)itemIndex], itemsCount - 1); - - // Validate - _ = actual.Should().Be((int)itemIndex).And.Be(expected); - } - } - - [Theory] - [MemberData(nameof(RecyclableLongListTestData.SourceDataWithItemIndexVariants), MemberType = typeof(RecyclableLongListTestData))] - public void LastIndexOfShouldThrowArgumentOutOfRangeWhenCountTooBig(string testCase, IEnumerable testData, int itemsCount, in long[] itemIndexes) - { - // Prepare - using var list = new RecyclableList(testData, itemsCount); - var expectedData = testData.ToList(); - - // Act & Validate - foreach (var itemIndex in itemIndexes) - { - _ = Assert.Throws(() => _ = expectedData.LastIndexOf(expectedData[(int)itemIndex], itemsCount - 1, itemsCount + 3).Should().Be((int)itemIndex)); - _ = Assert.Throws(() => _ = list.LastIndexOf(expectedData[(int)itemIndex], itemsCount - 1, itemsCount + 3).Should().Be((int)itemIndex)); - } - } - [Theory] [MemberData(nameof(RecyclableLongListTestData.SourceDataWithItemIndexVariants), MemberType = typeof(RecyclableLongListTestData))] public void InitializeSortClearAddRangeRemoveShouldSucceed(string testCase, IEnumerable testData, int itemsCount, in long[] itemIndexes) @@ -1281,49 +739,6 @@ namespace Recyclable.CollectionsTests } } - [Theory] - [MemberData(nameof(RecyclableLongListTestData.SourceDataWithItemIndexVariants), MemberType = typeof(RecyclableLongListTestData))] - public void InsertRangeShouldMoveItems(string testCase, IEnumerable testData, int itemsCount, in long[] itemIndexes) - { - foreach (var itemIndex in itemIndexes) - { - // Prepare - using var list = new RecyclableList(testData.Reverse(), itemsCount); - var expectedItems = testData.Reverse().ToList(); - var item = expectedItems[^1]; - expectedItems.InsertRange((int)itemIndex, testData); - - // Act - list.InsertRange((int)itemIndex, testData); - - // Validate - _ = list[(int)itemIndex].Should().Be(item); - _ = list.Count.Should().Be(itemsCount << 1); - _ = list.Capacity.Should().BeGreaterThanOrEqualTo(itemsCount << 1); - _ = list.Should().Equal(expectedItems); - } - } - - [Theory] - [MemberData(nameof(RecyclableLongListTestData.SourceDataWithItemIndexVariants), MemberType = typeof(RecyclableLongListTestData))] - public void RemoveAllShouldRemoveTheCorrectItems(string testCase, IEnumerable testData, int itemsCount, in long[] itemIndexes) - { - // Prepare - using var list = new RecyclableList(testData, itemsCount); - var itemsToRemove = itemIndexes.Select(x => list[(int)x]).ToArray(); - var expectedItems = testData.ToList(); - var expectedResult = expectedItems.RemoveAll(itemsToRemove.Contains); - - // Act - var actualResult = list.RemoveAll(itemsToRemove.Contains); - - // Validate - _ = actualResult.Should().Be(expectedResult); - _ = list.Capacity.Should().BeGreaterThanOrEqualTo(itemsCount); - _ = list.Count.Should().Be(itemsCount - itemsToRemove.Length); - _ = list.Should().Equal(expectedItems); - } - [Theory] [MemberData(nameof(RecyclableLongListTestData.SourceRefDataWithItemIndexVariants), MemberType = typeof(RecyclableLongListTestData))] public void RemoveAtShouldClearItemWhenReferenceType(string testCase, IEnumerable testData, int itemsCount, in long[] indexesToRemove) @@ -1363,29 +778,6 @@ namespace Recyclable.CollectionsTests } } - [Theory] - [MemberData(nameof(RecyclableLongListTestData.SourceDataWithItemIndexVariants), MemberType = typeof(RecyclableLongListTestData))] - public void RemoveRangeShouldRemoveCorrectItems(string testCase, IEnumerable testData, int itemsCount, in long[] itemIndexes) - { - _ = testData.Any().Should().BeTrue("we need items on the list that we can look for"); - - foreach (var itemIndex in itemIndexes) - { - // Prepare - int startingIndex = (int)Math.Min(1, itemIndex); - var expectedData = testData.ToList(); - expectedData.RemoveRange(startingIndex, (int)itemIndex); - - // Act - using var list = new RecyclableList(testData, itemsCount); - list.RemoveRange(startingIndex, (int)itemIndex); - - // Validate - _ = list.Count.Should().Be(expectedData.Count); - _ = list.Should().Equal(expectedData); - } - } - [Theory] [MemberData(nameof(RecyclableLongListTestData.SourceRefDataWithItemIndexVariants), MemberType = typeof(RecyclableLongListTestData))] public void RemoveShouldClearItemWhenReferenceType(string testCase, IEnumerable testData, int itemsCount, in long[] indexesToRemove) @@ -1430,45 +822,6 @@ namespace Recyclable.CollectionsTests } } - [Theory] - [MemberData(nameof(RecyclableLongListTestData.SourceDataVariants), MemberType = typeof(RecyclableLongListTestData))] - public void ReverseShouldSwapItemsInCorrectOrder(string testCase, IEnumerable testData, int itemsCount) - { - // Prepare - using var list = new RecyclableList(testData, itemsCount); - var expectedData = testData.ToList(); - expectedData.Reverse(); - - // Act - list.Reverse(); - - // Validate - _ = list.Should().Equal(expectedData); - } - - [Theory] - [MemberData(nameof(RecyclableLongListTestData.SourceDataWithItemIndexVariants), MemberType = typeof(RecyclableLongListTestData))] - public void ReverseShouldSwapItemsInCorrectOrderWhenConstrained(string testCase, IEnumerable testData, int itemsCount, long[] itemIndexes) - { - // Prepare - var expectedData = testData.ToArray(); - - foreach (var itemIndex in itemIndexes) - { - // Prepare - using var list = new RecyclableList(testData, itemsCount); - var startingItemIndex = (int)Math.Min(1, itemIndex); - var expectedRangeItems = expectedData.ToList(); - expectedRangeItems.Reverse(startingItemIndex, (int)itemIndex); - - // Act - list.Reverse(startingItemIndex, (int)itemIndex); - - // Validate - _ = list.Should().Equal(expectedRangeItems); - } - } - [Theory] [MemberData(nameof(RecyclableLongListTestData.SourceDataVariants), MemberType = typeof(RecyclableLongListTestData))] public void SetByIndexShouldReturnCorrectItem(string testCase, IEnumerable testData, int itemsCount) @@ -1490,91 +843,6 @@ namespace Recyclable.CollectionsTests } } - [Theory] - [MemberData(nameof(RecyclableLongListTestData.SourceDataVariants), MemberType = typeof(RecyclableLongListTestData))] - public void SortShouldSortItemsInCorrectOrder(string testCase, IEnumerable testData, int itemsCount) - { - // Prepare - using var list = new RecyclableList(testData.Reverse(), itemsCount); - var expectedData = testData.Reverse().ToList(); - expectedData.Sort(); - - // Act - list.Sort(); - - // Validate - _ = list.Should().Equal(expectedData); - } - - [Theory] - [MemberData(nameof(RecyclableLongListTestData.SourceDataVariants), MemberType = typeof(RecyclableLongListTestData))] - public void SortShouldSortItemsInCorrectOrderWhenWithComparer(string testCase, IEnumerable testData, int itemsCount) - { - // Prepare - using var list = new RecyclableList(testData.Reverse(), itemsCount); - IComparer comparer = Comparer.Default; - var expectedData = testData.Reverse().ToList(); - expectedData.Sort(comparer); - - // Act - list.Sort(comparer); - - // Validate - _ = list.Should().Equal(expectedData); - } - - [Theory] - [MemberData(nameof(RecyclableLongListTestData.SourceDataVariants), MemberType = typeof(RecyclableLongListTestData))] - public void SortShouldSortItemsInCorrectOrderWhenWithComparison(string testCase, IEnumerable testData, int itemsCount) - { - // Prepare - using var list = new RecyclableList(testData.Reverse(), itemsCount); - - static int comparison(long x, long y) - { - return (x - y) switch - { - > 0 => 1, - < 0 => -1, - _ => 0, - }; - } - - var expectedData = testData.Reverse().ToList(); - expectedData.Sort(comparison); - - // Act - list.Sort(comparison); - - // Validate - _ = list.Should().Equal(expectedData); - } - - [Theory] - [MemberData(nameof(RecyclableLongListTestData.SourceDataWithItemIndexVariants), MemberType = typeof(RecyclableLongListTestData))] - public void SortShouldSortItemsInCorrectOrderWhenConstrained(string testCase, IEnumerable testData, int itemsCount, long[] itemIndexes) - { - // Prepare - IComparer comparer = Comparer.Default; - var expectedData = testData.Reverse().ToArray(); - - foreach (var itemIndex in itemIndexes) - { - // Prepare - using var list = new RecyclableList(testData.Reverse(), itemsCount); - var startingIndex = (int)Math.Min(1, itemIndex); - - var expectedSortedData = expectedData.ToList(); - expectedSortedData.Sort(startingIndex, (int)itemIndex, comparer); - - // Act - list.Sort(startingIndex, (int)itemIndex, comparer); - - // Validate - _ = list.Should().Equal(expectedSortedData); - } - } - [Theory] [MemberData(nameof(RecyclableLongListTestData.SourceDataVariants), MemberType = typeof(RecyclableLongListTestData))] public void ToArrayShouldReturnAllItemsInCorrectOrder(string testCase, IEnumerable testData, int itemsCount) @@ -1591,220 +859,6 @@ namespace Recyclable.CollectionsTests _ = returnedItems.Should().Equal(expectedData); } - [Theory] - [MemberData(nameof(RecyclableLongListTestData.SourceDataVariants), MemberType = typeof(RecyclableLongListTestData))] - public void TrimExcessShouldDecreaseCapacity(string testCase, IEnumerable testData, int itemsCount) - { - // Prepare - using var list = new RecyclableList(testData, itemsCount); - var expectedCapacity = itemsCount >= RecyclableDefaults.InitialCapacity ? itemsCount : RecyclableDefaults.InitialCapacity; - - // Act - list.TrimExcess(); - - // Validate - _ = list.Capacity.Should().Be(expectedCapacity); - _ = list.Count.Should().Be(itemsCount); - _ = list.Should().Equal(testData); - } - - [Theory] - [MemberData(nameof(RecyclableLongListTestData.SourceDataVariants), MemberType = typeof(RecyclableLongListTestData))] - public void TrimExcessShouldNotBreakAdd(string testCase, IEnumerable testData, int itemsCount) - { - // Prepare - using var list = new RecyclableList(testData, itemsCount); - var expectedCapacity = (int)BitOperations.RoundUpToPowerOf2((uint)itemsCount + 1); - expectedCapacity = expectedCapacity >= RecyclableDefaults.InitialCapacity ? expectedCapacity : RecyclableDefaults.InitialCapacity; - - // Act - list.TrimExcess(); - list.Add(-1); - - // Validate - _ = list.Capacity.Should().Be(expectedCapacity); - _ = list.Count.Should().Be(itemsCount + 1); - _ = list.Should().Equal(testData.Append(-1)); - } - - [Theory] - [MemberData(nameof(RecyclableLongListTestData.SourceDataVariants), MemberType = typeof(RecyclableLongListTestData))] - public void TrimExcessShouldNotBreakAddRange(string testCase, IEnumerable testData, int itemsCount) - { - // Prepare - using var list = new RecyclableList(testData, itemsCount); - var expectedCapacity = (int)BitOperations.RoundUpToPowerOf2(checked((uint)itemsCount << 1)); - expectedCapacity = expectedCapacity >= RecyclableDefaults.InitialCapacity ? expectedCapacity : RecyclableDefaults.InitialCapacity; - - // Act - list.TrimExcess(); - list.AddRange(testData); - - // Validate - _ = list.Capacity.Should().BeGreaterThanOrEqualTo(expectedCapacity); - _ = list.Count.Should().Be(itemsCount << 1); - _ = list.Should().Equal(testData.Concat(testData)); - } - - [Theory] - [MemberData(nameof(RecyclableLongListTestData.SourceDataVariants), MemberType = typeof(RecyclableLongListTestData))] - public void TrimExcessShouldNotBreakClear(string testCase, IEnumerable testData, int itemsCount) - { - // Prepare - using var list = new RecyclableList(testData, itemsCount); - - // Act - list.TrimExcess(); - list.Clear(); - - // Validate - _ = list.Capacity.Should().Be(Math.Max(RecyclableDefaults.InitialCapacity, itemsCount)); - _ = list.Count.Should().Be(0); - _ = list.Should().BeEmpty(); - } - - [Theory] - [MemberData(nameof(RecyclableLongListTestData.SourceDataWithItemIndexVariants), MemberType = typeof(RecyclableLongListTestData))] - public void TrimExcessShouldNotBreakInsert(string testCase, IEnumerable testData, int itemsCount, long[] itemIndexes) - { - // Prepare - var expectedCapacity = (int)BitOperations.RoundUpToPowerOf2((uint)itemsCount + 1); - expectedCapacity = expectedCapacity >= RecyclableDefaults.InitialCapacity ? expectedCapacity : RecyclableDefaults.InitialCapacity; - var expectedData = testData.ToArray(); - - foreach (var itemIndex in itemIndexes) - { - using var list = new RecyclableList(testData, itemsCount); - var expectedItemsAfterInsert = expectedData.ToList(); - expectedItemsAfterInsert.Insert((int)itemIndex, -3); - - // Act - list.TrimExcess(); - list.Insert((int)itemIndex, -3); - - // Validate - _ = list.Capacity.Should().BeGreaterThanOrEqualTo(expectedCapacity); - _ = list.Count.Should().Be(expectedItemsAfterInsert.Count); - _ = list.Should().Equal(expectedItemsAfterInsert); - } - } - - [Theory] - [MemberData(nameof(RecyclableLongListTestData.SourceDataWithItemIndexVariants), MemberType = typeof(RecyclableLongListTestData))] - public void TrimExcessShouldNotBreakRemove(string testCase, IEnumerable testData, int itemsCount, long[] itemIndexes) - { - // Prepare - var expectedData = testData.ToArray(); - - foreach (var itemIndex in itemIndexes) - { - using var list = new RecyclableList(testData, itemsCount); - var expectedItemsAfterInsert = expectedData.ToList(); - expectedItemsAfterInsert.RemoveAt((int)itemIndex); - - // Act - list.TrimExcess(); - list.RemoveAt((int)itemIndex); - - // Validate - _ = list.Capacity.Should().BeGreaterThanOrEqualTo(itemsCount); - _ = list.Count.Should().Be(expectedItemsAfterInsert.Count); - _ = list.Should().Equal(expectedItemsAfterInsert); - } - } - - [Theory] - [MemberData(nameof(RecyclableLongListTestData.SourceDataWithItemIndexVariants), MemberType = typeof(RecyclableLongListTestData))] - public void TrimExcessShouldNotBreakIndexOf(string testCase, IEnumerable testData, int itemsCount, long[] itemIndexes) - { - // Prepare - var expectedData = testData.ToArray(); - - foreach (var itemIndex in itemIndexes) - { - using var list = new RecyclableList(testData, itemsCount); - - // Act - list.TrimExcess(); - var actual = list.IndexOf(expectedData[(int)itemIndex]); - - // Validate - _ = actual.Should().Be((int)itemIndex); - } - } - - [Theory] - [MemberData(nameof(RecyclableLongListTestData.SourceDataVariants), MemberType = typeof(RecyclableLongListTestData))] - public void TrimmedArraysShouldNotBePooled(string testCase, IEnumerable testData, int itemsCount) - { - // Prepare - using var list = new RecyclableList(testData, itemsCount); - - // Act - list.TrimExcess(); - var trimmedMemoryBlock = list._memoryBlock; - - list.Dispose(); - - // Validate - _ = list.Capacity.Should().Be(0); - _ = list.Count.Should().Be(0); - _ = list.Should().BeEmpty(); - - if (itemsCount >= RecyclableDefaults.MinPooledArrayLength) - { - var newMemoryBlock = RecyclableArrayPool.RentShared(itemsCount); - if (BitOperations.IsPow2(itemsCount)) - { - _ = newMemoryBlock.Should().BeSameAs(trimmedMemoryBlock); - } - else - { - _ = newMemoryBlock.Should().NotBeSameAs(trimmedMemoryBlock); - } - } - } - - [Theory] - [MemberData(nameof(RecyclableLongListTestData.SourceDataWithItemIndexVariants), MemberType = typeof(RecyclableLongListTestData))] - public void TrueForAllShouldBeFalseWhenNoMatch(string testCase, IEnumerable testData, int itemsCount, long[] itemIndexes) - { - // Prepare - var expectedData = testData.ToList(); - - foreach (var itemIndex in itemIndexes) - { - using RecyclableList list = new(testData, itemsCount); - Predicate condition = item => item == itemIndex; - var expected = expectedData.TrueForAll(condition); - - // Act - var actual = list.TrueForAll(condition); - - // Validate - _ = actual.Should().Be(expected).And.BeFalse(); - } - } - - [Theory] - [MemberData(nameof(RecyclableLongListTestData.SourceDataWithItemIndexVariants), MemberType = typeof(RecyclableLongListTestData))] - public void TrueForAllShouldBeTrueWhenMatched(string testCase, IEnumerable testData, int itemsCount, long[] itemIndexes) - { - // Prepare - using RecyclableList list = new(testData, itemsCount); - int index = 0; - Predicate condition = item => item == ++index; - var expected = testData.ToList().TrueForAll(condition); - - index = 0; - - // Act - var actual = list.TrueForAll(condition); - - // Validate - _ = actual.Should().Be(expected).And.BeTrue(); - } - [Theory] [MemberData(nameof(RecyclableLongListTestData.SourceDataVariants), MemberType = typeof(RecyclableLongListTestData))] public void VersionedEnumerateShouldRaiseExceptionWhenCollectionIsModified(string testCase, IEnumerable testData, int itemsCount) diff --git a/Recyclable.CollectionsTests/RecyclableLongListTestData.cs b/Recyclable.CollectionsTests/RecyclableLongListTestData.cs deleted file mode 100644 index a9f5a30..0000000 --- a/Recyclable.CollectionsTests/RecyclableLongListTestData.cs +++ /dev/null @@ -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().ToArray(); - public static object[] SourceRefData => _sourceRefData; - - public static IEnumerable CreateTestData(long itemsCount) - { - for (long index = 1; index <= itemsCount; index++) - { - yield return index; - } - } - - public static IEnumerable CreateRefTestData(long itemsCount) - { - for (long index = 1; index <= itemsCount; index++) - { - yield return index; - } - } - - public static readonly IEnumerable 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 ItemsCountTestCases = ItemsCountVariants.Select(x => new object[] { (int)x }); - - public static readonly IEnumerable 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 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 TargetDataVariants => GetTargetDataVariants(); - - private static IEnumerable CombineSourceDataWithBlockSize(IEnumerable 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 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[{itemsCount}]", testData, itemsCount }; - yield return new object[] { $"IEnumerable[{itemsCount}]", testData, itemsCount }; - yield return new object[] { $"IEnumerable[{itemsCount}] without non-enumerated count", new EnumerableWithoutCount(testData), itemsCount }; - yield return new object[] { $"IList[{itemsCount}]", new CustomIList(testData), itemsCount }; - yield return new object[] { $"IReadOnlyList[{itemsCount}])", testData, itemsCount }; - yield return new object[] { $"List[{itemsCount}]", testData.ToList(), itemsCount }; - yield return new object[] { $"ReadOnlySpan[{itemsCount}]", testData, itemsCount }; - yield return new object[] { $"RecyclableList[{itemsCount}]", testData.ToRecyclableList(), itemsCount }; - - foreach (var sourceBlockSize in BlockSizeVariants) - { - if (!IsValidBlockSize(itemsCount, sourceBlockSize)) - { - continue; - } - - yield return new object[] - { - $"RecyclableLongList[itemsCount: {itemsCount}, minBlockSize: {sourceBlockSize}]", - testData.ToRecyclableLongList(sourceBlockSize), - itemsCount - }; - } - - yield return new object[] { $"Span[{itemsCount}]", testData, itemsCount }; - yield return new object[] { $"T[{itemsCount}]", testData, itemsCount }; - break; - - case true: - IEnumerable 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(itemsCount: {itemsCount}", testRefData, itemsCount }; - yield return new object[] { $"IEnumerable(itemsCount: {itemsCount})", testRefData, itemsCount }; - yield return new object[] { $"IEnumerable(itemsCount: {itemsCount}) without non-enumerated count", new EnumerableWithoutCount(testRefData), itemsCount }; - yield return new object[] { $"IList(itemsCount: {itemsCount})", new CustomIList(testRefData), itemsCount }; - yield return new object[] { $"IReadOnlyList(itemsCount: {itemsCount})", testRefData, itemsCount }; - yield return new object[] { $"List(itemsCount: {itemsCount}", testRefData.ToList(), itemsCount }; - yield return new object[] { $"ReadOnlySpan[{itemsCount}]", testRefData, itemsCount }; - yield return new object[] { $"RecyclableList(itemsCount: {itemsCount})", testRefData.ToRecyclableList(), itemsCount }; - - foreach (var sourceBlockSize in BlockSizeVariants) - { - if (!IsValidBlockSize(itemsCount, sourceBlockSize)) - { - continue; - } - - yield return new object[] - { - $"RecyclableLongList(itemsCount: {itemsCount}, minBlockSize: {sourceBlockSize})", - testRefData.ToRecyclableLongList(sourceBlockSize), - itemsCount - }; - } - - yield return new object[] { $"Span[{itemsCount}]", testRefData, itemsCount }; - yield return new object[] { $"T[{itemsCount}]", testRefData, itemsCount }; - break; - } - } - - private static IEnumerable CreateSourceDataVariants(bool refType) - { - foreach (var itemsCount in ItemsCountVariants) - { - foreach (var variant in CreateSourceDataVariants(itemsCount, refType)) - { - yield return variant; - } - } - } - - public static IEnumerable EmptySourceDataVariants => CreateSourceDataVariants(0, false); - public static IEnumerable SourceDataVariants => CreateSourceDataVariants(false); - public static IEnumerable 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 SourceRefDataWithItemIndexVariants - { - get - { - IEnumerable 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 SourceDataWithBlockSizeVariants => CombineSourceDataWithBlockSize(SourceDataVariants); - public static IEnumerable SourceRefDataVariants => CreateSourceDataVariants(true); - public static IEnumerable SourceRefDataWithBlockSizeVariants { get; } = CombineSourceDataWithBlockSize(SourceRefDataVariants); - - private static IEnumerable _initialItemIndexVariants => new long[] { 0, 1, 2, 3, 4, 5 }; - private static IEnumerable CreateItemIndexVariants(long itemsCount, int blockSize) - { - IEnumerable 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 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 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 CombineSourceRefDataWithBlockSizeWithItemIndex(bool refType) - { - IEnumerable 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 SourceDataWithBlockSizeWithItemIndexVariants { get; } = CombineSourceRefDataWithBlockSizeWithItemIndex(false); - public static IEnumerable SourceRefDataWithBlockSizeWithItemIndexVariants { get; } = CombineSourceRefDataWithBlockSizeWithItemIndex(true); - } -} \ No newline at end of file diff --git a/Recyclable.CollectionsTests/RecyclableLongListTests.cs b/Recyclable.CollectionsTests/RecyclableLongListTests.cs index 9c74a9a..5f37dd1 100644 --- a/Recyclable.CollectionsTests/RecyclableLongListTests.cs +++ b/Recyclable.CollectionsTests/RecyclableLongListTests.cs @@ -1,5 +1,6 @@ using FluentAssertions; using Recyclable.Collections; +using Recyclable.Collections.TestData; using Recyclable.Collections.Linq; using System.Collections; using System.Numerics; diff --git a/logo.png b/logo.png new file mode 100644 index 0000000..da81460 Binary files /dev/null and b/logo.png differ