Skip to content

Commit f24aee2

Browse files
committed
Add new constructors to Span<T> and ReadOnlySpan<T>
- Add constructor from pointer. - Add missing base classes to enumerators. - Add Slice API to ReadOnlySpan. - Add new unit tests (some are commented out as they are WIP). - IntelliSense comments fixed/improved.
1 parent 72085be commit f24aee2

File tree

5 files changed

+614
-7
lines changed

5 files changed

+614
-7
lines changed

Tests/NFUnitTestTypes/NFUnitTestTypes.nfproj

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
<ItemGroup>
2727
<Compile Include="UnitTestGuid.cs" />
2828
<Compile Include="UnitTestObjectTypeTests.cs" />
29+
<Compile Include="UnitTestsReadOnlySpanByte.cs" />
2930
<Compile Include="UnitTestsSpanByte.cs" />
3031
<Compile Include="UnitTestSubTypeTests.cs" />
3132
<Compile Include="UnitTestValueArrayTypess.cs" />
Lines changed: 351 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,351 @@
1+
// Licensed to the .NET Foundation under one or more agreements.
2+
// The .NET Foundation licenses this file to you under the MIT license.
3+
4+
using System;
5+
using nanoFramework.TestFramework;
6+
7+
namespace NFUnitTestTypes
8+
{
9+
[TestClass]
10+
public class UnitTestsReadOnlySpanByte
11+
{
12+
//[TestMethod]
13+
//public void EmptySpanTests()
14+
//{
15+
// // Empty span using default constructor
16+
// ReadOnlySpan<byte> span = new ReadOnlySpan<byte>();
17+
18+
// Assert.AreEqual(0, span.Length, "Empty ReadOnlySpan should have length of 0");
19+
// Assert.IsTrue(span.IsEmpty, "Empty ReadOnlySpan should be IsEmpty");
20+
21+
// // Empty span from null array
22+
// span = new ReadOnlySpan<byte>(null);
23+
24+
// Assert.AreEqual(0, span.Length, "ReadOnlySpan from null should have length of 0");
25+
// Assert.IsTrue(span.IsEmpty, "ReadOnlySpan from null should be IsEmpty");
26+
27+
// // Empty span using Empty property
28+
// span = ReadOnlySpan<byte>.Empty;
29+
30+
// Assert.AreEqual(0, span.Length, "Empty ReadOnlySpan should have length of 0");
31+
// Assert.IsTrue(span.IsEmpty, "Empty ReadOnlySpan should be IsEmpty");
32+
//}
33+
34+
//[TestMethod]
35+
//public void RaisingExceptionsOfAllKindsTests()
36+
//{
37+
// // Should raise an exception on creation
38+
// Assert.ThrowsException(typeof(ArgumentOutOfRangeException), () => { ReadOnlySpan<byte> span = new ReadOnlySpan<byte>(null, 1, 2); }, "ArgumentOutOfRangeException when array is null, start is 1 and length is 2");
39+
// Assert.ThrowsException(typeof(ArgumentOutOfRangeException), () => { ReadOnlySpan<byte> span = new ReadOnlySpan<byte>(new byte[1], 1, 2); }, "ArgumentOutOfRangeException when array is new byte[1], start is 1 and length is 2");
40+
// Assert.ThrowsException(typeof(ArgumentOutOfRangeException), () => { ReadOnlySpan<byte> span = new ReadOnlySpan<byte>(new byte[1], 0, 2); }, "ArgumentOutOfRangeException when array is new byte[1], start is 0 and length is 2");
41+
// Assert.ThrowsException(typeof(ArgumentOutOfRangeException), () => { ReadOnlySpan<byte> span = new ReadOnlySpan<byte>(new byte[1], 2, 0); }, "ArgumentOutOfRangeException when array is new byte[1], start is 2 and length is 0");
42+
43+
// // Exception on index access
44+
// byte[] array = new byte[16] { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F };
45+
// Assert.ThrowsException(typeof(ArgumentOutOfRangeException), () =>
46+
// {
47+
// ReadOnlySpan<byte> span = new ReadOnlySpan<byte>(array);
48+
// _ = span[span.Length];
49+
// });
50+
51+
// Assert.ThrowsException(typeof(ArgumentOutOfRangeException), () =>
52+
// {
53+
// ReadOnlySpan<byte> span = new ReadOnlySpan<byte>(array);
54+
// _ = span[-1];
55+
// });
56+
57+
// // Slicing arguments
58+
// Assert.ThrowsException(typeof(ArgumentOutOfRangeException), () =>
59+
// {
60+
// ReadOnlySpan<byte> span = new ReadOnlySpan<byte>(array);
61+
// _ = span.Slice(span.Length + 1);
62+
// });
63+
64+
// Assert.ThrowsException(typeof(ArgumentOutOfRangeException), () =>
65+
// {
66+
// ReadOnlySpan<byte> span = new ReadOnlySpan<byte>(array);
67+
// _ = span.Slice(1, span.Length);
68+
// });
69+
70+
// Assert.ThrowsException(typeof(ArgumentOutOfRangeException), () =>
71+
// {
72+
// ReadOnlySpan<byte> span = new ReadOnlySpan<byte>(array);
73+
// _ = span.Slice(-1, span.Length);
74+
// });
75+
76+
// Assert.ThrowsException(typeof(ArgumentOutOfRangeException), () =>
77+
// {
78+
// ReadOnlySpan<byte> span = new ReadOnlySpan<byte>(array);
79+
// _ = span.Slice(1, -1);
80+
// });
81+
//}
82+
83+
[TestMethod]
84+
public void ToArrayTest()
85+
{
86+
byte[] array = new byte[16] { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F };
87+
88+
ReadOnlySpan<byte> span = new ReadOnlySpan<byte>(array);
89+
90+
byte[] toArray = span.ToArray();
91+
92+
CollectionAssert.AreEqual(array, toArray, "Original array and ReadOnlySpan.ToArray should be the same");
93+
}
94+
95+
[TestMethod]
96+
public void ConstructorsOfAllKindsTests()
97+
{
98+
// Empty span using default constructor
99+
ReadOnlySpan<byte> span = new ReadOnlySpan<byte>();
100+
101+
Assert.AreEqual(span.Length, 0, "Empty ReadOnlySpan should have length of 0");
102+
Assert.IsTrue(span.IsEmpty, "Empty ReadOnlySpan should be IsEmpty");
103+
104+
// Empty span from null with zero start and length
105+
span = new ReadOnlySpan<byte>(null, 0, 0);
106+
107+
Assert.AreEqual(span.Length, 0, "Empty ReadOnlySpan should have length of 0");
108+
Assert.IsTrue(span.IsEmpty, "Empty ReadOnlySpan should be IsEmpty");
109+
110+
//// Empty span using Empty property
111+
//span = ReadOnlySpan<byte>.Empty;
112+
113+
//Assert.AreEqual(span.Length, 0, "Empty ReadOnlySpan should have length of 0");
114+
//Assert.IsTrue(span.IsEmpty, "Empty ReadOnlySpan should be IsEmpty");
115+
116+
// ReadOnlySpan from normal array
117+
byte[] array = new byte[16] { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F };
118+
span = new ReadOnlySpan<byte>(array);
119+
120+
Assert.AreEqual(span.Length, array.Length, $"ReadOnlySpan should have length of the array it takes: {array.Length}");
121+
Assert.IsFalse(span.IsEmpty, "ReadOnlySpan should NOT be IsEmpty");
122+
123+
// ReadOnlySpan from normal array with different start and length
124+
span = new ReadOnlySpan<byte>(array, 2, 8);
125+
126+
Assert.AreEqual(span.Length, 8, $"ReadOnlySpan should have length of 8");
127+
Assert.IsFalse(span.IsEmpty, "ReadOnlySpan should NOT be IsEmpty");
128+
}
129+
130+
//[TestMethod]
131+
//public void SliceTests()
132+
//{
133+
// // ReadOnlySpan from normal array
134+
// byte[] array = new byte[16] { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F };
135+
// ReadOnlySpan<byte> span = new ReadOnlySpan<byte>(array);
136+
137+
// // Slice 2 elements and check
138+
// ReadOnlySpan<byte> sliced = span.Slice(0, 2);
139+
140+
// Assert.AreEqual(sliced.Length, 2, "Sliced span length must be 2");
141+
// Assert.AreEqual(sliced[0], (byte)0x00, "Sliced first element must be value 0");
142+
// Assert.AreEqual(sliced[1], (byte)0x01, "Sliced second element must be value 1");
143+
144+
// // Slice 4 elements starting at index 2 and check
145+
// sliced = span.Slice(2, 4);
146+
147+
// Assert.AreEqual(sliced.Length, 4, "Sliced span length must be 4");
148+
// Assert.AreEqual(sliced[0], (byte)0x02, "Sliced first element must be value 2");
149+
// Assert.AreEqual(sliced[1], (byte)0x03, "Sliced second element must be value 3");
150+
// Assert.AreEqual(sliced[2], (byte)0x04, "Sliced third element must be value 4");
151+
// Assert.AreEqual(sliced[3], (byte)0x05, "Sliced fourth element must be value 5");
152+
153+
// // Slice starting at element 4 and check
154+
// sliced = span.Slice(4);
155+
156+
// Assert.AreEqual(sliced.Length, 12, "Sliced span length must be 12");
157+
158+
// for (int i = 0; i < sliced.Length; i++)
159+
// {
160+
// Assert.AreEqual(sliced[i], span[i + 4], "ReadOnlySpan value should be the same as from the original span");
161+
// }
162+
163+
// // Slice of slice
164+
// ReadOnlySpan<byte> secondSliced = sliced.Slice(2, 4);
165+
166+
// Assert.AreEqual(secondSliced.Length, 4, "Sliced span length must be 4");
167+
168+
// for (int i = 0; i < secondSliced.Length; i++)
169+
// {
170+
// Assert.AreEqual(secondSliced[i], sliced[i + 2], "ReadOnlySpan value should be the same as from the original span");
171+
// }
172+
173+
// // Should be an empty one
174+
// ReadOnlySpan<byte> empty = span.Slice(span.Length);
175+
176+
// Assert.AreEqual(empty.Length, 0, "Slicing all the span should result in an empty span");
177+
// Assert.IsTrue(empty.IsEmpty, "Empty span should be empty");
178+
//}
179+
180+
//[TestMethod]
181+
//public void GetElementsTests()
182+
//{
183+
// // ReadOnlySpan from normal array
184+
// byte[] array = new byte[16] { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F };
185+
// ReadOnlySpan<byte> span = new ReadOnlySpan<byte>(array);
186+
// for (int i = 0; i < span.Length; i++)
187+
// {
188+
// Assert.AreEqual(span[i], array[i], "ReadOnlySpan value should be the same as from the original array");
189+
// }
190+
191+
// // Partial span
192+
// span = new ReadOnlySpan<byte>(array, 2, 8);
193+
// for (int i = 0; i < span.Length; i++)
194+
// {
195+
// Assert.AreEqual(span[i], array[i + 2], "ReadOnlySpan value should be the same as from the original array");
196+
// }
197+
//}
198+
199+
//[TestMethod]
200+
//public void StackAllocReadOnlySpanTests()
201+
//{
202+
// // Create a ReadOnlySpan from stack-allocated memory
203+
// ReadOnlySpan<byte> span = stackalloc byte[16];
204+
205+
// Assert.AreEqual(16, span.Length, "Stack-allocated ReadOnlySpan should have length of 16");
206+
// Assert.IsFalse(span.IsEmpty, "Stack-allocated ReadOnlySpan should NOT be IsEmpty");
207+
208+
// // Verify all elements are initialized to zero
209+
// for (int i = 0; i < span.Length; i++)
210+
// {
211+
// Assert.AreEqual((byte)0, span[i], "Stack-allocated ReadOnlySpan elements should be initialized to 0");
212+
// }
213+
//}
214+
215+
//[TestMethod]
216+
//public void StackAllocReadOnlySpanWithInitializerTests()
217+
//{
218+
// // Create a ReadOnlySpan from stack-allocated memory with initializer
219+
// ReadOnlySpan<byte> span = stackalloc byte[8] { 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08 };
220+
221+
// Assert.AreEqual(8, span.Length, "Stack-allocated ReadOnlySpan with initializer should have length of 8");
222+
// Assert.IsFalse(span.IsEmpty, "Stack-allocated ReadOnlySpan should NOT be IsEmpty");
223+
224+
// // Verify the initialized values
225+
// for (int i = 0; i < span.Length; i++)
226+
// {
227+
// Assert.AreEqual((byte)(i + 1), span[i], $"Stack-allocated ReadOnlySpan element at index {i} should be {i + 1}");
228+
// }
229+
//}
230+
231+
//[TestMethod]
232+
//public void StackAllocReadOnlySpanSliceTests()
233+
//{
234+
// // Create a ReadOnlySpan from stack-allocated memory
235+
// ReadOnlySpan<byte> span = stackalloc byte[16] { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F };
236+
237+
// // Slice the stack-allocated span
238+
// ReadOnlySpan<byte> sliced = span.Slice(4, 8);
239+
240+
// Assert.AreEqual(8, sliced.Length, "Sliced stack-allocated ReadOnlySpan should have length of 8");
241+
242+
// for (int i = 0; i < sliced.Length; i++)
243+
// {
244+
// Assert.AreEqual((byte)(i + 4), sliced[i], $"Sliced element at index {i} should be {i + 4}");
245+
// }
246+
//}
247+
248+
[TestMethod]
249+
public void StackAllocReadOnlySpanToArrayTests()
250+
{
251+
// Create a ReadOnlySpan from stack-allocated memory
252+
ReadOnlySpan<byte> span = stackalloc byte[6] { 0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF };
253+
254+
// Convert to array
255+
byte[] array = span.ToArray();
256+
257+
Assert.AreEqual(6, array.Length, "ToArray should create an array with the same length");
258+
259+
byte[] expected = new byte[] { 0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF };
260+
CollectionAssert.AreEqual(expected, array, "Stack-allocated ReadOnlySpan ToArray should match expected values");
261+
}
262+
263+
[TestMethod]
264+
public void StackAllocEmptyReadOnlySpanTests()
265+
{
266+
// Create an empty stack-allocated ReadOnlySpan
267+
ReadOnlySpan<byte> span = stackalloc byte[0];
268+
269+
Assert.AreEqual(0, span.Length, "Empty stack-allocated ReadOnlySpan should have length of 0");
270+
Assert.IsTrue(span.IsEmpty, "Empty stack-allocated ReadOnlySpan should be IsEmpty");
271+
}
272+
273+
//[TestMethod]
274+
//public void ImplicitConversionFromArrayTests()
275+
//{
276+
// // Test implicit conversion from array to ReadOnlySpan
277+
// byte[] array = new byte[8] { 0x10, 0x20, 0x30, 0x40, 0x50, 0x60, 0x70, 0x80 };
278+
279+
// ReadOnlySpan<byte> span = array; // Implicit conversion
280+
281+
// Assert.AreEqual(array.Length, span.Length, "Implicitly converted ReadOnlySpan should have same length as array");
282+
283+
// for (int i = 0; i < array.Length; i++)
284+
// {
285+
// Assert.AreEqual(array[i], span[i], $"Element at index {i} should match");
286+
// }
287+
//}
288+
289+
//[TestMethod]
290+
//public void EqualityOperatorTests()
291+
//{
292+
// byte[] array1 = new byte[4] { 0x01, 0x02, 0x03, 0x04 };
293+
// byte[] array2 = new byte[4] { 0x01, 0x02, 0x03, 0x04 };
294+
// byte[] array3 = new byte[4] { 0x01, 0x02, 0x03, 0x05 };
295+
296+
// ReadOnlySpan<byte> span1 = new ReadOnlySpan<byte>(array1);
297+
// ReadOnlySpan<byte> span2 = new ReadOnlySpan<byte>(array2);
298+
// ReadOnlySpan<byte> span3 = new ReadOnlySpan<byte>(array3);
299+
300+
// // Test equality with same content
301+
// Assert.IsTrue(span1 == span2, "ReadOnlySpans with same content should be equal");
302+
303+
// // Test inequality with different content
304+
// Assert.IsTrue(span1 != span3, "ReadOnlySpans with different content should not be equal");
305+
// Assert.IsFalse(span1 == span3, "ReadOnlySpans with different content should not be equal");
306+
307+
// // Test empty spans
308+
// ReadOnlySpan<byte> empty1 = new ReadOnlySpan<byte>();
309+
// ReadOnlySpan<byte> empty2 = new ReadOnlySpan<byte>();
310+
311+
// Assert.IsTrue(empty1 == empty2, "Empty ReadOnlySpans should be equal");
312+
//}
313+
314+
//[TestMethod]
315+
//public void ReadOnlyBehaviorTests()
316+
//{
317+
// // Verify that ReadOnlySpan protects the underlying data from modification through the span
318+
// byte[] array = new byte[4] { 0x01, 0x02, 0x03, 0x04 };
319+
// ReadOnlySpan<byte> span = new ReadOnlySpan<byte>(array);
320+
321+
// // We can read values
322+
// Assert.AreEqual((byte)0x01, span[0], "Should be able to read from ReadOnlySpan");
323+
324+
// // The following would not compile (which is the desired behavior):
325+
// // span[0] = 0xFF; // Error: Cannot assign to a readonly ref return
326+
327+
// // But we can still modify the underlying array directly
328+
// array[0] = 0xFF;
329+
// Assert.AreEqual((byte)0xFF, span[0], "Modifying underlying array should be visible through ReadOnlySpan");
330+
//}
331+
332+
//[TestMethod]
333+
//public void PartialSpanTests()
334+
//{
335+
// byte[] array = new byte[16] { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F };
336+
337+
// // Create ReadOnlySpan that covers middle portion of array
338+
// ReadOnlySpan<byte> span = new ReadOnlySpan<byte>(array, 4, 8);
339+
340+
// Assert.AreEqual(8, span.Length, "Partial ReadOnlySpan should have correct length");
341+
// Assert.AreEqual((byte)0x04, span[0], "First element should be from start index");
342+
// Assert.AreEqual((byte)0x0B, span[7], "Last element should be at start + length - 1");
343+
344+
// // Verify all elements in the partial span
345+
// for (int i = 0; i < span.Length; i++)
346+
// {
347+
// Assert.AreEqual(array[i + 4], span[i], $"Element at index {i} should match array element at {i + 4}");
348+
// }
349+
//}
350+
}
351+
}

0 commit comments

Comments
 (0)