1 ///////////////////////////////////////////////////////////////////////////////
2 //
3 // Copyright (c) 2015 Microsoft Corporation. All rights reserved.
4 //
5 // This code is licensed under the MIT License (MIT).
6 //
7 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
8 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
9 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
10 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
11 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
12 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
13 // THE SOFTWARE.
14 //
15 ///////////////////////////////////////////////////////////////////////////////
16 
17 #include <UnitTest++/UnitTest++.h>
18 #include <gsl/multi_span>
19 
20 #include <string>
21 #include <vector>
22 #include <list>
23 #include <iostream>
24 #include <memory>
25 #include <map>
26 
27 using namespace std;
28 using namespace gsl;
29 
30 namespace
31 {
32 	struct BaseClass {};
33 	struct DerivedClass : BaseClass {};
34 }
35 
SUITE(strided_span_tests)36 SUITE(strided_span_tests)
37 {
38 	TEST (span_section_test)
39 	{
40 		int a[30][4][5];
41 
42 		auto av = as_multi_span(a);
43 		auto sub = av.section({15, 0, 0}, gsl::index<3>{2, 2, 2});
44 		auto subsub = sub.section({1, 0, 0}, gsl::index<3>{1, 1, 1});
45 		(void)subsub;
46 	}
47 
48 	TEST(span_section)
49 	{
50 		std::vector<int> data(5 * 10);
51 		std::iota(begin(data), end(data), 0);
52         const multi_span<int, 5, 10> av = as_multi_span(multi_span<int>{data}, dim<5>(), dim<10>());
53 
54 		strided_span<int, 2> av_section_1 = av.section({ 1, 2 }, { 3, 4 });
55 		CHECK((av_section_1[{0, 0}] == 12));
56 		CHECK((av_section_1[{0, 1}] == 13));
57 		CHECK((av_section_1[{1, 0}] == 22));
58 		CHECK((av_section_1[{2, 3}] == 35));
59 
60 		strided_span<int, 2> av_section_2 = av_section_1.section({ 1, 2 }, { 2,2 });
61 		CHECK((av_section_2[{0, 0}] == 24));
62 		CHECK((av_section_2[{0, 1}] == 25));
63 		CHECK((av_section_2[{1, 0}] == 34));
64 	}
65 
66 	TEST(strided_span_constructors)
67 	{
68 		// Check stride constructor
69 		{
70 			int arr[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9 };
71 			const int carr[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9 };
72 
73 			strided_span<int, 1> sav1{ arr, {{9}, {1}} }; // T -> T
74 			CHECK(sav1.bounds().index_bounds() == index<1>{ 9 });
75 			CHECK(sav1.bounds().stride() == 1);
76 			CHECK(sav1[0] == 1 && sav1[8] == 9);
77 
78 
79 			strided_span<const int, 1> sav2{ carr, {{ 4 }, { 2 }} }; // const T -> const T
80 			CHECK(sav2.bounds().index_bounds() == index<1>{ 4 });
81 			CHECK(sav2.bounds().strides() == index<1>{2});
82 			CHECK(sav2[0] == 1 && sav2[3] == 7);
83 
84 			strided_span<int, 2> sav3{ arr, {{ 2, 2 },{ 6, 2 }} }; // T -> const T
85 			CHECK((sav3.bounds().index_bounds() == index<2>{ 2, 2 }));
86 			CHECK((sav3.bounds().strides() == index<2>{ 6, 2 }));
87 			CHECK((sav3[{0, 0}] == 1 && sav3[{0, 1}] == 3 && sav3[{1, 0}] == 7));
88 		}
89 
90 		// Check multi_span constructor
91 		{
92 			int arr[] = { 1, 2 };
93 
94 			// From non-cv-qualified source
95 			{
96 				const multi_span<int> src = arr;
97 
98 				strided_span<int, 1> sav{ src, {2, 1} };
99 				CHECK(sav.bounds().index_bounds() == index<1>{ 2 });
100 				CHECK(sav.bounds().strides() == index<1>{ 1 });
101 				CHECK(sav[1] == 2);
102 
103 #if _MSC_VER > 1800
104 				//strided_span<const int, 1> sav_c{ {src}, {2, 1} };
105 				strided_span<const int, 1> sav_c{ multi_span<const int>{src}, strided_bounds<1>{2, 1} };
106 #else
107 				strided_span<const int, 1> sav_c{ multi_span<const int>{src}, strided_bounds<1>{2, 1} };
108 #endif
109 				CHECK(sav_c.bounds().index_bounds() == index<1>{ 2 });
110 				CHECK(sav_c.bounds().strides() == index<1>{ 1 });
111 				CHECK(sav_c[1] == 2);
112 
113 #if _MSC_VER > 1800
114 				strided_span<volatile int, 1> sav_v{ src, {2, 1} };
115 #else
116 				strided_span<volatile int, 1> sav_v{ multi_span<volatile int>{src}, strided_bounds<1>{2, 1} };
117 #endif
118 				CHECK(sav_v.bounds().index_bounds() == index<1>{ 2 });
119 				CHECK(sav_v.bounds().strides() == index<1>{ 1 });
120 				CHECK(sav_v[1] == 2);
121 
122 #if _MSC_VER > 1800
123 				strided_span<const volatile int, 1> sav_cv{ src, {2, 1} };
124 #else
125 				strided_span<const volatile int, 1> sav_cv{ multi_span<const volatile int>{src}, strided_bounds<1>{2, 1} };
126 #endif
127 				CHECK(sav_cv.bounds().index_bounds() == index<1>{ 2 });
128 				CHECK(sav_cv.bounds().strides() == index<1>{ 1 });
129 				CHECK(sav_cv[1] == 2);
130 			}
131 
132 			// From const-qualified source
133 			{
134 				const multi_span<const int> src{ arr };
135 
136 				strided_span<const int, 1> sav_c{ src, {2, 1} };
137 				CHECK(sav_c.bounds().index_bounds() == index<1>{ 2 });
138 				CHECK(sav_c.bounds().strides() == index<1>{ 1 });
139 				CHECK(sav_c[1] == 2);
140 
141 #if _MSC_VER > 1800
142 				strided_span<const volatile int, 1> sav_cv{ src, {2, 1} };
143 #else
144 				strided_span<const volatile int, 1> sav_cv{ multi_span<const volatile int>{src}, strided_bounds<1>{2, 1} };
145 #endif
146 
147 				CHECK(sav_cv.bounds().index_bounds() == index<1>{ 2 });
148 				CHECK(sav_cv.bounds().strides() == index<1>{ 1 });
149 				CHECK(sav_cv[1] == 2);
150 			}
151 
152 			// From volatile-qualified source
153 			{
154 				const multi_span<volatile int> src{ arr };
155 
156 				strided_span<volatile int, 1> sav_v{ src, {2, 1} };
157 				CHECK(sav_v.bounds().index_bounds() == index<1>{ 2 });
158 				CHECK(sav_v.bounds().strides() == index<1>{ 1 });
159 				CHECK(sav_v[1] == 2);
160 
161 #if _MSC_VER > 1800
162 				strided_span<const volatile int, 1> sav_cv{ src, {2, 1} };
163 #else
164 				strided_span<const volatile int, 1> sav_cv{ multi_span<const volatile int>{src}, strided_bounds<1>{2, 1} };
165 #endif
166 				CHECK(sav_cv.bounds().index_bounds() == index<1>{ 2 });
167 				CHECK(sav_cv.bounds().strides() == index<1>{ 1 });
168 				CHECK(sav_cv[1] == 2);
169 			}
170 
171 			// From cv-qualified source
172 			{
173 				const multi_span<const volatile int> src{ arr };
174 
175 				strided_span<const volatile int, 1> sav_cv{ src, {2, 1} };
176 				CHECK(sav_cv.bounds().index_bounds() == index<1>{ 2 });
177 				CHECK(sav_cv.bounds().strides() == index<1>{ 1 });
178 				CHECK(sav_cv[1] == 2);
179 			}
180 		}
181 
182 		// Check const-casting constructor
183 		{
184 			int arr[2] = { 4, 5 };
185 
186 			const multi_span<int, 2> av(arr, 2);
187 			multi_span<const int, 2> av2{ av };
188 			CHECK(av2[1] == 5);
189 
190 			static_assert(std::is_convertible<const multi_span<int, 2>, multi_span<const int, 2>>::value, "ctor is not implicit!");
191 
192 			const strided_span<int, 1> src{ arr, {2, 1} };
193 			strided_span<const int, 1> sav{ src };
194 			CHECK(sav.bounds().index_bounds() == index<1>{ 2 });
195 			CHECK(sav.bounds().stride() == 1);
196 			CHECK(sav[1] == 5);
197 
198 			static_assert(std::is_convertible<const strided_span<int, 1>, strided_span<const int, 1>>::value, "ctor is not implicit!");
199 		}
200 
201 		// Check copy constructor
202 		{
203 			int arr1[2] = { 3, 4 };
204 			const strided_span<int, 1> src1{ arr1, {2, 1} };
205 			strided_span<int, 1> sav1{ src1 };
206 
207 			CHECK(sav1.bounds().index_bounds() == index<1>{ 2 });
208 			CHECK(sav1.bounds().stride() == 1);
209 			CHECK(sav1[0] == 3);
210 
211 			int arr2[6] = { 1, 2, 3, 4, 5, 6 };
212 			const strided_span<const int, 2> src2{ arr2, {{ 3, 2 }, { 2, 1 }} };
213 			strided_span<const int, 2> sav2{ src2 };
214 			CHECK((sav2.bounds().index_bounds() == index<2>{ 3, 2 }));
215 			CHECK((sav2.bounds().strides() == index<2>{ 2, 1 }));
216 			CHECK((sav2[{0, 0}] == 1 && sav2[{2, 0}] == 5));
217 		}
218 
219 		// Check const-casting assignment operator
220 		{
221 			int arr1[2] = { 1, 2 };
222 			int arr2[6] = { 3, 4, 5, 6, 7, 8 };
223 
224 			const strided_span<int, 1> src{ arr1, {{2}, {1}} };
225 			strided_span<const int, 1> sav{ arr2, {{3}, {2}} };
226 			strided_span<const int, 1>& sav_ref = (sav = src);
227 			CHECK(sav.bounds().index_bounds() == index<1>{ 2 });
228 			CHECK(sav.bounds().strides() == index<1>{ 1 });
229 			CHECK(sav[0] == 1);
230 			CHECK(&sav_ref == &sav);
231 		}
232 
233 		// Check copy assignment operator
234 		{
235 			int arr1[2] = { 3, 4 };
236 			int arr1b[1] = { 0 };
237 			const strided_span<int, 1> src1{ arr1, {2, 1} };
238 			strided_span<int, 1> sav1{ arr1b, {1, 1} };
239 			strided_span<int, 1>& sav1_ref = (sav1 = src1);
240 			CHECK(sav1.bounds().index_bounds() == index<1>{ 2 });
241 			CHECK(sav1.bounds().strides() == index<1>{ 1 });
242 			CHECK(sav1[0] == 3);
243 			CHECK(&sav1_ref == &sav1);
244 
245 			const int arr2[6] = { 1, 2, 3, 4, 5, 6 };
246 			const int arr2b[1] = { 0 };
247 			const strided_span<const int, 2> src2{ arr2, {{ 3, 2 },{ 2, 1 }} };
248 			strided_span<const int, 2> sav2{ arr2b, {{ 1, 1 },{ 1, 1 }} };
249 			strided_span<const int, 2>& sav2_ref = (sav2 = src2);
250 			CHECK((sav2.bounds().index_bounds() == index<2>{ 3, 2 }));
251 			CHECK((sav2.bounds().strides() == index<2>{ 2, 1 }));
252 			CHECK((sav2[{0, 0}] == 1 && sav2[{2, 0}] == 5));
253 			CHECK(&sav2_ref == &sav2);
254 		}
255 	}
256 
257 	TEST(strided_span_slice)
258 	{
259 		std::vector<int> data(5 * 10);
260 		std::iota(begin(data), end(data), 0);
261         const multi_span<int, 5, 10> src = as_multi_span(multi_span<int>{data}, dim<5>(), dim<10>());
262 
263 		const strided_span<int, 2> sav{ src, {{5, 10}, {10, 1}} };
264 #ifdef CONFIRM_COMPILATION_ERRORS
265 		const strided_span<const int, 2> csav{ {src},{ { 5, 10 },{ 10, 1 } } };
266 #endif
267 		const strided_span<const int, 2> csav{ multi_span<const int, 5, 10>{ src }, { { 5, 10 },{ 10, 1 } } };
268 
269 		strided_span<int, 1> sav_sl = sav[2];
270 		CHECK(sav_sl[0] == 20);
271 		CHECK(sav_sl[9] == 29);
272 
273 		strided_span<const int, 1> csav_sl = sav[3];
274 		CHECK(csav_sl[0] == 30);
275 		CHECK(csav_sl[9] == 39);
276 
277 		CHECK(sav[4][0] == 40);
278 		CHECK(sav[4][9] == 49);
279 	}
280 
281 	TEST(strided_span_column_major)
282 	{
283 		// strided_span may be used to accomodate more peculiar
284 		// use cases, such as column-major multidimensional array
285 		// (aka. "FORTRAN" layout).
286 
287 		int cm_array[3 * 5] = {
288 			1, 4, 7, 10, 13,
289 			2, 5, 8, 11, 14,
290 			3, 6, 9, 12, 15
291 		};
292 		strided_span<int, 2> cm_sav{ cm_array, {{ 5, 3 },{ 1, 5 }} };
293 
294 		// Accessing elements
295 		CHECK((cm_sav[{0, 0}] == 1));
296 		CHECK((cm_sav[{0, 1}] == 2));
297 		CHECK((cm_sav[{1, 0}] == 4));
298 		CHECK((cm_sav[{4, 2}] == 15));
299 
300 		// Slice
301 		strided_span<int, 1> cm_sl = cm_sav[3];
302 
303 		CHECK(cm_sl[0] == 10);
304 		CHECK(cm_sl[1] == 11);
305 		CHECK(cm_sl[2] == 12);
306 
307 		// Section
308 		strided_span<int, 2> cm_sec = cm_sav.section( { 2, 1 }, { 3, 2 });
309 
310 		CHECK((cm_sec.bounds().index_bounds() == index<2>{3, 2}));
311 		CHECK((cm_sec[{0, 0}] == 8));
312 		CHECK((cm_sec[{0, 1}] == 9));
313 		CHECK((cm_sec[{1, 0}] == 11));
314 		CHECK((cm_sec[{2, 1}] == 15));
315 	}
316 
317 	TEST(strided_span_bounds)
318 	{
319 		int arr[] = { 0, 1, 2, 3 };
320 		multi_span<int> av(arr);
321 
322 		{
323 			// incorrect sections
324 
325 			CHECK_THROW(av.section(0, 0)[0], fail_fast);
326 			CHECK_THROW(av.section(1, 0)[0], fail_fast);
327 			CHECK_THROW(av.section(1, 1)[1], fail_fast);
328 
329 			CHECK_THROW(av.section(2, 5), fail_fast);
330 			CHECK_THROW(av.section(5, 2), fail_fast);
331 			CHECK_THROW(av.section(5, 0), fail_fast);
332 			CHECK_THROW(av.section(0, 5), fail_fast);
333 			CHECK_THROW(av.section(5, 5), fail_fast);
334 		}
335 
336 		{
337 			// zero stride
338 			strided_span<int, 1> sav{ av,{ { 4 },{} } };
339 			CHECK(sav[0] == 0);
340 			CHECK(sav[3] == 0);
341 			CHECK_THROW(sav[4], fail_fast);
342 		}
343 
344 		{
345 			// zero extent
346 			strided_span<int, 1> sav{ av,{ {},{ 1 } } };
347 			CHECK_THROW(sav[0], fail_fast);
348 		}
349 
350 		{
351 			// zero extent and stride
352 			strided_span<int, 1> sav{ av,{ {},{} } };
353 			CHECK_THROW(sav[0], fail_fast);
354 		}
355 
356 		{
357 			// strided array ctor with matching strided bounds
358 			strided_span<int, 1> sav{ arr,{ 4, 1 } };
359 			CHECK(sav.bounds().index_bounds() == index<1>{ 4 });
360 			CHECK(sav[3] == 3);
361 			CHECK_THROW(sav[4], fail_fast);
362 		}
363 
364 		{
365 			// strided array ctor with smaller strided bounds
366 			strided_span<int, 1> sav{ arr,{ 2, 1 } };
367 			CHECK(sav.bounds().index_bounds() == index<1>{ 2 });
368 			CHECK(sav[1] == 1);
369 			CHECK_THROW(sav[2], fail_fast);
370 		}
371 
372 		{
373 			// strided array ctor with fitting irregular bounds
374 			strided_span<int, 1> sav{ arr,{ 2, 3 } };
375 			CHECK(sav.bounds().index_bounds() == index<1>{ 2 });
376 			CHECK(sav[0] == 0);
377 			CHECK(sav[1] == 3);
378 			CHECK_THROW(sav[2], fail_fast);
379 		}
380 
381 		{
382 			// bounds cross data boundaries - from static arrays
383 			CHECK_THROW((strided_span<int, 1> { arr, { 3, 2 } }), fail_fast);
384 			CHECK_THROW((strided_span<int, 1> { arr, { 3, 3 } }), fail_fast);
385 			CHECK_THROW((strided_span<int, 1> { arr, { 4, 5 } }), fail_fast);
386 			CHECK_THROW((strided_span<int, 1> { arr, { 5, 1 } }), fail_fast);
387 			CHECK_THROW((strided_span<int, 1> { arr, { 5, 5 } }), fail_fast);
388 		}
389 
390 		{
391 			// bounds cross data boundaries - from array view
392 			CHECK_THROW((strided_span<int, 1> { av, { 3, 2 } }), fail_fast);
393 			CHECK_THROW((strided_span<int, 1> { av, { 3, 3 } }), fail_fast);
394 			CHECK_THROW((strided_span<int, 1> { av, { 4, 5 } }), fail_fast);
395 			CHECK_THROW((strided_span<int, 1> { av, { 5, 1 } }), fail_fast);
396 			CHECK_THROW((strided_span<int, 1> { av, { 5, 5 } }), fail_fast);
397 		}
398 
399 		{
400 			// bounds cross data boundaries - from dynamic arrays
401 			CHECK_THROW((strided_span<int, 1> { av.data(), 4, { 3, 2 } }), fail_fast);
402 			CHECK_THROW((strided_span<int, 1> { av.data(), 4, { 3, 3 } }), fail_fast);
403 			CHECK_THROW((strided_span<int, 1> { av.data(), 4, { 4, 5 } }), fail_fast);
404 			CHECK_THROW((strided_span<int, 1> { av.data(), 4, { 5, 1 } }), fail_fast);
405 			CHECK_THROW((strided_span<int, 1> { av.data(), 4, { 5, 5 } }), fail_fast);
406 			CHECK_THROW((strided_span<int, 1> { av.data(), 2, { 2, 2 } }), fail_fast);
407 		}
408 
409 #ifdef CONFIRM_COMPILATION_ERRORS
410 		{
411 			strided_span<int, 1> sav0{ av.data(), { 3, 2 } };
412 			strided_span<int, 1> sav1{ arr, { 1 } };
413 			strided_span<int, 1> sav2{ arr, { 1,1,1 } };
414 			strided_span<int, 1> sav3{ av, { 1 } };
415 			strided_span<int, 1> sav4{ av, { 1,1,1 } };
416 			strided_span<int, 2> sav5{ av.as_multi_span(dim<2>(), dim<2>()), { 1 } };
417 			strided_span<int, 2> sav6{ av.as_multi_span(dim<2>(), dim<2>()), { 1,1,1 } };
418 			strided_span<int, 2> sav7{ av.as_multi_span(dim<2>(), dim<2>()), { { 1,1 },{ 1,1 },{ 1,1 } } };
419 
420 			index<1> index{ 0, 1 };
421 			strided_span<int, 1> sav8{ arr,{ 1,{ 1,1 } } };
422 			strided_span<int, 1> sav9{ arr,{ { 1,1 },{ 1,1 } } };
423 			strided_span<int, 1> sav10{ av,{ 1,{ 1,1 } } };
424 			strided_span<int, 1> sav11{ av,{ { 1,1 },{ 1,1 } } };
425 			strided_span<int, 2> sav12{ av.as_multi_span(dim<2>(), dim<2>()),{ { 1 },{ 1 } } };
426 			strided_span<int, 2> sav13{ av.as_multi_span(dim<2>(), dim<2>()),{ { 1 },{ 1,1,1 } } };
427 			strided_span<int, 2> sav14{ av.as_multi_span(dim<2>(), dim<2>()),{ { 1,1,1 },{ 1 } } };
428 		}
429 #endif
430 	}
431 
432 	TEST(strided_span_type_conversion)
433 	{
434 		int arr[] = { 0, 1, 2, 3 };
435 		multi_span<int> av(arr);
436 
437 		{
438 			strided_span<int, 1> sav{ av.data(), av.size(), { av.size() / 2, 2 } };
439 #ifdef CONFIRM_COMPILATION_ERRORS
440 			strided_span<long, 1> lsav1 = sav.as_strided_span<long, 1>();
441 #endif
442 		}
443 		{
444 			strided_span<int, 1> sav{ av, { av.size() / 2, 2 } };
445 #ifdef CONFIRM_COMPILATION_ERRORS
446 			strided_span<long, 1> lsav1 = sav.as_strided_span<long, 1>();
447 #endif
448 		}
449 
450 		multi_span<const byte, dynamic_range> bytes = as_bytes(av);
451 
452 		// retype strided array with regular strides - from raw data
453 		{
454 			strided_bounds<2> bounds{ { 2, bytes.size() / 4 }, { bytes.size() / 2, 1 } };
455 			strided_span<const byte, 2> sav2{ bytes.data(), bytes.size(), bounds };
456 			strided_span<const int, 2> sav3 = sav2.as_strided_span<const int>();
457 			CHECK(sav3[0][0] == 0);
458 			CHECK(sav3[1][0] == 2);
459 			CHECK_THROW(sav3[1][1], fail_fast);
460 			CHECK_THROW(sav3[0][1], fail_fast);
461 		}
462 
463 		// retype strided array with regular strides - from multi_span
464 		{
465 			strided_bounds<2> bounds{ { 2, bytes.size() / 4 }, { bytes.size() / 2, 1 } };
466 			multi_span<const byte, 2, dynamic_range> bytes2 = as_multi_span(bytes, dim<2>(), dim(bytes.size() / 2));
467 			strided_span<const byte, 2> sav2{ bytes2, bounds };
468 			strided_span<int, 2> sav3 = sav2.as_strided_span<int>();
469 			CHECK(sav3[0][0] == 0);
470 			CHECK(sav3[1][0] == 2);
471 			CHECK_THROW(sav3[1][1], fail_fast);
472 			CHECK_THROW(sav3[0][1], fail_fast);
473 		}
474 
475 		// retype strided array with not enough elements - last dimension of the array is too small
476 		{
477 			strided_bounds<2> bounds{ { 4,2 },{ 4, 1 } };
478 			multi_span<const byte, 2, dynamic_range> bytes2 = as_multi_span(bytes, dim<2>(), dim(bytes.size() / 2));
479 			strided_span<const byte, 2> sav2{ bytes2, bounds };
480 			CHECK_THROW(sav2.as_strided_span<int>(), fail_fast);
481 		}
482 
483 		// retype strided array with not enough elements - strides are too small
484 		{
485 			strided_bounds<2> bounds{ { 4,2 },{ 2, 1 } };
486 			multi_span<const byte, 2, dynamic_range> bytes2 = as_multi_span(bytes, dim<2>(), dim(bytes.size() / 2));
487 			strided_span<const byte, 2> sav2{ bytes2, bounds };
488 			CHECK_THROW(sav2.as_strided_span<int>(), fail_fast);
489 		}
490 
491 		// retype strided array with not enough elements - last dimension does not divide by the new typesize
492 		{
493 			strided_bounds<2> bounds{ { 2,6 },{ 4, 1 } };
494 			multi_span<const byte, 2, dynamic_range> bytes2 = as_multi_span(bytes, dim<2>(), dim(bytes.size() / 2));
495 			strided_span<const byte, 2> sav2{ bytes2, bounds };
496 			CHECK_THROW(sav2.as_strided_span<int>(), fail_fast);
497 		}
498 
499 		// retype strided array with not enough elements - strides does not divide by the new typesize
500 		{
501 			strided_bounds<2> bounds{ { 2, 1 },{ 6, 1 } };
502 			multi_span<const byte, 2, dynamic_range> bytes2 = as_multi_span(bytes, dim<2>(), dim(bytes.size() / 2));
503 			strided_span<const byte, 2> sav2{ bytes2, bounds };
504 			CHECK_THROW(sav2.as_strided_span<int>(), fail_fast);
505 		}
506 
507 		// retype strided array with irregular strides - from raw data
508 		{
509 			strided_bounds<1> bounds{ bytes.size() / 2, 2 };
510 			strided_span<const byte, 1> sav2{ bytes.data(), bytes.size(), bounds };
511 			CHECK_THROW(sav2.as_strided_span<int>(), fail_fast);
512 		}
513 
514 		// retype strided array with irregular strides - from multi_span
515 		{
516 			strided_bounds<1> bounds{ bytes.size() / 2, 2 };
517 			strided_span<const byte, 1> sav2{ bytes, bounds };
518 			CHECK_THROW(sav2.as_strided_span<int>(), fail_fast);
519 		}
520 	}
521 
522 	TEST(empty_strided_spans)
523 	{
524 		{
525 			multi_span<int, 0> empty_av(nullptr);
526 			strided_span<int, 1> empty_sav{ empty_av, { 0, 1 } };
527 
528 			CHECK(empty_sav.bounds().index_bounds() == index<1>{ 0 });
529 			CHECK_THROW(empty_sav[0], fail_fast);
530 			CHECK_THROW(empty_sav.begin()[0], fail_fast);
531 			CHECK_THROW(empty_sav.cbegin()[0], fail_fast);
532 
533 			for (auto& v : empty_sav)
534 			{
535                 (void)v;
536 				CHECK(false);
537 			}
538 		}
539 
540 		{
541 			strided_span<int, 1> empty_sav{ nullptr, 0, { 0, 1 } };
542 
543 			CHECK(empty_sav.bounds().index_bounds() == index<1>{ 0 });
544 			CHECK_THROW(empty_sav[0], fail_fast);
545 			CHECK_THROW(empty_sav.begin()[0], fail_fast);
546 			CHECK_THROW(empty_sav.cbegin()[0], fail_fast);
547 
548 			for (auto& v : empty_sav)
549 			{
550                 (void)v;
551 				CHECK(false);
552 			}
553 		}
554 	}
555 
556     void iterate_every_other_element(multi_span<int, dynamic_range> av)
557     {
558         // pick every other element
559 
560         auto length = av.size() / 2;
561 #if _MSC_VER > 1800
562         auto bounds = strided_bounds<1>({length}, {2});
563 #else
564         auto bounds = strided_bounds<1>(index<1>{ length }, index<1>{ 2 });
565 #endif
566         strided_span<int, 1> strided(&av.data()[1], av.size() - 1, bounds);
567 
568         CHECK(strided.size() == length);
569         CHECK(strided.bounds().index_bounds()[0] == length);
570         for (auto i = 0; i < strided.size(); ++i)
571         {
572             CHECK(strided[i] == av[2 * i + 1]);
573         }
574 
575         int idx = 0;
576         for (auto num : strided)
577         {
578             CHECK(num == av[2 * idx + 1]);
579             idx++;
580         }
581     }
582 
583     TEST(strided_span_section_iteration)
584     {
585         int arr[8] = {4,0,5,1,6,2,7,3};
586 
587         // static bounds
588         {
589             multi_span<int, 8> av(arr, 8);
590             iterate_every_other_element(av);
591         }
592 
593         // dynamic bounds
594         {
595             multi_span<int, dynamic_range> av(arr, 8);
596             iterate_every_other_element(av);
597         }
598     }
599 
600     TEST(dynamic_strided_span_section_iteration)
601     {
602         auto arr = new int[8];
603         for (int i = 0; i < 4; ++i)
604         {
605             arr[2 * i] = 4 + i;
606             arr[2 * i + 1] = i;
607         }
608 
609         auto av = as_multi_span(arr, 8);
610         iterate_every_other_element(av);
611 
612         delete[] arr;
613     }
614 
615     void iterate_second_slice(multi_span<int, dynamic_range, dynamic_range, dynamic_range> av)
616     {
617         int expected[6] = {2,3,10,11,18,19};
618         auto section = av.section({0,1,0}, {3,1,2});
619 
620         for (auto i = 0; i < section.extent<0>(); ++i)
621         {
622             for (auto j = 0; j < section.extent<1>(); ++j)
623                 for (auto k = 0; k < section.extent<2>(); ++k)
624                 {
625                     auto idx = index<3>{i,j,k}; // avoid braces in the CHECK macro
626                     CHECK(section[idx] == expected[2 * i + 2 * j + k]);
627                 }
628         }
629 
630         for (auto i = 0; i < section.extent<0>(); ++i)
631         {
632             for (auto j = 0; j < section.extent<1>(); ++j)
633                 for (auto k = 0; k < section.extent<2>(); ++k)
634                     CHECK(section[i][j][k] == expected[2 * i + 2 * j + k]);
635         }
636 
637         int i = 0;
638         for (auto num : section)
639         {
640             CHECK(num == expected[i]);
641             i++;
642         }
643     }
644 
645     TEST(strided_span_section_iteration_3d)
646     {
647         int arr[3][4][2];
648         for (auto i = 0; i < 3; ++i)
649         {
650             for (auto j = 0; j < 4; ++j)
651                 for (auto k = 0; k < 2; ++k)
652                     arr[i][j][k] = 8 * i + 2 * j + k;
653         }
654 
655         {
656             multi_span<int, 3, 4, 2> av = arr;
657             iterate_second_slice(av);
658         }
659     }
660 
661     TEST(dynamic_strided_span_section_iteration_3d)
662     {
663         auto height = 12, width = 2;
664         auto size = height * width;
665 
666         auto arr = new int[size];
667         for (auto i = 0; i < size; ++i)
668         {
669             arr[i] = i;
670         }
671 
672         {
673             auto av = as_multi_span(as_multi_span(arr, 24), dim<3>(), dim<4>(), dim<2>());
674             iterate_second_slice(av);
675         }
676 
677         {
678             auto av = as_multi_span(as_multi_span(arr, 24), dim(3), dim<4>(), dim<2>());
679             iterate_second_slice(av);
680         }
681 
682         {
683             auto av = as_multi_span(as_multi_span(arr, 24), dim<3>(), dim(4), dim<2>());
684             iterate_second_slice(av);
685         }
686 
687         {
688             auto av = as_multi_span(as_multi_span(arr, 24), dim<3>(), dim<4>(), dim(2));
689             iterate_second_slice(av);
690         }
691         delete[] arr;
692     }
693 
694     TEST(strided_span_conversion)
695     {
696         // get an multi_span of 'c' values from the list of X's
697 
698         struct X { int a; int b; int c; };
699 
700         X arr[4] = {{0,1,2},{3,4,5},{6,7,8},{9,10,11}};
701 
702         int s = sizeof(int) / sizeof(byte);
703         auto d2 = 3 * s;
704         auto d1 = sizeof(int) * 12 / d2;
705 
706         // convert to 4x12 array of bytes
707         auto av = as_multi_span(as_bytes(as_multi_span(arr, 4)), dim(d1), dim(d2));
708 
709         CHECK(av.bounds().index_bounds()[0] == 4);
710         CHECK(av.bounds().index_bounds()[1] == 12);
711 
712         // get the last 4 columns
713         auto section = av.section({0, 2 * s}, {4, s}); // { { arr[0].c[0], arr[0].c[1], arr[0].c[2], arr[0].c[3] } , { arr[1].c[0], ... } , ... }
714 
715                                                        // convert to array 4x1 array of integers
716         auto cs = section.as_strided_span<int>(); // { { arr[0].c }, {arr[1].c } , ... }
717 
718         CHECK(cs.bounds().index_bounds()[0] == 4);
719         CHECK(cs.bounds().index_bounds()[1] == 1);
720 
721         // transpose to 1x4 array
722         strided_bounds<2> reverse_bounds{
723             {cs.bounds().index_bounds()[1] , cs.bounds().index_bounds()[0]},
724             {cs.bounds().strides()[1], cs.bounds().strides()[0]}
725         };
726 
727         strided_span<int, 2> transposed{cs.data(), cs.bounds().total_size(), reverse_bounds};
728 
729         // slice to get a one-dimensional array of c's
730         strided_span<int, 1> result = transposed[0];
731 
732         CHECK(result.bounds().index_bounds()[0] == 4);
733         CHECK_THROW(result.bounds().index_bounds()[1], fail_fast);
734 
735         int i = 0;
736         for (auto& num : result)
737         {
738             CHECK(num == arr[i].c);
739             i++;
740         }
741 
742     }
743 }
744 
main(int,const char * [])745 int main(int, const char *[])
746 {
747 	return UnitTest::RunAllTests();
748 }
749