Skip to content

Commit e349192

Browse files
committed
Feat: Add Sum extension methods for Span and ReadOnlySpan
1 parent cabd40e commit e349192

File tree

2 files changed

+182
-0
lines changed

2 files changed

+182
-0
lines changed
Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
// ---------------------------------------------------------------------------------------------------------------------
2+
// Imports
3+
// ---------------------------------------------------------------------------------------------------------------------
4+
// ReSharper disable once CheckNamespace
5+
namespace System;
6+
7+
// ---------------------------------------------------------------------------------------------------------------------
8+
// Code
9+
// ---------------------------------------------------------------------------------------------------------------------
10+
public static class SpanLinqSumExtensions {
11+
public static int Sum<T>(this in Span<T> span, Func<T, int> selector, int length = -1) {
12+
int totalGroups = 0;
13+
length = length switch {
14+
< -1 => throw new ArgumentOutOfRangeException(nameof(length)),
15+
-1 => span.Length,
16+
_ => length
17+
};
18+
19+
for (int index = 0; index < length; index++) {
20+
totalGroups += selector(span[index]);
21+
}
22+
return totalGroups;
23+
}
24+
25+
public static int Sum<T>(this in Span<T> span, Func<T, int> selector, Range range) {
26+
int totalGroups = 0;
27+
ReadOnlySpan<T> slice = span[range];
28+
int length = slice.Length;
29+
30+
for (int index = 0; index < length; index++) {
31+
totalGroups += selector(slice[index]);
32+
}
33+
return totalGroups;
34+
}
35+
36+
public static int Sum<T>(this in ReadOnlySpan<T> span, Func<T, int> selector, int length = -1) {
37+
int totalGroups = 0;
38+
length = length switch {
39+
< -1 => throw new ArgumentOutOfRangeException(nameof(length)),
40+
-1 => span.Length,
41+
_ => length
42+
};
43+
44+
for (int index = 0; index < length; index++) {
45+
totalGroups += selector(span[index]);
46+
}
47+
return totalGroups;
48+
}
49+
50+
public static int Sum<T>(this in ReadOnlySpan<T> span, Func<T, int> selector, Range range) {
51+
int totalGroups = 0;
52+
ReadOnlySpan<T> slice = span[range];
53+
int length = slice.Length;
54+
55+
for (int index = 0; index < length; index++) {
56+
totalGroups += selector(slice[index]);
57+
}
58+
return totalGroups;
59+
}
60+
}
Lines changed: 122 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,122 @@
1+
// ---------------------------------------------------------------------------------------------------------------------
2+
// Imports
3+
// ---------------------------------------------------------------------------------------------------------------------
4+
namespace Tests.CodeOfChaos.Extensions.SpanLinq;
5+
6+
// ---------------------------------------------------------------------------------------------------------------------
7+
// Code
8+
// ---------------------------------------------------------------------------------------------------------------------
9+
public class SpanLinqSumTests {
10+
private record TestItem(int Value);
11+
12+
[Test]
13+
public async Task Sum_Span_WithDefaultLength_ShouldSumAllElements() {
14+
// Arrange
15+
Span<int> numbers = [1, 2, 3, 4, 5];
16+
17+
// Act
18+
int result = numbers.Sum(x => x);
19+
20+
// Assert
21+
await Assert.That(result).IsEqualTo(15);
22+
}
23+
24+
[Test]
25+
public async Task Sum_Span_WithSpecificLength_ShouldSumSpecifiedElements() {
26+
// Arrange
27+
Span<int> numbers = [1, 2, 3, 4, 5];
28+
29+
// Act
30+
int result = numbers.Sum(x => x, 3);
31+
32+
// Assert
33+
await Assert.That(result).IsEqualTo(6); // Sum of first 3 elements: 1 + 2 + 3
34+
}
35+
36+
[Test]
37+
public async Task Sum_Span_WithRange_ShouldSumElementsInRange() {
38+
// Arrange
39+
Span<int> numbers = [1, 2, 3, 4, 5];
40+
var range = 1..4; // Elements at index 1, 2, and 3
41+
42+
// Act
43+
int result = numbers.Sum(x => x, range);
44+
45+
// Assert
46+
await Assert.That(result).IsEqualTo(9); // Sum of elements 2 + 3 + 4
47+
}
48+
49+
[Test]
50+
public async Task Sum_Span_WithSelector_ShouldApplySelector() {
51+
// Arrange
52+
Span<int> numbers = [1, 2, 3];
53+
54+
// Act
55+
int result = numbers.Sum(x => x * 2);
56+
57+
// Assert
58+
await Assert.That(result).IsEqualTo(12); // (1*2) + (2*2) + (3*2)
59+
}
60+
61+
[Test]
62+
public async Task Sum_ReadOnlySpan_WithDefaultLength_ShouldSumAllElements() {
63+
// Arrange
64+
ReadOnlySpan<int> numbers = [1, 2, 3, 4, 5];
65+
66+
// Act
67+
int result = numbers.Sum(x => x);
68+
69+
// Assert
70+
await Assert.That(result).IsEqualTo(15);
71+
}
72+
73+
[Test]
74+
public async Task Sum_ReadOnlySpan_WithSpecificLength_ShouldSumSpecifiedElements() {
75+
// Arrange
76+
ReadOnlySpan<int> numbers = [1, 2, 3, 4, 5];
77+
78+
// Act
79+
int result = numbers.Sum(x => x, 3);
80+
81+
// Assert
82+
await Assert.That(result).IsEqualTo(6); // Sum of first 3 elements
83+
}
84+
85+
[Test]
86+
public async Task Sum_ReadOnlySpan_WithRange_ShouldSumElementsInRange() {
87+
// Arrange
88+
ReadOnlySpan<int> numbers = [1, 2, 3, 4, 5];
89+
Range range = 1..4;
90+
91+
// Act
92+
int result = numbers.Sum(x => x, range);
93+
94+
// Assert
95+
await Assert.That(result).IsEqualTo(9); // Sum of elements 2 + 3 + 4
96+
}
97+
98+
[Test]
99+
public void Sum_InvalidLength_ShouldThrowArgumentOutOfRangeException() {
100+
Assert.Throws<ArgumentOutOfRangeException>(() => {
101+
Span<int> numbers = [1, 2, 3];
102+
numbers.Sum(x => x, -2);
103+
});
104+
}
105+
106+
[Test]
107+
public async Task Sum_WithCustomType_ShouldSumSelectedValues() {
108+
// Arrange
109+
var items = new TestItem[] {
110+
new(1),
111+
new(2),
112+
new(3)
113+
};
114+
Span<TestItem> span = items;
115+
116+
// Act
117+
int result = span.Sum(x => x.Value);
118+
119+
// Assert
120+
await Assert.That(result).IsEqualTo(6);
121+
}
122+
}

0 commit comments

Comments
 (0)