Collections.Benchmarks.Core package updated. Bug fixes. Logo added.

This commit is contained in:
mlemanczyk committed 2023-10-22 13:05:31 +02:00
1 parent fd38907eaa
commit 4f0102438e
17 files changed
+346 -67

No files matched your search

@@ -1,10 +1,12 @@
using Collections.Benchmarks.Core; using Collections.Benchmarks.Core;
namespace Recyclable.Collections.Benchmarks namespace Recyclable.Collections.Compatibility.List.Benchmarks
{ {
public class BinarySearchBenchmarks<T> : CollectionsBenchmarksBase<T> public class BinarySearchBenchmarks : RecyclableCollectionsCompatibilityListBenchmarks
{ {
public void Array_BinarySearch_BestAndWorstCases() public override string MethodNameSuffix => "_BinarySearch";
public void Array_BinarySearch()
{ {
var data = TestObjects; var data = TestObjects;
var list = TestObjects; var list = TestObjects;
@@ -16,7 +18,7 @@ namespace Recyclable.Collections.Benchmarks
} }
} }
public void List_BinarySearch_BestAndWorstCases() public void List_BinarySearch()
{ {
var data = TestObjects; var data = TestObjects;
var list = TestObjectsAsList; var list = TestObjectsAsList;
@@ -28,7 +30,7 @@ namespace Recyclable.Collections.Benchmarks
} }
} }
public void PooledList_BinarySearch_BestAndWorstCases() public void PooledList_BinarySearch()
{ {
var data = TestObjects; var data = TestObjects;
var list = TestObjectsAsPooledList; var list = TestObjectsAsPooledList;
@@ -40,7 +42,7 @@ namespace Recyclable.Collections.Benchmarks
} }
} }
public void RecyclableList_BinarySearch_BestAndWorstCases() public void RecyclableList_BinarySearch()
{ {
var data = TestObjects; var data = TestObjects;
var list = TestObjectsAsRecyclableList; var list = TestObjectsAsRecyclableList;
@@ -52,7 +54,7 @@ namespace Recyclable.Collections.Benchmarks
} }
} }
// public void RecyclableLongList_BinarySearch_BestAndWorstCases() // public void RecyclableLongList_BinarySearch()
// { // {
// var data = TestObjects; // var data = TestObjects;
// var list = TestObjectsAsRecyclableLongList; // var list = TestObjectsAsRecyclableLongList;
@@ -1,9 +1,11 @@
using Collections.Benchmarks.Core; using Collections.Benchmarks.Core;
namespace Recyclable.Collections.Benchmarks namespace Recyclable.Collections.Compatibility.List.Benchmarks
{ {
public class ConvertAllBenchmarks<T> : CollectionsBenchmarksBase<T> public class ConvertAllBenchmarks : RecyclableCollectionsCompatibilityListBenchmarks
{ {
public override string MethodNameSuffix => "_ConvertAll";
public void Array_ConvertAll() public void Array_ConvertAll()
{ {
var data = TestObjects; var data = TestObjects;
@@ -1,9 +1,11 @@
using Collections.Benchmarks.Core; using Collections.Benchmarks.Core;
namespace Recyclable.Collections.Benchmarks namespace Recyclable.Collections.Compatibility.List.Benchmarks
{ {
public partial class RecyclableCollectionsCompatibilityListBenchmarks public class ExistsBenchmarks : RecyclableCollectionsCompatibilityListBenchmarks
{ {
public override string MethodNameSuffix => "_Exists_BestAndWorstCases";
public void Array_Exists_BestAndWorstCases() public void Array_Exists_BestAndWorstCases()
{ {
var data = TestObjects; var data = TestObjects;
@@ -1,9 +1,11 @@
using Collections.Benchmarks.Core; using Collections.Benchmarks.Core;
namespace Recyclable.Collections.Benchmarks namespace Recyclable.Collections.Compatibility.List.Benchmarks
{ {
public partial class RecyclableCollectionsCompatibilityListBenchmarks public class FindAllBenchmarks : RecyclableCollectionsCompatibilityListBenchmarks
{ {
public override string MethodNameSuffix => "_FindAll_BestAndWorstCases";
public void Array_FindAll_BestAndWorstCases() public void Array_FindAll_BestAndWorstCases()
{ {
var data = TestObjects; var data = TestObjects;
@@ -1,9 +1,11 @@
using Collections.Benchmarks.Core; using Collections.Benchmarks.Core;
namespace Recyclable.Collections.Benchmarks namespace Recyclable.Collections.Compatibility.List.Benchmarks
{ {
public partial class RecyclableCollectionsCompatibilityListBenchmarks : CollectionsBenchmarksBase<CollectionsBenchmarksSource> public class FindLastIndexBenchmarks : RecyclableCollectionsCompatibilityListBenchmarks
{ {
public override string MethodNameSuffix => "_FindLastIndex_BestAndWorstCases";
public void Array_FindLastIndex_BestAndWorstCases() public void Array_FindLastIndex_BestAndWorstCases()
{ {
var data = TestObjects; var data = TestObjects;
@@ -1,9 +1,11 @@
using Collections.Benchmarks.Core; using Collections.Benchmarks.Core;
namespace Recyclable.Collections.Benchmarks namespace Recyclable.Collections.Compatibility.List.Benchmarks
{ {
public partial class RecyclableCollectionsCompatibilityListBenchmarks public class FindLastBenchmarks : RecyclableCollectionsCompatibilityListBenchmarks
{ {
public override string MethodNameSuffix => "_FindLast_BestAndWorstCases";
public void Array_FindLast_BestAndWorstCases() public void Array_FindLast_BestAndWorstCases()
{ {
var data = TestObjects; var data = TestObjects;
@@ -1,9 +1,11 @@
using Collections.Benchmarks.Core; using Collections.Benchmarks.Core;
namespace Recyclable.Collections.Benchmarks namespace Recyclable.Collections.Compatibility.List.Benchmarks
{ {
public partial class RecyclableCollectionsCompatibilityListBenchmarks public class FindBenchmarks: RecyclableCollectionsCompatibilityListBenchmarks
{ {
public override string MethodNameSuffix => "_Find_BestAndWorstCases";
public void Array_Find_BestAndWorstCases() public void Array_Find_BestAndWorstCases()
{ {
var data = TestObjects; var data = TestObjects;
@@ -1,2 +1,25 @@
// See https://aka.ms/new-console-template for more information using BenchmarkDotNet.Configs;
Console.WriteLine("Hello, World!"); using BenchmarkDotNet.Running;
namespace Recyclable.Collections.Compatibility.List.Benchmarks
{
public static class Program
{
static IConfig BenchmarkConfig { get; } = ManualConfig.Create(DefaultConfig.Instance)
.WithOptions(ConfigOptions.DisableOptimizationsValidator | ConfigOptions.JoinSummary);
static void Main()
{
BenchmarkRunner.Run(new[]
{
typeof(BinarySearchBenchmarks),
typeof(ConvertAllBenchmarks),
typeof(ExistsBenchmarks),
typeof(FindBenchmarks),
typeof(FindAllBenchmarks),
typeof(FindLastBenchmarks),
typeof(FindLastIndexBenchmarks)
}, BenchmarkConfig);
}
}
}
@@ -1,15 +1,19 @@
<Project Sdk="Microsoft.NET.Sdk"> <Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup> <PropertyGroup>
<OutputType>Exe</OutputType> <OutputType>Exe</OutputType>
<TargetFramework>net6.0</TargetFramework> <TargetFrameworks>net6.0;net7.0</TargetFrameworks>
<ImplicitUsings>enable</ImplicitUsings> <ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable> <Nullable>enable</Nullable>
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="Collections.Benchmarks.Core" Version="0.0.2" /> <PackageReference Include="Collections.Benchmarks.Core" Version="0.0.4" />
<PackageReference Include="Recyclable.Collections" Version="0.0.6" /> <PackageReference Include="Recyclable.Collections" Version="0.0.6.1" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\Recyclable.Collections.Compatibility.List\Recyclable.Collections.Compatibility.List.csproj" />
</ItemGroup> </ItemGroup>
</Project> </Project>
@@ -0,0 +1,23 @@
using BenchmarkDotNet.Attributes;
using Collections.Benchmarks.Core;
namespace Recyclable.Collections.Compatibility.List.Benchmarks
{
public partial class RecyclableCollectionsCompatibilityListBenchmarks : DataDrivenBenchmarksBase<CollectionsBenchmarksSource>
{
[Params(CollectionsBenchmarksSource.Array)]
public override CollectionsBenchmarksSource BaseDataType { get => base.BaseDataType; set => base.BaseDataType = value; }
[Params(
CollectionsBenchmarksSource.List,
CollectionsBenchmarksSource.PooledList,
CollectionsBenchmarksSource.RecyclableList
)]
public override CollectionsBenchmarksSource DataType { get => base.DataType; set => base.DataType = value; }
//[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(RecyclableDefaults.MinPooledArrayLength, RecyclableDefaults.MinItemsCountForParallelization)]
public override int TestObjectCount { get => base.TestObjectCount; set => base.TestObjectCount = value; }
}
}
@@ -12,8 +12,8 @@
<ItemGroup> <ItemGroup>
<PackageReference Include="FluentAssertions" Version="6.12.0" /> <PackageReference Include="FluentAssertions" Version="6.12.0" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.7.2" /> <PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.7.2" />
<PackageReference Include="Recyclable.Collections" Version="0.0.6" /> <PackageReference Include="Recyclable.Collections" Version="0.0.6.1" />
<PackageReference Include="Recyclable.Collections.TestData" Version="0.0.2" /> <PackageReference Include="Recyclable.Collections.TestData" Version="0.0.3.1" />
<PackageReference Include="xunit" Version="2.5.3" /> <PackageReference Include="xunit" Version="2.5.3" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.5.3"> <PackageReference Include="xunit.runner.visualstudio" Version="2.5.3">
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets> <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
@@ -25,4 +25,8 @@
</PackageReference> </PackageReference>
</ItemGroup> </ItemGroup>
<ItemGroup>
<ProjectReference Include="..\Recyclable.Collections.Compatibility.List\Recyclable.Collections.Compatibility.List.csproj" />
</ItemGroup>
</Project> </Project>
@@ -3,6 +3,7 @@ using Recyclable.Collections;
using Recyclable.Collections.TestData; using Recyclable.Collections.TestData;
using Recyclable.Collections.Pools; using Recyclable.Collections.Pools;
using System.Numerics; using System.Numerics;
using System.Collections;
#pragma warning disable xUnit1026, RCS1163, IDE0039, IDE0060, RCS1235 #pragma warning disable xUnit1026, RCS1163, IDE0039, IDE0060, RCS1235
@@ -201,6 +202,27 @@ namespace Recyclable.CollectionsTests
} }
} }
[Theory]
[MemberData(nameof(RecyclableLongListTestData.SourceDataWithItemIndexVariants), MemberType = typeof(RecyclableLongListTestData))]
public void FindIndexShouldNotAnythingWhenRangeExcludesItem(string testCase, IEnumerable<long> testData, int itemsCount, in long[] itemIndexes)
{
// Prepare
using var list = new RecyclableList<long>(testData, itemsCount);
var expectedData = testData.ToList();
foreach (var itemIndex in itemIndexes)
{
var expectedItem = expectedData[(int)itemIndex];
var expected = expectedData.FindIndex((int)itemIndex + 1, (int)(itemsCount - itemIndex - 1), item => item == expectedItem);
// Act
var actual = list.FindIndex((int)itemIndex + 1, (int)(itemsCount - itemIndex - 1), item => item == expectedItem);
// Validate
_ = actual.Should().Be(-1).And.Be(expected);
}
}
[Theory] [Theory]
[MemberData(nameof(RecyclableLongListTestData.SourceDataWithItemIndexVariants), MemberType = typeof(RecyclableLongListTestData))] [MemberData(nameof(RecyclableLongListTestData.SourceDataWithItemIndexVariants), MemberType = typeof(RecyclableLongListTestData))]
public void FindIndexShouldReturnCorrectIndexesWhenConstrainedIndex(string testCase, IEnumerable<long> testData, int itemsCount, in long[] itemIndexes) public void FindIndexShouldReturnCorrectIndexesWhenConstrainedIndex(string testCase, IEnumerable<long> testData, int itemsCount, in long[] itemIndexes)
@@ -475,6 +497,82 @@ namespace Recyclable.CollectionsTests
} }
} }
[Theory]
[MemberData(nameof(RecyclableLongListTestData.SourceDataWithItemIndexVariants), MemberType = typeof(RecyclableLongListTestData))]
public void InsertRangeShouldAddItemsInTheRightPosition(string testCase, IEnumerable<long> testData, int itemsCount, in long[] itemIndexes)
{
// Prepare
var expectedData = testData.Reverse().ToArray();
foreach (var itemIndex in itemIndexes)
{
using var list = new RecyclableList<long>(testData.Reverse(), itemsCount);
var expected = expectedData.ToList();
expected.InsertRange((int)itemIndex, testData);
if (testCase.Contains("Array[", StringComparison.OrdinalIgnoreCase))
{
list.InsertRange((int)itemIndex, (Array)testData);
}
else if (testCase.Contains("ICollection[", StringComparison.OrdinalIgnoreCase))
{
list.InsertRange((int)itemIndex, (ICollection)testData);
}
else if (testCase.Contains("ICollection<T>[", StringComparison.OrdinalIgnoreCase))
{
list.InsertRange((int)itemIndex, (ICollection<long>)testData);
}
else if (testCase.Contains("IEnumerable[", StringComparison.OrdinalIgnoreCase))
{
list.InsertRange((int)itemIndex, (IEnumerable)testData);
}
else if (testCase.Contains("IReadOnlyList<T>[", StringComparison.OrdinalIgnoreCase))
{
list.InsertRange((int)itemIndex, (IReadOnlyList<long>)testData);
}
else if (testCase.Contains("ReadOnlySpan<T>[", StringComparison.OrdinalIgnoreCase))
{
list.InsertRange((int)itemIndex, new ReadOnlySpan<long>((long[])testData));
}
else if (testCase.Contains("Span<T>[", StringComparison.OrdinalIgnoreCase))
{
list.InsertRange((int)itemIndex, new Span<long>((long[])testData));
}
else if (testData is long[] testDataArray)
{
list.InsertRange((int)itemIndex, testDataArray);
}
else if (testData is List<long> testDataList)
{
list.InsertRange((int)itemIndex, testDataList);
}
else if (testData is RecyclableList<long> testDataRecyclableList)
{
list.InsertRange((int)itemIndex, testDataRecyclableList);
}
else if (testData is RecyclableLongList<long> testDataRecyclableLongList)
{
list.InsertRange((int)itemIndex, testDataRecyclableLongList);
}
else if (testData is IList<long> testDataIList)
{
list.InsertRange((int)itemIndex, testDataIList);
}
else if (testData is IEnumerable<long> testDataIEnumerable)
{
list.InsertRange((int)itemIndex, testDataIEnumerable);
}
else
{
throw new InvalidCastException("Unknown type of test data");
}
// Validate
list.Count.Should().Be(itemsCount << 1);
_ = list.Should().Equal(expected);
}
}
[Theory] [Theory]
[MemberData(nameof(RecyclableLongListTestData.SourceDataWithItemIndexVariants), MemberType = typeof(RecyclableLongListTestData))] [MemberData(nameof(RecyclableLongListTestData.SourceDataWithItemIndexVariants), MemberType = typeof(RecyclableLongListTestData))]
public void LastIndexOfShouldReturnCorrectIndexes(string testCase, IEnumerable<long> testData, int itemsCount, in long[] itemIndexes) public void LastIndexOfShouldReturnCorrectIndexes(string testCase, IEnumerable<long> testData, int itemsCount, in long[] itemIndexes)
@@ -564,7 +662,62 @@ namespace Recyclable.CollectionsTests
expectedItems.InsertRange((int)itemIndex, testData); expectedItems.InsertRange((int)itemIndex, testData);
// Act // Act
list.InsertRange((int)itemIndex, testData); if (testCase.Contains("Array[", StringComparison.OrdinalIgnoreCase))
{
list.InsertRange((int)itemIndex, (Array)testData);
}
else if (testCase.Contains("ICollection[", StringComparison.OrdinalIgnoreCase))
{
list.InsertRange((int)itemIndex, (ICollection)testData);
}
else if (testCase.Contains("ICollection<T>[", StringComparison.OrdinalIgnoreCase))
{
list.InsertRange((int)itemIndex, (ICollection<long>)testData);
}
else if (testCase.Contains("IEnumerable[", StringComparison.OrdinalIgnoreCase))
{
list.InsertRange((int)itemIndex, (IEnumerable)testData);
}
else if (testCase.Contains("IReadOnlyList<T>[", StringComparison.OrdinalIgnoreCase))
{
list.InsertRange((int)itemIndex, (IReadOnlyList<long>)testData);
}
else if (testCase.Contains("ReadOnlySpan<T>[", StringComparison.OrdinalIgnoreCase))
{
list.InsertRange((int)itemIndex, new ReadOnlySpan<long>((long[])testData));
}
else if (testCase.Contains("Span<T>[", StringComparison.OrdinalIgnoreCase))
{
list.InsertRange((int)itemIndex, new Span<long>((long[])testData));
}
else if (testData is long[] testDataArray)
{
list.InsertRange((int)itemIndex, testDataArray);
}
else if (testData is List<long> testDataList)
{
list.InsertRange((int)itemIndex, testDataList);
}
else if (testData is RecyclableList<long> testDataRecyclableList)
{
list.InsertRange((int)itemIndex, testDataRecyclableList);
}
else if (testData is RecyclableLongList<long> testDataRecyclableLongList)
{
list.InsertRange((int)itemIndex, testDataRecyclableLongList);
}
else if (testData is IList<long> testDataIList)
{
list.InsertRange((int)itemIndex, testDataIList);
}
else if (testData is IEnumerable<long> testDataIEnumerable)
{
list.InsertRange((int)itemIndex, testDataIEnumerable);
}
else
{
throw new InvalidCastException("Unknown type of test data");
}
// Validate // Validate
_ = list[(int)itemIndex].Should().Be(item); _ = list[(int)itemIndex].Should().Be(item);
+15 -1
View File
@@ -7,26 +7,40 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Recyclable.Collections.Comp
EndProject EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Recyclable.Collections.Compatibility.List.Tests", "Recyclable.Collections.Compatibility.List.Tests\Recyclable.Collections.Compatibility.List.Tests.csproj", "{1501C2BD-BDAF-4C89-B131-16C7D9C1B41B}" Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Recyclable.Collections.Compatibility.List.Tests", "Recyclable.Collections.Compatibility.List.Tests\Recyclable.Collections.Compatibility.List.Tests.csproj", "{1501C2BD-BDAF-4C89-B131-16C7D9C1B41B}"
EndProject EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Recyclable.Collections.Compatibility.List.Benchmarks", "Recyclable.Collections.Compatibility.List.Benchmarks\Recyclable.Collections.Compatibility.List.Benchmarks.csproj", "{A1414948-E61B-4AE1-ACAF-33A8BB85041E}" Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Recyclable.Collections.Compatibility.List.Benchmarks", "Recyclable.Collections.Compatibility.List.Benchmarks\Recyclable.Collections.Compatibility.List.Benchmarks.csproj", "{A1414948-E61B-4AE1-ACAF-33A8BB85041E}"
EndProject EndProject
Global Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU Debug|Any CPU = Debug|Any CPU
Debug|x64 = Debug|x64
Release|Any CPU = Release|Any CPU Release|Any CPU = Release|Any CPU
Release|x64 = Release|x64
EndGlobalSection EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution GlobalSection(ProjectConfigurationPlatforms) = postSolution
{779028EF-0584-4566-A80D-B5F3D6E25DD0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {779028EF-0584-4566-A80D-B5F3D6E25DD0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{779028EF-0584-4566-A80D-B5F3D6E25DD0}.Debug|Any CPU.Build.0 = Debug|Any CPU {779028EF-0584-4566-A80D-B5F3D6E25DD0}.Debug|Any CPU.Build.0 = Debug|Any CPU
{779028EF-0584-4566-A80D-B5F3D6E25DD0}.Debug|x64.ActiveCfg = Debug|x64
{779028EF-0584-4566-A80D-B5F3D6E25DD0}.Debug|x64.Build.0 = Debug|x64
{779028EF-0584-4566-A80D-B5F3D6E25DD0}.Release|Any CPU.ActiveCfg = Release|Any CPU {779028EF-0584-4566-A80D-B5F3D6E25DD0}.Release|Any CPU.ActiveCfg = Release|Any CPU
{779028EF-0584-4566-A80D-B5F3D6E25DD0}.Release|Any CPU.Build.0 = Release|Any CPU {779028EF-0584-4566-A80D-B5F3D6E25DD0}.Release|Any CPU.Build.0 = Release|Any CPU
{779028EF-0584-4566-A80D-B5F3D6E25DD0}.Release|x64.ActiveCfg = Release|x64
{779028EF-0584-4566-A80D-B5F3D6E25DD0}.Release|x64.Build.0 = Release|x64
{1501C2BD-BDAF-4C89-B131-16C7D9C1B41B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {1501C2BD-BDAF-4C89-B131-16C7D9C1B41B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{1501C2BD-BDAF-4C89-B131-16C7D9C1B41B}.Debug|Any CPU.Build.0 = Debug|Any CPU {1501C2BD-BDAF-4C89-B131-16C7D9C1B41B}.Debug|Any CPU.Build.0 = Debug|Any CPU
{1501C2BD-BDAF-4C89-B131-16C7D9C1B41B}.Debug|x64.ActiveCfg = Debug|Any CPU
{1501C2BD-BDAF-4C89-B131-16C7D9C1B41B}.Debug|x64.Build.0 = Debug|Any CPU
{1501C2BD-BDAF-4C89-B131-16C7D9C1B41B}.Release|Any CPU.ActiveCfg = Release|Any CPU {1501C2BD-BDAF-4C89-B131-16C7D9C1B41B}.Release|Any CPU.ActiveCfg = Release|Any CPU
{1501C2BD-BDAF-4C89-B131-16C7D9C1B41B}.Release|Any CPU.Build.0 = Release|Any CPU {1501C2BD-BDAF-4C89-B131-16C7D9C1B41B}.Release|Any CPU.Build.0 = Release|Any CPU
{1501C2BD-BDAF-4C89-B131-16C7D9C1B41B}.Release|x64.ActiveCfg = Release|Any CPU
{1501C2BD-BDAF-4C89-B131-16C7D9C1B41B}.Release|x64.Build.0 = Release|Any CPU
{A1414948-E61B-4AE1-ACAF-33A8BB85041E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {A1414948-E61B-4AE1-ACAF-33A8BB85041E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{A1414948-E61B-4AE1-ACAF-33A8BB85041E}.Debug|Any CPU.Build.0 = Debug|Any CPU {A1414948-E61B-4AE1-ACAF-33A8BB85041E}.Debug|Any CPU.Build.0 = Debug|Any CPU
{A1414948-E61B-4AE1-ACAF-33A8BB85041E}.Debug|x64.ActiveCfg = Debug|Any CPU
{A1414948-E61B-4AE1-ACAF-33A8BB85041E}.Debug|x64.Build.0 = Debug|Any CPU
{A1414948-E61B-4AE1-ACAF-33A8BB85041E}.Release|Any CPU.ActiveCfg = Release|Any CPU {A1414948-E61B-4AE1-ACAF-33A8BB85041E}.Release|Any CPU.ActiveCfg = Release|Any CPU
{A1414948-E61B-4AE1-ACAF-33A8BB85041E}.Release|Any CPU.Build.0 = Release|Any CPU {A1414948-E61B-4AE1-ACAF-33A8BB85041E}.Release|Any CPU.Build.0 = Release|Any CPU
{A1414948-E61B-4AE1-ACAF-33A8BB85041E}.Release|x64.ActiveCfg = Release|Any CPU
{A1414948-E61B-4AE1-ACAF-33A8BB85041E}.Release|x64.Build.0 = Release|Any CPU
EndGlobalSection EndGlobalSection
GlobalSection(SolutionProperties) = preSolution GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE HideSolutionNode = FALSE
@@ -6,7 +6,7 @@
<Nullable>enable</Nullable> <Nullable>enable</Nullable>
<GeneratePackageOnBuild>true</GeneratePackageOnBuild> <GeneratePackageOnBuild>true</GeneratePackageOnBuild>
<PackageId>Recyclable.Collections.Compatibility.List</PackageId> <PackageId>Recyclable.Collections.Compatibility.List</PackageId>
<PackageVersion>0.0.1</PackageVersion> <PackageVersion>0.0.2</PackageVersion>
<Authors>Marek Lemańczyk</Authors> <Authors>Marek Lemańczyk</Authors>
<Company>N/A</Company> <Company>N/A</Company>
<Product>Recyclable.Collections.Compatibility.List</Product> <Product>Recyclable.Collections.Compatibility.List</Product>
@@ -18,8 +18,9 @@
<PackageLicenseFile>LICENSE.md</PackageLicenseFile> <PackageLicenseFile>LICENSE.md</PackageLicenseFile>
<PackageReadmeFile>README.md</PackageReadmeFile> <PackageReadmeFile>README.md</PackageReadmeFile>
<RepositoryType>git</RepositoryType> <RepositoryType>git</RepositoryType>
<PackageReleaseNotes>Support for RecyclableList&lt;T&gt; &amp; RecyclableLongList&lt;T&gt; added.</PackageReleaseNotes> <PackageReleaseNotes>Collections.Benchmarks.Core package updated. Bug fixes.</PackageReleaseNotes>
<Platforms>AnyCPU;x64</Platforms> <Platforms>AnyCPU;x64</Platforms>
<PackageIcon>logo.png</PackageIcon>
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
@@ -36,6 +37,6 @@
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="Recyclable.Collections" Version="0.0.6" /> <PackageReference Include="Recyclable.Collections" Version="0.0.6.1" />
</ItemGroup> </ItemGroup>
</Project> </Project>
@@ -117,13 +117,12 @@ namespace Recyclable.Collections
public static int FindIndex<T>(this RecyclableList<T> list, int startIndex, int count, Predicate<T> match) public static int FindIndex<T>(this RecyclableList<T> list, int startIndex, int count, Predicate<T> match)
{ {
int sourceItemsCount = list._count; int sourceItemsCount = Math.Min(startIndex + count, list._count);
if (sourceItemsCount == 0 || startIndex >= sourceItemsCount) if (sourceItemsCount == 0 || startIndex >= sourceItemsCount)
{ {
return RecyclableDefaults.ItemNotFoundIndex; return RecyclableDefaults.ItemNotFoundIndex;
} }
sourceItemsCount = Math.Min(sourceItemsCount, startIndex + sourceItemsCount);
ReadOnlySpan<T> sourceSpan = list._memoryBlock; ReadOnlySpan<T> sourceSpan = list._memoryBlock;
for (var itemIndex = startIndex; itemIndex < sourceItemsCount; itemIndex++) for (var itemIndex = startIndex; itemIndex < sourceItemsCount; itemIndex++)
{ {
@@ -74,6 +74,7 @@ namespace Recyclable.Collections
{ {
list._capacity = RecyclableListHelpers<T>.EnsureCapacity(list, currentItemsCount, checked((int)BitOperations.RoundUpToPowerOf2((uint)(currentItemsCount + requiredAdditionalCapacity)))); list._capacity = RecyclableListHelpers<T>.EnsureCapacity(list, currentItemsCount, checked((int)BitOperations.RoundUpToPowerOf2((uint)(currentItemsCount + requiredAdditionalCapacity))));
// TODO: Count should be requiredAdditionalCapacity, we need to move as many items as many we're inserting
Array.Copy(list._memoryBlock, index, list._memoryBlock, index + requiredAdditionalCapacity, list._count - index); Array.Copy(list._memoryBlock, index, list._memoryBlock, index + requiredAdditionalCapacity, list._count - index);
Span<T> memorySpan = list._memoryBlock; Span<T> memorySpan = list._memoryBlock;
foreach (var item in items) foreach (var item in items)
@@ -94,6 +95,7 @@ namespace Recyclable.Collections
} }
T[] memoryBlock = list._memoryBlock; T[] memoryBlock = list._memoryBlock;
// TODO: Count should be items.Count, we need to move as many items as many we're inserting
Array.Copy(memoryBlock, index, memoryBlock, index + items.Length, list._count - index); Array.Copy(memoryBlock, index, memoryBlock, index + items.Length, list._count - index);
Array.Copy(items, items.GetLowerBound(0), memoryBlock, index, items.Length); Array.Copy(items, items.GetLowerBound(0), memoryBlock, index, items.Length);
list._count += items.Length; list._count += items.Length;
@@ -109,6 +111,7 @@ namespace Recyclable.Collections
} }
T[] memoryBlock = list._memoryBlock; T[] memoryBlock = list._memoryBlock;
// TODO: Count should be items.Count, we need to move as many items as many we're inserting
Array.Copy(memoryBlock, index, memoryBlock, index + items.Length, list._count - index); Array.Copy(memoryBlock, index, memoryBlock, index + items.Length, list._count - index);
new ReadOnlySpan<T>(items).CopyTo(new Span<T>(memoryBlock, index, items.Length)); new ReadOnlySpan<T>(items).CopyTo(new Span<T>(memoryBlock, index, items.Length));
list._count += items.Length; list._count += items.Length;
@@ -124,6 +127,7 @@ namespace Recyclable.Collections
} }
T[] memoryBlock = list._memoryBlock; T[] memoryBlock = list._memoryBlock;
// TODO: Count should be items.Count, we need to move as many items as many we're inserting
Array.Copy(memoryBlock, index, memoryBlock, index + items.Length, list._count - index); Array.Copy(memoryBlock, index, memoryBlock, index + items.Length, list._count - index);
items.CopyTo(new Span<T>(memoryBlock, index, items.Length)); items.CopyTo(new Span<T>(memoryBlock, index, items.Length));
list._count += items.Length; list._count += items.Length;
@@ -139,6 +143,7 @@ namespace Recyclable.Collections
} }
T[] memoryBlock = list._memoryBlock; T[] memoryBlock = list._memoryBlock;
// TODO: Count should be items.Count, we need to move as many items as many we're inserting
Array.Copy(memoryBlock, index, memoryBlock, index + items.Length, list._count - index); Array.Copy(memoryBlock, index, memoryBlock, index + items.Length, list._count - index);
items.CopyTo(new Span<T>(memoryBlock, index, items.Length)); items.CopyTo(new Span<T>(memoryBlock, index, items.Length));
list._count += items.Length; list._count += items.Length;
@@ -154,6 +159,7 @@ namespace Recyclable.Collections
} }
T[] memoryBlock = list._memoryBlock; T[] memoryBlock = list._memoryBlock;
// TODO: Count should be items.Count, we need to move as many items as many we're inserting
Array.Copy(memoryBlock, index, memoryBlock, index + items.Count, list._count - index); Array.Copy(memoryBlock, index, memoryBlock, index + items.Count, list._count - index);
items.CopyTo(memoryBlock, index); items.CopyTo(memoryBlock, index);
list._count += items.Count; list._count += items.Count;
@@ -169,6 +175,7 @@ namespace Recyclable.Collections
} }
T[] memoryBlock = list._memoryBlock; T[] memoryBlock = list._memoryBlock;
// TODO: Count should be items.Count, we need to move as many items as many we're inserting
Array.Copy(memoryBlock, index, memoryBlock, index + items.Count, list._count - index); Array.Copy(memoryBlock, index, memoryBlock, index + items.Count, list._count - index);
items.CopyTo(list._memoryBlock, index); items.CopyTo(list._memoryBlock, index);
list._count += items.Count; list._count += items.Count;
@@ -184,6 +191,7 @@ namespace Recyclable.Collections
} }
T[] memoryBlock = list._memoryBlock; T[] memoryBlock = list._memoryBlock;
// TODO: Count should be items.Count, we need to move as many items as many we're inserting
Array.Copy(memoryBlock, index, memoryBlock, index + items.Count, list._count - index); Array.Copy(memoryBlock, index, memoryBlock, index + items.Count, list._count - index);
items.CopyTo(memoryBlock, index); items.CopyTo(memoryBlock, index);
list._count += items.Count; list._count += items.Count;
@@ -199,6 +207,7 @@ namespace Recyclable.Collections
} }
T[] memoryBlock = list._memoryBlock; T[] memoryBlock = list._memoryBlock;
// TODO: Count should be items.Count, we need to move as many items as many we're inserting
Array.Copy(memoryBlock, index, memoryBlock, index + items.Count, list._count - index); Array.Copy(memoryBlock, index, memoryBlock, index + items.Count, list._count - index);
new ReadOnlySpan<T>(items._memoryBlock, 0, items._count).CopyTo(new(list._memoryBlock, index, items._count)); new ReadOnlySpan<T>(items._memoryBlock, 0, items._count).CopyTo(new(list._memoryBlock, index, items._count));
list._count += items._count; list._count += items._count;
@@ -257,43 +266,64 @@ namespace Recyclable.Collections
list._version++; list._version++;
} }
public static IEnumerator InsertRange<T>(this RecyclableList<T> list, int index, IEnumerable source, int growByCount = RecyclableDefaults.MinPooledArrayLength) public static void InsertRange<T>(this RecyclableList<T> list, int index, IEnumerable items, int growByCount = RecyclableDefaults.MinPooledArrayLength)
{ {
int targetItemIndex = list._count; var enumerator = items.GetEnumerator();
Span<T> memorySpan; if (!enumerator.MoveNext())
int i;
var enumerator = source.GetEnumerator();
int capacity = list._capacity;
memorySpan = list._memoryBlock;
if (enumerator.MoveNext())
{ {
int available = capacity - targetItemIndex; return;
do
{
if (targetItemIndex + growByCount > capacity)
{
capacity = RecyclableListHelpers<T>.EnsureCapacity(list, targetItemIndex, checked((int)BitOperations.RoundUpToPowerOf2((uint)(targetItemIndex + growByCount))));
memorySpan = list._memoryBlock;
available = capacity - targetItemIndex;
}
for (i = 0; i < available; i++)
{
memorySpan[targetItemIndex++] = (T)enumerator.Current;
if (!enumerator.MoveNext())
{
break;
}
}
}
while (i >= available);
} }
int capacity = list._capacity,
added = 0,
available = capacity - list._count,
i,
movingBlockLength = list._count - index;
T[] memoryBlock = list._memoryBlock;
if (available > 0)
{
Array.Copy(memoryBlock, index, memoryBlock, capacity - movingBlockLength, movingBlockLength);
}
Span<T> memorySpan = memoryBlock;
do
{
if (index + available + movingBlockLength > capacity)
{
var capacityBeforeIncrease = capacity;
capacity = checked((int)BitOperations.RoundUpToPowerOf2((uint)(capacity + growByCount)));
_ = RecyclableListHelpers<T>.EnsureCapacity(list, memoryBlock.Length, capacity);
memorySpan = memoryBlock = list._memoryBlock;
available = capacity - index - movingBlockLength;
Array.Copy(memoryBlock, capacityBeforeIncrease - movingBlockLength, memoryBlock, capacity - movingBlockLength, movingBlockLength);
}
for (i = 0; i < available; i++)
{
memorySpan[index++] = (T)enumerator.Current;
if (!enumerator.MoveNext())
{
added++;
break;
}
}
added += i;
}
while (i == available);
if (i != available)
{
Array.Copy(memoryBlock, capacity - movingBlockLength, memoryBlock, index, movingBlockLength);
if (RecyclableList<T>._needsClearing)
{
Array.Clear(memoryBlock, capacity - movingBlockLength, movingBlockLength);
}
}
list._count += added;
list._capacity = capacity; list._capacity = capacity;
list._count = targetItemIndex;
return enumerator;
} }
public static void InsertRange<T>(this RecyclableList<T> list, int index, IReadOnlyList<T> items) public static void InsertRange<T>(this RecyclableList<T> list, int index, IReadOnlyList<T> items)
@@ -304,7 +334,8 @@ namespace Recyclable.Collections
list._capacity = RecyclableListHelpers<T>.EnsureCapacity(list, list._count, checked((int)BitOperations.RoundUpToPowerOf2((uint)(list._count + sourceItemsCount)))); list._capacity = RecyclableListHelpers<T>.EnsureCapacity(list, list._count, checked((int)BitOperations.RoundUpToPowerOf2((uint)(list._count + sourceItemsCount))));
} }
Span<T> memorySpan = new(list._memoryBlock, list._count, sourceItemsCount); Array.Copy(list._memoryBlock, index, list._memoryBlock, index + sourceItemsCount, Math.Min(list.Count - index, sourceItemsCount));
Span<T> memorySpan = new(list._memoryBlock, index, sourceItemsCount);
for (var sourceItemIndex = 0; sourceItemIndex < sourceItemsCount; sourceItemIndex++) for (var sourceItemIndex = 0; sourceItemIndex < sourceItemsCount; sourceItemIndex++)
{ {
memorySpan[sourceItemIndex] = items[sourceItemIndex]; memorySpan[sourceItemIndex] = items[sourceItemIndex];
@@ -2,6 +2,7 @@
using System.Collections.ObjectModel; using System.Collections.ObjectModel;
using System.Numerics; using System.Numerics;
using System.Runtime.CompilerServices;
using Recyclable.Collections.Pools; using Recyclable.Collections.Pools;
namespace Recyclable.Collections namespace Recyclable.Collections
@@ -13,12 +14,15 @@ namespace Recyclable.Collections
{ {
public static ReadOnlyCollection<T> AsReadOnly<T>(this RecyclableList<T> list) => new(list); public static ReadOnlyCollection<T> AsReadOnly<T>(this RecyclableList<T> list) => new(list);
[MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)]
public static int BinarySearch<T>(this RecyclableList<T> list, T item) public static int BinarySearch<T>(this RecyclableList<T> list, T item)
=> Array.BinarySearch(list._memoryBlock, 0, list._count, item); => Array.BinarySearch(list._memoryBlock, 0, list._count, item);
[MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)]
public static int BinarySearch<T>(this RecyclableList<T> list, T item, IComparer<T>? comparer) public static int BinarySearch<T>(this RecyclableList<T> list, T item, IComparer<T>? comparer)
=> Array.BinarySearch(list._memoryBlock, 0, list._count, item, comparer); => Array.BinarySearch(list._memoryBlock, 0, list._count, item, comparer);
[MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)]
public static int BinarySearch<T>(this RecyclableList<T> list, int index, int count, T item, IComparer<T>? comparer) public static int BinarySearch<T>(this RecyclableList<T> list, int index, int count, T item, IComparer<T>? comparer)
=> Array.BinarySearch(list._memoryBlock, index, count, item, comparer); => Array.BinarySearch(list._memoryBlock, index, count, item, comparer);
@@ -42,8 +46,10 @@ namespace Recyclable.Collections
return result; return result;
} }
[MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)]
public static void CopyTo<T>(this RecyclableList<T> list, T[] array) => Array.Copy(list._memoryBlock, array, list._count); public static void CopyTo<T>(this RecyclableList<T> list, T[] array) => Array.Copy(list._memoryBlock, array, list._count);
[MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)]
public static void CopyTo<T>(this RecyclableList<T> list, int index, T[] array, int arrayIndex, int count) => Array.Copy(list._memoryBlock, index, array, arrayIndex, count); public static void CopyTo<T>(this RecyclableList<T> list, int index, T[] array, int arrayIndex, int count) => Array.Copy(list._memoryBlock, index, array, arrayIndex, count);
public static void ForEach<T>(this RecyclableList<T> list, Action<T> action) public static void ForEach<T>(this RecyclableList<T> list, Action<T> action)
@@ -131,42 +137,49 @@ namespace Recyclable.Collections
list._version++; list._version++;
} }
[MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)]
public static void Reverse<T>(this RecyclableList<T> list) public static void Reverse<T>(this RecyclableList<T> list)
{ {
Array.Reverse(list._memoryBlock, 0, list._count); Array.Reverse(list._memoryBlock, 0, list._count);
list._version++; list._version++;
} }
[MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)]
public static void Reverse<T>(this RecyclableList<T> list, int index, int count) public static void Reverse<T>(this RecyclableList<T> list, int index, int count)
{ {
Array.Reverse(list._memoryBlock, index, count); Array.Reverse(list._memoryBlock, index, count);
list._version++; list._version++;
} }
[MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)]
public static void Sort<T>(this RecyclableList<T> list) public static void Sort<T>(this RecyclableList<T> list)
{ {
Array.Sort(list._memoryBlock, 0, list._count); Array.Sort(list._memoryBlock, 0, list._count);
list._version++; list._version++;
} }
[MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)]
public static void Sort<T>(this RecyclableList<T> list, Comparison<T> comparison) public static void Sort<T>(this RecyclableList<T> list, Comparison<T> comparison)
{ {
Array.Sort(list._memoryBlock, 0, list._count, new ComparisonToComparerAdapter<T>(comparison)); Array.Sort(list._memoryBlock, 0, list._count, new ComparisonToComparerAdapter<T>(comparison));
list._version++; list._version++;
} }
[MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)]
public static void Sort<T>(this RecyclableList<T> list, IComparer<T>? comparer) public static void Sort<T>(this RecyclableList<T> list, IComparer<T>? comparer)
{ {
Array.Sort(list._memoryBlock, 0, list._count, comparer); Array.Sort(list._memoryBlock, 0, list._count, comparer);
list._version++; list._version++;
} }
[MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)]
public static void Sort<T>(this RecyclableList<T> list, int index, int count, IComparer<T>? comparer) public static void Sort<T>(this RecyclableList<T> list, int index, int count, IComparer<T>? comparer)
{ {
Array.Sort(list._memoryBlock, index, count, comparer); Array.Sort(list._memoryBlock, index, count, comparer);
list._version++; list._version++;
} }
[MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)]
public static T[] ToArray<T>(this RecyclableList<T> list) public static T[] ToArray<T>(this RecyclableList<T> list)
{ {
T[] result = new T[list._count]; T[] result = new T[list._count];