Skip to content

Commit 3c29ee4

Browse files
authored
Improve performance of Sum() (#370)
1 parent e3c97cf commit 3c29ee4

File tree

72 files changed

+2048
-266
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

72 files changed

+2048
-266
lines changed

NetFabric.Hyperlinq.UnitTests/Aggregation/Sum.TestData.cs

Lines changed: 45 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,13 +7,18 @@ namespace NetFabric.Hyperlinq
77
{
88
public static partial class TestData
99
{
10-
public static TheoryData<double[]> Sum
10+
public static TheoryData<double[]> SumDouble
1111
=> new()
1212
{
1313
new double[] { },
1414
new[] { double.NaN },
1515
new[] { double.PositiveInfinity },
1616
new[] { 1.0 },
17+
new[] { 1.0, 2.0 },
18+
new[] { 1.0, 2.0, 3.0 },
19+
new[] { 1.0, 2.0, 3.0, 4.0 },
20+
new[] { 1.0, 2.0, 3.0, 4.0, 5.0 },
21+
new[] { 1.0, 2.0, 3.0, 4.0, 5.0, 6.0 },
1722
new[] { 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0 },
1823
new[] { 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0 },
1924
new[] { 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0 },
@@ -24,22 +29,58 @@ public static TheoryData<double[]> Sum
2429
new[] { double.PositiveInfinity, double.PositiveInfinity }
2530
};
2631

27-
public static TheoryData<double?[]> NullableSum
32+
public static TheoryData<double?[]> SumNullableDouble
2833
=> new()
2934
{
3035
new double?[] { },
3136
new double?[] { default },
3237
new double?[] { double.NaN },
3338
new double?[] { double.PositiveInfinity },
34-
new double?[] { 1 },
39+
new double?[] { 1.0 },
40+
new double?[] { 1.0, 2.0 },
41+
new double?[] { 1.0, 2.0, 3.0 },
42+
new double?[] { 1.0, 2.0, 3.0, 4.0 },
43+
new double?[] { 1.0, 2.0, 3.0, 4.0, 5.0 },
3544
new double?[] { default, default, default },
3645
new double?[] { default, 2.0, double.NaN, 4.0, default },
3746
new double?[] { default, 2.0, 3.0, 4.0, default },
3847
new double?[] { 1.0, 2.0, default, 4.0, 5.0 },
39-
new double?[] { 1.0, 2.0, 3.0, 4.0, 5.0 },
4048
new double?[] { double.MaxValue, double.MaxValue },
4149
new double?[] { double.PositiveInfinity, double.PositiveInfinity }
4250
};
4351

52+
public static TheoryData<decimal[]> SumDecimal
53+
=> new()
54+
{
55+
new decimal[] { },
56+
new[] { 1.0M },
57+
new[] { 1.0M, 2.0M },
58+
new[] { 1.0M, 2.0M, 3.0M },
59+
new[] { 1.0M, 2.0M, 3.0M, 4.0M },
60+
new[] { 1.0M, 2.0M, 3.0M, 4.0M, 5.0M },
61+
new[] { 1.0M, 2.0M, 3.0M, 4.0M, 5.0M, 6.0M },
62+
new[] { 1.0M, 2.0M, 3.0M, 4.0M, 5.0M, 6.0M, 7.0M },
63+
new[] { 1.0M, 2.0M, 3.0M, 4.0M, 5.0M, 6.0M, 7.0M, 8.0M },
64+
new[] { 1.0M, 2.0M, 3.0M, 4.0M, 5.0M, 6.0M, 7.0M, 8.0M, 9.0M },
65+
new[] { 1.0M, 2.0M, 3.0M, 4.0M, 5.0M, 6.0M, 7.0M, 8.0M, 9.0M, 10.0M, 11.0M, 12.0M, 13.0M, 14.0M, 15.0M, 16.0M, 17.0M, 18.0M, 19.0M, 20.0M },
66+
//new[] { decimal.MaxValue, decimal.MaxValue },
67+
};
68+
69+
70+
public static TheoryData<decimal?[]> SumNullableDecimal
71+
=> new()
72+
{
73+
new decimal?[] { },
74+
new decimal?[] { default },
75+
new decimal?[] { 1.0M },
76+
new decimal?[] { 1.0M, 2.0M },
77+
new decimal?[] { 1.0M, 2.0M, 3.0M },
78+
new decimal?[] { 1.0M, 2.0M, 3.0M, 4.0M },
79+
new decimal?[] { 1.0M, 2.0M, 3.0M, 4.0M, 5.0M },
80+
new decimal?[] { default, default, default },
81+
new decimal?[] { default, 2.0M, 3.0M, 4.0M, default },
82+
new decimal?[] { 1.0M, 2.0M, default, 4.0M, 5.0M },
83+
//new decimal?[] { decimal.MaxValue, decimal.MaxValue },
84+
};
4485
}
4586
}

NetFabric.Hyperlinq.UnitTests/Aggregation/Sum/Sum.ReadOnlySpan.Tests.cs

Lines changed: 41 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,8 @@ public class ArrayTests
99
{
1010

1111
[Theory]
12-
[MemberData(nameof(TestData.Sum), MemberType = typeof(TestData))]
13-
public void Sum_With_ValidData_Must_Succeed(double[] source)
12+
[MemberData(nameof(TestData.SumDouble), MemberType = typeof(TestData))]
13+
public void Sum_With_Double_Must_Succeed(double[] source)
1414
{
1515
// Arrange
1616
var wrapped = (ReadOnlySpan<double>)source.AsSpan();
@@ -27,8 +27,8 @@ public void Sum_With_ValidData_Must_Succeed(double[] source)
2727
}
2828

2929
[Theory]
30-
[MemberData(nameof(TestData.NullableSum), MemberType = typeof(TestData))]
31-
public void Sum_With_Nullable_ValidData_Must_Succeed(double?[] source)
30+
[MemberData(nameof(TestData.SumNullableDouble), MemberType = typeof(TestData))]
31+
public void Sum_With_NullableDouble_Must_Succeed(double?[] source)
3232
{
3333
// Arrange
3434
var wrapped = (ReadOnlySpan<double?>)source.AsSpan();
@@ -43,5 +43,42 @@ public void Sum_With_Nullable_ValidData_Must_Succeed(double?[] source)
4343
_ = result.Must()
4444
.BeEqualTo(expected!.Value);
4545
}
46+
47+
48+
[Theory]
49+
[MemberData(nameof(TestData.SumDecimal), MemberType = typeof(TestData))]
50+
public void Sum_With_Decimal_Must_Succeed(decimal[] source)
51+
{
52+
// Arrange
53+
var wrapped = (ReadOnlySpan<decimal>)source.AsSpan();
54+
var expected = source
55+
.Sum();
56+
57+
// Act
58+
var result = wrapped.AsValueEnumerable()
59+
.Sum();
60+
61+
// Assert
62+
_ = result.Must()
63+
.BeEqualTo(expected);
64+
}
65+
66+
[Theory]
67+
[MemberData(nameof(TestData.SumNullableDecimal), MemberType = typeof(TestData))]
68+
public void Sum_With_NullableDecimal_ValidData_Must_Succeed(decimal?[] source)
69+
{
70+
// Arrange
71+
var wrapped = (ReadOnlySpan<decimal?>)source.AsSpan();
72+
var expected = source
73+
.Sum();
74+
75+
// Act
76+
var result = wrapped.AsValueEnumerable()
77+
.Sum();
78+
79+
// Assert
80+
_ = result.Must()
81+
.BeEqualTo(expected!.Value);
82+
}
4683
}
4784
}

