Skip to content

Commit 89b6688

Browse files
committed
merged
2 parents efe426d + 071d6cc commit 89b6688

15 files changed

+666
-0
lines changed

SpanExtensions.sln

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SpanExtensions", "src\SpanE
77
EndProject
88
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "UnitTests", "tests\unit-tests\UnitTests.csproj", "{B48A0293-A7FF-4E39-8F8D-57B6F824D70F}"
99
EndProject
10+
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "PerformanceTests", "tests\Performance\PerformanceTests.csproj", "{CE74F420-1038-4E51-AC31-00DA964CC4F5}"
11+
EndProject
1012
Global
1113
GlobalSection(SolutionConfigurationPlatforms) = preSolution
1214
Debug|Any CPU = Debug|Any CPU
@@ -21,6 +23,10 @@ Global
2123
{B48A0293-A7FF-4E39-8F8D-57B6F824D70F}.Debug|Any CPU.Build.0 = Debug|Any CPU
2224
{B48A0293-A7FF-4E39-8F8D-57B6F824D70F}.Release|Any CPU.ActiveCfg = Release|Any CPU
2325
{B48A0293-A7FF-4E39-8F8D-57B6F824D70F}.Release|Any CPU.Build.0 = Release|Any CPU
26+
{CE74F420-1038-4E51-AC31-00DA964CC4F5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
27+
{CE74F420-1038-4E51-AC31-00DA964CC4F5}.Debug|Any CPU.Build.0 = Debug|Any CPU
28+
{CE74F420-1038-4E51-AC31-00DA964CC4F5}.Release|Any CPU.ActiveCfg = Release|Any CPU
29+
{CE74F420-1038-4E51-AC31-00DA964CC4F5}.Release|Any CPU.Build.0 = Release|Any CPU
2430
EndGlobalSection
2531
GlobalSection(SolutionProperties) = preSolution
2632
HideSolutionNode = FALSE
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
<Project Sdk="Microsoft.NET.Sdk">
2+
3+
<PropertyGroup>
4+
<OutputType>Exe</OutputType>
5+
<TargetFramework>net8.0</TargetFramework>
6+
<ImplicitUsings>enable</ImplicitUsings>
7+
<Nullable>enable</Nullable>
8+
</PropertyGroup>
9+
10+
<ItemGroup>
11+
<PackageReference Include="BenchmarkDotNet" Version="0.13.12" />
12+
</ItemGroup>
13+
14+
15+
<ItemGroup>
16+
<ProjectReference Include="..\..\src\SpanExtensions.csproj" />
17+
</ItemGroup>
18+
19+
</Project>

tests/Performance/Program.cs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
using BenchmarkDotNet.Running;
2+
3+
BenchmarkSwitcher.FromAssembly(typeof(Program).Assembly).Run(args);
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
using BenchmarkDotNet.Attributes;
2+
3+
namespace SpanExtensions.Tests.Performance;
4+
5+
[MemoryDiagnoser(false)]
6+
public class ReadOnlySpan_Split_Benchmark
7+
{
8+
[Benchmark]
9+
[ArgumentsSource(nameof(GetArgsWithDelimiter))]
10+
public int Split_ReadOnlySpan(ReadOnlySpan<char> value, char delimiter)
11+
{
12+
int length = 0;
13+
14+
foreach(ReadOnlySpan<char> part in value.Split(delimiter))
15+
{
16+
length += part.Length;
17+
}
18+
19+
return length;
20+
}
21+
22+
[Benchmark(Baseline = true)]
23+
[ArgumentsSource(nameof(GetArgsWithDelimiter))]
24+
public int Split_String(string value, char delimiter)
25+
{
26+
int length = 0;
27+
28+
foreach(string part in value.Split(delimiter))
29+
{
30+
length += part.Length;
31+
}
32+
33+
return length;
34+
}
35+
36+
public IEnumerable<object[]> GetArgsWithDelimiter()
37+
{
38+
yield return new object[] { "xyz", 'y' };
39+
yield return new object[] { "abcde", 'c' };
40+
yield return new object[] { "abcdefg", 'd' };
41+
yield return new object[] { "abba", 'b' };
42+
yield return new object[] { "aaa", 'a' };
43+
yield return new object[] { "aba", 'a' };
44+
yield return new object[] { "12131415161718190", '1' };
45+
}
46+
}
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
using BenchmarkDotNet.Attributes;
2+
3+
namespace SpanExtensions.Tests.Performance;
4+
5+
[MemoryDiagnoser(false)]
6+
public class ReadOnlySpan_Split_Count_Benchmark
7+
{
8+
[Benchmark]
9+
[ArgumentsSource(nameof(GetArgsWithDelimiterAndCount))]
10+
public int Split_ReadOnlySpan(ReadOnlySpan<char> value, char delimiter, int count)
11+
{
12+
int length = 0;
13+
14+
foreach(ReadOnlySpan<char> part in value.Split(delimiter, count))
15+
{
16+
length += part.Length;
17+
}
18+
19+
return length;
20+
}
21+
22+
[Benchmark(Baseline = true)]
23+
[ArgumentsSource(nameof(GetArgsWithDelimiterAndCount))]
24+
public int Split_String(string value, char delimiter, int count)
25+
{
26+
int length = 0;
27+
28+
foreach(string part in value.Split(delimiter, count))
29+
{
30+
length += part.Length;
31+
}
32+
33+
return length;
34+
}
35+
36+
[Benchmark]
37+
[ArgumentsSource(nameof(GetArgsWithDelimiterAndCount))]
38+
public int Split_CutLastElements_ReadOnlySpan(ReadOnlySpan<char> value, char delimiter, int count)
39+
{
40+
int length = 0;
41+
42+
foreach(ReadOnlySpan<char> part in value.Split(delimiter, count, CountExceedingBehaviour.CutLastElements))
43+
{
44+
length += part.Length;
45+
}
46+
47+
return length;
48+
}
49+
50+
public IEnumerable<object[]> GetArgsWithDelimiterAndCount()
51+
{
52+
yield return ["xyz", 'y', 1];
53+
yield return ["aba", 'a', 2];
54+
yield return ["12131415161718190", '1', 3];
55+
yield return ["12131415161718190", '1', 2];
56+
yield return ["12131415161718190", '1', 7];
57+
}
58+
}
Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
using BenchmarkDotNet.Attributes;
2+
3+
namespace SpanExtensions.Tests.Performance;
4+
5+
[MemoryDiagnoser(false)]
6+
public class ReadOnlySpan_Split_Count_StringSplitOptions_Benchmark
7+
{
8+
[Benchmark]
9+
[ArgumentsSource(nameof(GetArgsWithDelimiterAndCountAndStringSplitOptions))]
10+
public int Split_Count_StringSplitOptions_ReadOnlySpan(ReadOnlySpan<char> value, char delimiter, int count, StringSplitOptions options)
11+
{
12+
int length = 0;
13+
14+
foreach(ReadOnlySpan<char> part in value.Split(delimiter, count, options))
15+
{
16+
length += part.Length;
17+
}
18+
19+
return length;
20+
}
21+
22+
[Benchmark(Baseline = true)]
23+
[ArgumentsSource(nameof(GetArgsWithDelimiterAndCountAndStringSplitOptions))]
24+
public int Split_Count_StringSplitOptions_String(string value, char delimiter, int count, StringSplitOptions options)
25+
{
26+
int length = 0;
27+
28+
foreach(string part in value.Split(delimiter, count, options))
29+
{
30+
length += part.Length;
31+
}
32+
33+
return length;
34+
}
35+
36+
[Benchmark]
37+
[ArgumentsSource(nameof(GetArgsWithDelimiterAndCountAndStringSplitOptions))]
38+
public int Split_Count_StringSplitOptions_CountExceedingBehaviour_CutLastElements_ReadOnlySpan(ReadOnlySpan<char> value, char delimiter, int count, StringSplitOptions options)
39+
{
40+
int length = 0;
41+
42+
foreach(ReadOnlySpan<char> part in value.Split(delimiter, count, options, CountExceedingBehaviour.CutLastElements))
43+
{
44+
length += part.Length;
45+
}
46+
47+
return length;
48+
}
49+
50+
public IEnumerable<object[]> GetArgsWithDelimiterAndCountAndStringSplitOptions()
51+
{
52+
yield return new object[] { "12131415161718190", '1', 3, StringSplitOptions.None };
53+
yield return new object[] { "12131415161718190", '1', 2, StringSplitOptions.None };
54+
yield return ["abba", 'b', 4, StringSplitOptions.None];
55+
yield return ["aaa", 'a', 1, StringSplitOptions.None];
56+
yield return ["aba", 'a', 10, StringSplitOptions.None];
57+
yield return ["12131415161718190", '1', 12, StringSplitOptions.None];
58+
yield return [" xy z", 'y', 2, StringSplitOptions.TrimEntries];
59+
yield return ["a bcd e", 'c', 1, StringSplitOptions.TrimEntries];
60+
yield return [" ab cdef g ", 'd', 4, StringSplitOptions.TrimEntries];
61+
yield return ["abb", 'b', 1, StringSplitOptions.RemoveEmptyEntries];
62+
yield return ["abb", 'b', 2, StringSplitOptions.RemoveEmptyEntries];
63+
yield return ["aaa", 'a', 1, StringSplitOptions.RemoveEmptyEntries];
64+
yield return ["aaa", 'a', 2, StringSplitOptions.RemoveEmptyEntries];
65+
yield return ["aba ", 'a', 1, StringSplitOptions.TrimEntries | StringSplitOptions.RemoveEmptyEntries];
66+
yield return ["aba ", 'a', 2, StringSplitOptions.TrimEntries | StringSplitOptions.RemoveEmptyEntries];
67+
yield return ["aba ", 'a', 3, StringSplitOptions.TrimEntries | StringSplitOptions.RemoveEmptyEntries];
68+
yield return ["1 13141516171 190", '1', 2, StringSplitOptions.TrimEntries | StringSplitOptions.RemoveEmptyEntries];
69+
yield return ["1 131 151 171 190", '1', 2, StringSplitOptions.TrimEntries | StringSplitOptions.RemoveEmptyEntries];
70+
yield return ["1131151171 190", '1', 2, StringSplitOptions.TrimEntries | StringSplitOptions.RemoveEmptyEntries];
71+
}
72+
}
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
using BenchmarkDotNet.Attributes;
2+
3+
namespace SpanExtensions.Tests.Performance;
4+
5+
[MemoryDiagnoser(false)]
6+
public class ReadOnlySpan_Split_StringSplitOptions_Benchmark
7+
{
8+
[Benchmark]
9+
[ArgumentsSource(nameof(GetArgsWithDelimiterAndStringSplitOptions))]
10+
public int Split_StringSplitOptions_ReadOnlySpan(ReadOnlySpan<char> value, char delimiter, StringSplitOptions options)
11+
{
12+
int length = 0;
13+
14+
foreach(ReadOnlySpan<char> part in value.Split(delimiter, options))
15+
{
16+
length += part.Length;
17+
}
18+
19+
return length;
20+
}
21+
22+
[Benchmark(Baseline = true)]
23+
[ArgumentsSource(nameof(GetArgsWithDelimiterAndStringSplitOptions))]
24+
public int Split_StringSplitOptions_String(string value, char delimiter, StringSplitOptions options)
25+
{
26+
int length = 0;
27+
28+
foreach(string part in value.Split(delimiter, options))
29+
{
30+
length += part.Length;
31+
}
32+
33+
return length;
34+
}
35+
36+
public IEnumerable<object[]> GetArgsWithDelimiterAndStringSplitOptions()
37+
{
38+
yield return ["xyz", 'y', StringSplitOptions.None];
39+
yield return ["abcde", 'c', StringSplitOptions.None];
40+
yield return ["abcdefg", 'd', StringSplitOptions.None];
41+
yield return ["abba", 'b', StringSplitOptions.None];
42+
yield return ["aaa", 'a', StringSplitOptions.None];
43+
yield return ["aba", 'a', StringSplitOptions.None];
44+
yield return ["12131415161718190", '1', StringSplitOptions.None];
45+
yield return [" xy z", 'y', StringSplitOptions.TrimEntries];
46+
yield return ["a bcd e", 'c', StringSplitOptions.TrimEntries];
47+
yield return [" ab cdef g ", 'd', StringSplitOptions.TrimEntries];
48+
yield return ["abb", 'b', StringSplitOptions.RemoveEmptyEntries];
49+
yield return ["aaa", 'a', StringSplitOptions.RemoveEmptyEntries];
50+
yield return ["aba ", 'a', StringSplitOptions.TrimEntries | StringSplitOptions.RemoveEmptyEntries];
51+
yield return ["1 13141516171 190", '1', StringSplitOptions.TrimEntries | StringSplitOptions.RemoveEmptyEntries];
52+
}
53+
}
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
using BenchmarkDotNet.Attributes;
2+
3+
namespace SpanExtensions.Tests.Performance
4+
{
5+
[MemoryDiagnoser(false)]
6+
public class ReadOnlySpan_Split_Any_Benchmark
7+
{
8+
[Benchmark]
9+
[ArgumentsSource(nameof(GetArgsWithDelimiter))]
10+
public int Split_Any_ReadOnlySpan(ReadOnlySpan<char> value, char[] delimiters)
11+
{
12+
int length = 0;
13+
14+
foreach(ReadOnlySpan<char> part in value.SplitAny(delimiters))
15+
{
16+
length += part.Length;
17+
}
18+
19+
return length;
20+
}
21+
22+
[Benchmark(Baseline = true)]
23+
[ArgumentsSource(nameof(GetArgsWithDelimiter))]
24+
public int Split_Any_String(string value, char[] delimiters)
25+
{
26+
int length = 0;
27+
28+
foreach(string part in value.Split(delimiters))
29+
{
30+
length += part.Length;
31+
}
32+
33+
return length;
34+
}
35+
36+
public IEnumerable<object[]> GetArgsWithDelimiter()
37+
{
38+
yield return new object[] { "abcde", new object[] { 'b', 'd' } };
39+
yield return new object[] { "abcdefg", new object[] { 'b', 'd', 'f' } };
40+
yield return new object[] { "abba", new object[] { 'b', 'a' } };
41+
yield return new object[] { "1234567890", new object[] { '1', '5', '7' } };
42+
}
43+
}
44+
}
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
using BenchmarkDotNet.Attributes;
2+
3+
namespace SpanExtensions.Tests.Performance
4+
{
5+
[MemoryDiagnoser(false)]
6+
public class ReadOnlySpan_Split_Any_Count_Benchmark
7+
{
8+
[Benchmark]
9+
[ArgumentsSource(nameof(GetArgsWithDelimiter))]
10+
public int Split_Any_Count_ReadOnlySpan(ReadOnlySpan<char> value, char[] delimiters, int count)
11+
{
12+
int length = 0;
13+
14+
foreach(ReadOnlySpan<char> part in value.SplitAny(delimiters, count))
15+
{
16+
length += part.Length;
17+
}
18+
19+
return length;
20+
}
21+
22+
[Benchmark(Baseline = true)]
23+
[ArgumentsSource(nameof(GetArgsWithDelimiter))]
24+
public int Split_Any_Count_String(string value, char[] delimiters, int count)
25+
{
26+
int length = 0;
27+
28+
foreach(string part in value.Split(delimiters, count))
29+
{
30+
length += part.Length;
31+
}
32+
33+
return length;
34+
}
35+
36+
public IEnumerable<object[]> GetArgsWithDelimiter()
37+
{
38+
yield return ["abcde", new object[] { 'b', 'd' }, 2];
39+
yield return ["abcdefg", new object[] { 'b', 'd', 'f' }, 4];
40+
yield return ["abba", new object[] { 'b', 'a' }, 2];
41+
yield return ["1234567890", new object[] { '1', '5', '7' }, 1];
42+
}
43+
}
44+
}

0 commit comments

Comments
 (0)