NetFabric.Hyperlinq.UnitTests/Aggregation/Sum/Sum.ValueEnumerable.Tests.cs

Lines changed: 44 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -8,35 +8,71 @@ namespace NetFabric.Hyperlinq.UnitTests.Aggregation.Sum
88
public class ValueEnumerableTests
99
{
1010
[Theory]
11-
[MemberData(nameof(TestData.Sum), MemberType = typeof(TestData))]
12-
public void Sum_With_ValidData_Must_Succeed(double[] source)
11+
[MemberData(nameof(TestData.SumDouble), MemberType = typeof(TestData))]
12+
public void Sum_With_Double_Must_Succeed(double[] source)
1313
{
1414
// Arrange
1515
var wrapped = Wrap.AsValueEnumerable(source);
1616
var expected = source
1717
.Sum();
1818

1919
// Act
20-
var result = wrapped
21-
.Sum<Wrap.ValueEnumerableWrapper<double>, Wrap.Enumerator<double>, double, double>();
20+
var result = wrapped.AsValueEnumerable()
21+
.Sum();
2222

2323
// Assert
2424
_ = result.Must()
2525
.BeEqualTo(expected);
2626
}
2727

2828
[Theory]
29-
[MemberData(nameof(TestData.NullableSum), MemberType = typeof(TestData))]
30-
public void Sum_With_Nullable_ValidData_Must_Succeed(double?[] source)
29+
[MemberData(nameof(TestData.SumNullableDouble), MemberType = typeof(TestData))]
30+
public void Sum_With_NullableDouble_Must_Succeed(double?[] source)
31+
{
32+
// Arrange
33+
var wrapped = Wrap.AsValueEnumerable(source);
34+
var expected = source
35+
.Sum();
36+
37+
// Act
38+
var result = wrapped.AsValueEnumerable()
39+
.Sum();
40+
41+
// Assert
42+
_ = result.Must()
43+
.BeEqualTo(expected!.Value);
44+
}
45+
46+
[Theory]
47+
[MemberData(nameof(TestData.SumDecimal), MemberType = typeof(TestData))]
48+
public void Sum_With_Decimal_Must_Succeed(decimal[] source)
3149
{
3250
// Arrange
3351
var wrapped = Wrap.AsValueEnumerable(source);
3452
var expected = source
3553
.Sum();
3654

3755
// Act
38-
var result = wrapped
39-
.Sum<Wrap.ValueEnumerableWrapper<double?>, Wrap.Enumerator<double?>, double?, double>();
56+
var result = wrapped.AsValueEnumerable()
57+
.Sum();
58+
59+
// Assert
60+
_ = result.Must()
61+
.BeEqualTo(expected);
62+
}
63+
64+
[Theory]
65+
[MemberData(nameof(TestData.SumNullableDecimal), MemberType = typeof(TestData))]
66+
public void Sum_With_NullableDecimal_Must_Succeed(decimal?[] source)
67+
{
68+
// Arrange
69+
var wrapped = Wrap.AsValueEnumerable(source);
70+
var expected = source
71+
.Sum();
72+
73+
// Act
74+
var result = wrapped.AsValueEnumerable()
75+
.Sum();
4076

4177
// Assert
4278
_ = result.Must()

NetFabric.Hyperlinq.UnitTests/Aggregation/Sum/Sum.ValueReadOnlyCollection.Tests.cs

Lines changed: 40 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,8 @@ namespace NetFabric.Hyperlinq.UnitTests.Aggregation.Sum
88
public class ValueReadOnlyCollectionTests
99
{
1010
[Theory]
11-
[MemberData(nameof(TestData.Sum), MemberType = typeof(TestData))]
12-
public void Sum_With_ValidData_Must_Succeed(double[] source)
11+
[MemberData(nameof(TestData.SumDouble), MemberType = typeof(TestData))]
12+
public void Sum_With_Double_Must_Succeed(double[] source)
1313
{
1414
// Arrange
1515
var wrapped = Wrap.AsValueReadOnlyCollection(source);
@@ -26,8 +26,44 @@ public void Sum_With_ValidData_Must_Succeed(double[] source)
2626
}
2727

2828
[Theory]
29-
[MemberData(nameof(TestData.NullableSum), MemberType = typeof(TestData))]
30-
public void Sum_With_Nullable_ValidData_Must_Succeed(double?[] source)
29+
[MemberData(nameof(TestData.SumNullableDouble), MemberType = typeof(TestData))]
30+
public void Sum_With_NullableDouble_Must_Succeed(double?[] source)
31+
{
32+
// Arrange
33+
var wrapped = Wrap.AsValueReadOnlyCollection(source);
34+
var expected = source
35+
.Sum();
36+
37+
// Act
38+
var result = wrapped.AsValueEnumerable()
39+
.Sum();
40+
41+
// Assert
42+
_ = result.Must()
43+
.BeEqualTo(expected!.Value);
44+
}
45+
46+
[Theory]
47+
[MemberData(nameof(TestData.SumDecimal), MemberType = typeof(TestData))]
48+
public void Sum_With_Decimal_Must_Succeed(decimal[] source)
49+
{
50+
// Arrange
51+
var wrapped = Wrap.AsValueReadOnlyCollection(source);
52+
var expected = source
53+
.Sum();
54+
55+
// Act
56+
var result = wrapped.AsValueEnumerable()
57+
.Sum();
58+
59+
// Assert
60+
_ = result.Must()
61+
.BeEqualTo(expected);
62+
}
63+
64+
[Theory]
65+
[MemberData(nameof(TestData.SumNullableDecimal), MemberType = typeof(TestData))]
66+
public void Sum_With_NullableDecimal_Must_Succeed(decimal?[] source)
3167
{
3268
// Arrange
3369
var wrapped = Wrap.AsValueReadOnlyCollection(source);

NetFabric.Hyperlinq.UnitTests/Aggregation/Sum/SumAsync.AsyncValueEnumerable.Tests.cs

Lines changed: 42 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,8 @@ namespace NetFabric.Hyperlinq.UnitTests.Aggregation.Sum
99
public class AsyncValueEnumerableTests
1010
{
1111
[Theory]
12-
[MemberData(nameof(TestData.Sum), MemberType = typeof(TestData))]
13-
public async ValueTask SumAsync_With_ValidData_Must_Succeed(double[] source)
12+
[MemberData(nameof(TestData.SumDouble), MemberType = typeof(TestData))]
13+
public async ValueTask SumAsync_With_Double_Must_Succeed(double[] source)
1414
{
1515
// Arrange
1616
var wrapped = Wrap.AsAsyncValueEnumerable(source);
@@ -28,8 +28,46 @@ public async ValueTask SumAsync_With_ValidData_Must_Succeed(double[] source)
2828
}
2929

3030
[Theory]
31-
[MemberData(nameof(TestData.NullableSum), MemberType = typeof(TestData))]
32-
public async ValueTask SumAsync_With_Nullable_ValidData_Must_Succeed(double?[] source)
31+
[MemberData(nameof(TestData.SumNullableDouble), MemberType = typeof(TestData))]
32+
public async ValueTask SumAsync_With_NullableDouble_Must_Succeed(double?[] source)
33+
{
34+
// Arrange
35+
var wrapped = Wrap.AsAsyncValueEnumerable(source);
36+
var expected = source
37+
.Sum();
38+
39+
// Act
40+
var result = await wrapped.AsAsyncValueEnumerable()
41+
.SumAsync()
42+
.ConfigureAwait(false);
43+
44+
// Assert
45+
_ = result.Must()
46+
.BeEqualTo(expected!.Value);
47+
}
48+
49+
[Theory]
50+
[MemberData(nameof(TestData.SumDecimal), MemberType = typeof(TestData))]
51+
public async ValueTask SumAsync_With_Decimal_Must_Succeed(decimal[] source)
52+
{
53+
// Arrange
54+
var wrapped = Wrap.AsAsyncValueEnumerable(source);
55+
var expected = source
56+
.Sum();
57+
58+
// Act
59+
var result = await wrapped.AsAsyncValueEnumerable()
60+
.SumAsync()
61+
.ConfigureAwait(false);
62+
63+
// Assert
64+
_ = result.Must()
65+
.BeEqualTo(expected);
66+
}
67+
68+
[Theory]
69+
[MemberData(nameof(TestData.SumNullableDecimal), MemberType = typeof(TestData))]
70+
public async ValueTask SumAsync_With_NullableDecimal_Must_Succeed(decimal?[] source)
3371
{
3472
// Arrange
3573
var wrapped = Wrap.AsAsyncValueEnumerable(source);

NetFabric.Hyperlinq/Aggregation/Sum/Sum.Range.cs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -43,18 +43,18 @@ static unsafe TResult SumRange<TResult, TVectorSelector, TSelector>(int start, i
4343
}
4444

4545
for (index = 0; index < Vector<TResult>.Count; index++)
46-
sum = GenericsOperator.Add(vectorSum[index], sum);
46+
sum = Scalar.Add(vectorSum[index], sum);
4747
}
4848

4949
if (start is 0)
5050
{
5151
for (; index < count; index++)
52-
sum = GenericsOperator.Add(selector.Invoke(index), sum);
52+
sum = Scalar.Add(selector.Invoke(index), sum);
5353
}
5454
else
5555
{
5656
for (; index < count; index++)
57-
sum = GenericsOperator.Add(selector.Invoke(index + start), sum);
57+
sum = Scalar.Add(selector.Invoke(index + start), sum);
5858
}
5959

6060
return sum;

0 commit comments

Comments
 (0)