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 <iostream>
21 #include <list>
22 #include <map>
23 #include <memory>
24 #include <string>
25 #include <vector>
26
27 using namespace std;
28 using namespace gsl;
29
30 namespace
31 {
32 struct BaseClass
33 {
34 };
35 struct DerivedClass : BaseClass
36 {
37 };
38 }
39
SUITE(multi_span_tests)40 SUITE(multi_span_tests)
41 {
42
43 TEST(default_constructor)
44 {
45 {
46 multi_span<int> s;
47 CHECK(s.length() == 0 && s.data() == nullptr);
48
49 multi_span<const int> cs;
50 CHECK(cs.length() == 0 && cs.data() == nullptr);
51 }
52
53 {
54 multi_span<int, 0> s;
55 CHECK(s.length() == 0 && s.data() == nullptr);
56
57 multi_span<const int, 0> cs;
58 CHECK(cs.length() == 0 && cs.data() == nullptr);
59 }
60
61 {
62 #ifdef CONFIRM_COMPILATION_ERRORS
63 multi_span<int, 1> s;
64 CHECK(s.length() == 1 && s.data() == nullptr); // explains why it can't compile
65 #endif
66 }
67
68 {
69 multi_span<int> s{};
70 CHECK(s.length() == 0 && s.data() == nullptr);
71
72 multi_span<const int> cs{};
73 CHECK(cs.length() == 0 && cs.data() == nullptr);
74 }
75 }
76
77 TEST(from_nullptr_constructor)
78 {
79 {
80 multi_span<int> s = nullptr;
81 CHECK(s.length() == 0 && s.data() == nullptr);
82
83 multi_span<const int> cs = nullptr;
84 CHECK(cs.length() == 0 && cs.data() == nullptr);
85 }
86
87 {
88 multi_span<int, 0> s = nullptr;
89 CHECK(s.length() == 0 && s.data() == nullptr);
90
91 multi_span<const int, 0> cs = nullptr;
92 CHECK(cs.length() == 0 && cs.data() == nullptr);
93 }
94
95 {
96 #ifdef CONFIRM_COMPILATION_ERRORS
97 multi_span<int, 1> s = nullptr;
98 CHECK(s.length() == 1 && s.data() == nullptr); // explains why it can't compile
99 #endif
100 }
101
102 {
103 multi_span<int> s{nullptr};
104 CHECK(s.length() == 0 && s.data() == nullptr);
105
106 multi_span<const int> cs{nullptr};
107 CHECK(cs.length() == 0 && cs.data() == nullptr);
108 }
109
110 {
111 multi_span<int*> s{nullptr};
112 CHECK(s.length() == 0 && s.data() == nullptr);
113
114 multi_span<const int*> cs{nullptr};
115 CHECK(cs.length() == 0 && cs.data() == nullptr);
116 }
117 }
118
119 TEST(from_nullptr_length_constructor)
120 {
121 {
122 multi_span<int> s{nullptr, 0};
123 CHECK(s.length() == 0 && s.data() == nullptr);
124
125 multi_span<const int> cs{nullptr, 0};
126 CHECK(cs.length() == 0 && cs.data() == nullptr);
127 }
128
129 {
130 multi_span<int, 0> s{nullptr, 0};
131 CHECK(s.length() == 0 && s.data() == nullptr);
132
133 multi_span<const int, 0> cs{nullptr, 0};
134 CHECK(cs.length() == 0 && cs.data() == nullptr);
135 }
136
137 {
138 #ifdef CONFIRM_COMPILATION_ERRORS
139 multi_span<int, 1> s{nullptr, 0};
140 CHECK(s.length() == 1 && s.data() == nullptr); // explains why it can't compile
141 #endif
142 }
143
144 {
145 auto workaround_macro = []() { multi_span<int> s{nullptr, 1}; };
146 CHECK_THROW(workaround_macro(), fail_fast);
147
148 auto const_workaround_macro = []() { multi_span<const int> cs{nullptr, 1}; };
149 CHECK_THROW(const_workaround_macro(), fail_fast);
150 }
151
152 {
153 auto workaround_macro = []() { multi_span<int, 0> s{nullptr, 1}; };
154 CHECK_THROW(workaround_macro(), fail_fast);
155
156 auto const_workaround_macro = []() { multi_span<const int, 0> s{nullptr, 1}; };
157 CHECK_THROW(const_workaround_macro(), fail_fast);
158 }
159
160 {
161 multi_span<int*> s{nullptr, 0};
162 CHECK(s.length() == 0 && s.data() == nullptr);
163
164 multi_span<const int*> cs{nullptr, 0};
165 CHECK(cs.length() == 0 && cs.data() == nullptr);
166 }
167 }
168
169 TEST(from_element_constructor)
170 {
171 int i = 5;
172
173 {
174 multi_span<int> s = i;
175 CHECK(s.length() == 1 && s.data() == &i);
176 CHECK(s[0] == 5);
177
178 multi_span<const int> cs = i;
179 CHECK(cs.length() == 1 && cs.data() == &i);
180 CHECK(cs[0] == 5);
181 }
182
183 {
184 #ifdef CONFIRM_COMPILATION_ERRORS
185 const j = 1;
186 multi_span<int, 0> s = j;
187 #endif
188 }
189
190 {
191 #ifdef CONFIRM_COMPILATION_ERRORS
192 multi_span<int, 0> s = i;
193 CHECK(s.length() == 0 && s.data() == &i);
194 #endif
195 }
196
197 {
198 multi_span<int, 1> s = i;
199 CHECK(s.length() == 1 && s.data() == &i);
200 CHECK(s[0] == 5);
201 }
202
203 {
204 #ifdef CONFIRM_COMPILATION_ERRORS
205 multi_span<int, 2> s = i;
206 CHECK(s.length() == 2 && s.data() == &i);
207 #endif
208 }
209
210 {
211 #ifdef CONFIRM_COMPILATION_ERRORS
212 auto get_a_temp = []() -> int { return 4; };
213 auto use_a_span = [](multi_span<int> s) { (void) s; };
214 use_a_span(get_a_temp());
215 #endif
216 }
217 }
218
219 TEST(from_pointer_length_constructor)
220 {
221 int arr[4] = {1, 2, 3, 4};
222
223 {
224 multi_span<int> s{&arr[0], 2};
225 CHECK(s.length() == 2 && s.data() == &arr[0]);
226 CHECK(s[0] == 1 && s[1] == 2);
227 }
228
229 {
230 multi_span<int, 2> s{&arr[0], 2};
231 CHECK(s.length() == 2 && s.data() == &arr[0]);
232 CHECK(s[0] == 1 && s[1] == 2);
233 }
234
235 {
236 int* p = nullptr;
237 multi_span<int> s{p, 0};
238 CHECK(s.length() == 0 && s.data() == nullptr);
239 }
240
241 {
242 int* p = nullptr;
243 auto workaround_macro = [=]() { multi_span<int> s{p, 2}; };
244 CHECK_THROW(workaround_macro(), fail_fast);
245 }
246 }
247
248 TEST(from_pointer_pointer_constructor)
249 {
250 int arr[4] = {1, 2, 3, 4};
251
252 {
253 multi_span<int> s{&arr[0], &arr[2]};
254 CHECK(s.length() == 2 && s.data() == &arr[0]);
255 CHECK(s[0] == 1 && s[1] == 2);
256 }
257
258 {
259 multi_span<int, 2> s{&arr[0], &arr[2]};
260 CHECK(s.length() == 2 && s.data() == &arr[0]);
261 CHECK(s[0] == 1 && s[1] == 2);
262 }
263
264 {
265 multi_span<int> s{&arr[0], &arr[0]};
266 CHECK(s.length() == 0 && s.data() == &arr[0]);
267 }
268
269 {
270 multi_span<int, 0> s{&arr[0], &arr[0]};
271 CHECK(s.length() == 0 && s.data() == &arr[0]);
272 }
273
274 {
275 auto workaround_macro = [&]() { multi_span<int> s{&arr[1], &arr[0]}; };
276 CHECK_THROW(workaround_macro(), fail_fast);
277 }
278
279 {
280 int* p = nullptr;
281 auto workaround_macro = [&]() { multi_span<int> s{&arr[0], p}; };
282 CHECK_THROW(workaround_macro(), fail_fast);
283 }
284
285 {
286 int* p = nullptr;
287 auto workaround_macro = [&]() { multi_span<int> s{p, p}; };
288 CHECK_THROW(workaround_macro(), fail_fast);
289 }
290
291 {
292 int* p = nullptr;
293 auto workaround_macro = [&]() { multi_span<int> s{&arr[0], p}; };
294 CHECK_THROW(workaround_macro(), fail_fast);
295 }
296 }
297
298 TEST(from_array_constructor)
299 {
300 int arr[5] = {1, 2, 3, 4, 5};
301
302 {
303 multi_span<int> s{arr};
304 CHECK(s.length() == 5 && s.data() == &arr[0]);
305 }
306
307 {
308 multi_span<int, 5> s{arr};
309 CHECK(s.length() == 5 && s.data() == &arr[0]);
310 }
311
312 {
313 #ifdef CONFIRM_COMPILATION_ERRORS
314 multi_span<int, 6> s{arr};
315 #endif
316 }
317
318 {
319 multi_span<int, 0> s{arr};
320 CHECK(s.length() == 0 && s.data() == &arr[0]);
321 }
322
323 int arr2d[2][3] = {1, 2, 3, 4, 5, 6};
324
325 {
326 multi_span<int> s{arr2d};
327 CHECK(s.length() == 6 && s.data() == &arr2d[0][0]);
328 CHECK(s[0] == 1 && s[5] == 6);
329 }
330
331 {
332 multi_span<int, 0> s{arr2d};
333 CHECK(s.length() == 0 && s.data() == &arr2d[0][0]);
334 }
335
336 {
337 #ifdef CONFIRM_COMPILATION_ERRORS
338 multi_span<int, 5> s{arr2d};
339 #endif
340 }
341
342 {
343 multi_span<int, 6> s{arr2d};
344 CHECK(s.length() == 6 && s.data() == &arr2d[0][0]);
345 CHECK(s[0] == 1 && s[5] == 6);
346 }
347
348 {
349 #ifdef CONFIRM_COMPILATION_ERRORS
350 multi_span<int, 7> s{arr2d};
351 #endif
352 }
353
354 {
355 multi_span<int[3]> s{arr2d[0]};
356 CHECK(s.length() == 1 && s.data() == &arr2d[0]);
357 }
358
359 {
360 multi_span<int, 2, 3> s{arr2d};
361 CHECK(s.length() == 6 && s.data() == &arr2d[0][0]);
362 auto workaround_macro = [&]() { return s[{1, 2}] == 6; };
363 CHECK(workaround_macro());
364 }
365
366 {
367 #ifdef CONFIRM_COMPILATION_ERRORS
368 multi_span<int, 3, 3> s{arr2d};
369 #endif
370 }
371
372 int arr3d[2][3][2] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12};
373
374 {
375 multi_span<int> s{arr3d};
376 CHECK(s.length() == 12 && s.data() == &arr3d[0][0][0]);
377 CHECK(s[0] == 1 && s[11] == 12);
378 }
379
380 {
381 multi_span<int, 0> s{arr3d};
382 CHECK(s.length() == 0 && s.data() == &arr3d[0][0][0]);
383 }
384
385 {
386 #ifdef CONFIRM_COMPILATION_ERRORS
387 multi_span<int, 11> s{arr3d};
388 #endif
389 }
390
391 {
392 multi_span<int, 12> s{arr3d};
393 CHECK(s.length() == 12 && s.data() == &arr3d[0][0][0]);
394 CHECK(s[0] == 1 && s[5] == 6);
395 }
396
397 {
398 #ifdef CONFIRM_COMPILATION_ERRORS
399 multi_span<int, 13> s{arr3d};
400 #endif
401 }
402
403 {
404 multi_span<int[3][2]> s{arr3d[0]};
405 CHECK(s.length() == 1 && s.data() == &arr3d[0]);
406 }
407
408 {
409 multi_span<int, 3, 2, 2> s{arr3d};
410 CHECK(s.length() == 12 && s.data() == &arr3d[0][0][0]);
411 auto workaround_macro = [&]() { return s[{2, 1, 0}] == 11; };
412 CHECK(workaround_macro());
413 }
414
415 {
416 #ifdef CONFIRM_COMPILATION_ERRORS
417 multi_span<int, 3, 3, 3> s{arr3d};
418 #endif
419 }
420 }
421
422 TEST(from_dynamic_array_constructor)
423 {
424 double(*arr)[3][4] = new double[100][3][4];
425
426 {
427 multi_span<double, dynamic_range, 3, 4> s(arr, 10);
428 CHECK(s.length() == 120 && s.data() == &arr[0][0][0]);
429 CHECK_THROW(s[10][3][4], fail_fast);
430 }
431
432 {
433 multi_span<double, dynamic_range, 4, 3> s(arr, 10);
434 CHECK(s.length() == 120 && s.data() == &arr[0][0][0]);
435 }
436
437 {
438 multi_span<double> s(arr, 10);
439 CHECK(s.length() == 120 && s.data() == &arr[0][0][0]);
440 }
441
442 {
443 multi_span<double, dynamic_range, 3, 4> s(arr, 0);
444 CHECK(s.length() == 0 && s.data() == &arr[0][0][0]);
445 }
446
447 delete[] arr;
448 }
449
450 TEST(from_std_array_constructor)
451 {
452 std::array<int, 4> arr = {1, 2, 3, 4};
453
454 {
455 multi_span<int> s{arr};
456 CHECK(s.size() == narrow_cast<ptrdiff_t>(arr.size()) && s.data() == arr.data());
457
458 multi_span<const int> cs{arr};
459 CHECK(cs.size() == narrow_cast<ptrdiff_t>(arr.size()) && cs.data() == arr.data());
460 }
461
462 {
463 multi_span<int, 4> s{arr};
464 CHECK(s.size() == narrow_cast<ptrdiff_t>(arr.size()) && s.data() == arr.data());
465
466 multi_span<const int, 4> cs{arr};
467 CHECK(cs.size() == narrow_cast<ptrdiff_t>(arr.size()) && cs.data() == arr.data());
468 }
469
470 {
471 multi_span<int, 2> s{arr};
472 CHECK(s.size() == 2 && s.data() == arr.data());
473
474 multi_span<const int, 2> cs{arr};
475 CHECK(cs.size() == 2 && cs.data() == arr.data());
476 }
477
478 {
479 multi_span<int, 0> s{arr};
480 CHECK(s.size() == 0 && s.data() == arr.data());
481
482 multi_span<const int, 0> cs{arr};
483 CHECK(cs.size() == 0 && cs.data() == arr.data());
484 }
485
486 // TODO This is currently an unsupported scenario. We will come back to it as we revise
487 // the multidimensional interface and what transformations between dimensionality look like
488 //{
489 // multi_span<int, 2, 2> s{arr};
490 // CHECK(s.size() == narrow_cast<ptrdiff_t>(arr.size()) && s.data() == arr.data());
491 //}
492
493 {
494 #ifdef CONFIRM_COMPILATION_ERRORS
495 multi_span<int, 5> s{arr};
496 #endif
497 }
498
499 {
500 #ifdef CONFIRM_COMPILATION_ERRORS
501 auto get_an_array = []() { return std::array<int, 4>{1, 2, 3, 4}; };
502 auto take_a_span = [](multi_span<int> s) { (void) s; };
503 // try to take a temporary std::array
504 take_a_span(get_an_array());
505 #endif
506 }
507 }
508
509 TEST(from_const_std_array_constructor)
510 {
511 const std::array<int, 4> arr = {1, 2, 3, 4};
512
513 {
514 multi_span<const int> s{arr};
515 CHECK(s.size() == narrow_cast<ptrdiff_t>(arr.size()) && s.data() == arr.data());
516 }
517
518 {
519 multi_span<const int, 4> s{arr};
520 CHECK(s.size() == narrow_cast<ptrdiff_t>(arr.size()) && s.data() == arr.data());
521 }
522
523 {
524 multi_span<const int, 2> s{arr};
525 CHECK(s.size() == 2 && s.data() == arr.data());
526 }
527
528 {
529 multi_span<const int, 0> s{arr};
530 CHECK(s.size() == 0 && s.data() == arr.data());
531 }
532
533 // TODO This is currently an unsupported scenario. We will come back to it as we revise
534 // the multidimensional interface and what transformations between dimensionality look like
535 //{
536 // multi_span<int, 2, 2> s{arr};
537 // CHECK(s.size() == narrow_cast<ptrdiff_t>(arr.size()) && s.data() == arr.data());
538 //}
539
540 {
541 #ifdef CONFIRM_COMPILATION_ERRORS
542 multi_span<const int, 5> s{arr};
543 #endif
544 }
545
546 {
547 #ifdef CONFIRM_COMPILATION_ERRORS
548 auto get_an_array = []() -> const std::array<int, 4> { return {1, 2, 3, 4}; };
549 auto take_a_span = [](multi_span<const int> s) { (void) s; };
550 // try to take a temporary std::array
551 take_a_span(get_an_array());
552 #endif
553 }
554 }
555
556 TEST(from_container_constructor)
557 {
558 std::vector<int> v = {1, 2, 3};
559 const std::vector<int> cv = v;
560
561 {
562 multi_span<int> s{v};
563 CHECK(s.size() == narrow_cast<std::ptrdiff_t>(v.size()) && s.data() == v.data());
564
565 multi_span<const int> cs{v};
566 CHECK(cs.size() == narrow_cast<std::ptrdiff_t>(v.size()) && cs.data() == v.data());
567 }
568
569 std::string str = "hello";
570 const std::string cstr = "hello";
571
572 {
573 #ifdef CONFIRM_COMPILATION_ERRORS
574 multi_span<char> s{str};
575 CHECK(s.size() == narrow_cast<std::ptrdiff_t>(str.size()) && s.data() == str.data());
576 #endif
577 multi_span<const char> cs{str};
578 CHECK(cs.size() == narrow_cast<std::ptrdiff_t>(str.size()) && cs.data() == str.data());
579 }
580
581 {
582 #ifdef CONFIRM_COMPILATION_ERRORS
583 multi_span<char> s{cstr};
584 #endif
585 multi_span<const char> cs{cstr};
586 CHECK(cs.size() == narrow_cast<std::ptrdiff_t>(cstr.size()) &&
587 cs.data() == cstr.data());
588 }
589
590 {
591 #ifdef CONFIRM_COMPILATION_ERRORS
592 auto get_temp_vector = []() -> std::vector<int> { return {}; };
593 auto use_span = [](multi_span<int> s) { (void) s; };
594 use_span(get_temp_vector());
595 #endif
596 }
597
598 {
599 #ifdef CONFIRM_COMPILATION_ERRORS
600 auto get_temp_string = []() -> std::string { return {}; };
601 auto use_span = [](multi_span<char> s) { (void) s; };
602 use_span(get_temp_string());
603 #endif
604 }
605
606 {
607 #ifdef CONFIRM_COMPILATION_ERRORS
608 auto get_temp_vector = []() -> const std::vector<int> { return {}; };
609 auto use_span = [](multi_span<const char> s) { (void) s; };
610 use_span(get_temp_vector());
611 #endif
612 }
613
614 {
615 #ifdef CONFIRM_COMPILATION_ERRORS
616 auto get_temp_string = []() -> const std::string { return {}; };
617 auto use_span = [](multi_span<const char> s) { (void) s; };
618 use_span(get_temp_string());
619 #endif
620 }
621
622 {
623 #ifdef CONFIRM_COMPILATION_ERRORS
624 std::map<int, int> m;
625 multi_span<int> s{m};
626 #endif
627 }
628 }
629
630 TEST(from_convertible_span_constructor)
631 {
632 #ifdef CONFIRM_COMPILATION_ERRORS
633 multi_span<int, 7, 4, 2> av1(nullptr, b1);
634
635 auto f = [&]() { multi_span<int, 7, 4, 2> av1(nullptr); };
636 CHECK_THROW(f(), fail_fast);
637 #endif
638
639 #ifdef CONFIRM_COMPILATION_ERRORS
640 static_bounds<size_t, 7, dynamic_range, 2> b12(b11);
641 b12 = b11;
642 b11 = b12;
643
644 multi_span<int, dynamic_range> av1 = nullptr;
645 multi_span<int, 7, dynamic_range, 2> av2(av1);
646 multi_span<int, 7, 4, 2> av2(av1);
647 #endif
648
649 multi_span<DerivedClass> avd;
650 #ifdef CONFIRM_COMPILATION_ERRORS
651 multi_span<BaseClass> avb = avd;
652 #endif
653 multi_span<const DerivedClass> avcd = avd;
654 (void) avcd;
655 }
656
657 TEST(copy_move_and_assignment)
658 {
659 multi_span<int> s1;
660 CHECK(s1.empty());
661
662 int arr[] = {3, 4, 5};
663
664 multi_span<const int> s2 = arr;
665 CHECK(s2.length() == 3 && s2.data() == &arr[0]);
666
667 s2 = s1;
668 CHECK(s2.empty());
669
670 auto get_temp_span = [&]() -> multi_span<int> { return {&arr[1], 2}; };
671 auto use_span = [&](multi_span<const int> s) { CHECK(s.length() == 2 && s.data() == &arr[1]); };
672 use_span(get_temp_span());
673
674 s1 = get_temp_span();
675 CHECK(s1.length() == 2 && s1.data() == &arr[1]);
676 }
677
678 template <class Bounds>
679 void fn(const Bounds&)
680 {
681 static_assert(Bounds::static_size == 60, "static bounds is wrong size");
682 }
683 TEST(as_multi_span_reshape)
684 {
685 int a[3][4][5];
686 auto av = as_multi_span(a);
687 fn(av.bounds());
688 auto av2 = as_multi_span(av, dim<60>());
689 auto av3 = as_multi_span(av2, dim<3>(), dim<4>(), dim<5>());
690 auto av4 = as_multi_span(av3, dim<4>(), dim(3), dim<5>());
691 auto av5 = as_multi_span(av4, dim<3>(), dim<4>(), dim<5>());
692 auto av6 = as_multi_span(av5, dim<12>(), dim(5));
693
694 fill(av6.begin(), av6.end(), 1);
695
696 auto av7 = as_bytes(av6);
697
698 auto av8 = as_multi_span<int>(av7);
699
700 CHECK(av8.size() == av6.size());
701 for (auto i = 0; i < av8.size(); i++) {
702 CHECK(av8[i] == 1);
703 }
704 }
705
706 TEST(first)
707 {
708 int arr[5] = {1, 2, 3, 4, 5};
709
710 {
711 multi_span<int, 5> av = arr;
712 CHECK((av.first<2>().bounds() == static_bounds<2>()));
713 CHECK(av.first<2>().length() == 2);
714 CHECK(av.first(2).length() == 2);
715 }
716
717 {
718 multi_span<int, 5> av = arr;
719 CHECK((av.first<0>().bounds() == static_bounds<0>()));
720 CHECK(av.first<0>().length() == 0);
721 CHECK(av.first(0).length() == 0);
722 }
723
724 {
725 multi_span<int, 5> av = arr;
726 CHECK((av.first<5>().bounds() == static_bounds<5>()));
727 CHECK(av.first<5>().length() == 5);
728 CHECK(av.first(5).length() == 5);
729 }
730
731 {
732 multi_span<int, 5> av = arr;
733 #ifdef CONFIRM_COMPILATION_ERRORS
734 CHECK(av.first<6>().bounds() == static_bounds<6>());
735 CHECK(av.first<6>().length() == 6);
736 CHECK(av.first<-1>().length() == -1);
737 #endif
738 CHECK_THROW(av.first(6).length(), fail_fast);
739 }
740
741 {
742 multi_span<int, dynamic_range> av;
743 CHECK((av.first<0>().bounds() == static_bounds<0>()));
744 CHECK(av.first<0>().length() == 0);
745 CHECK(av.first(0).length() == 0);
746 }
747 }
748
749 TEST(last)
750 {
751 int arr[5] = {1, 2, 3, 4, 5};
752
753 {
754 multi_span<int, 5> av = arr;
755 CHECK((av.last<2>().bounds() == static_bounds<2>()));
756 CHECK(av.last<2>().length() == 2);
757 CHECK(av.last(2).length() == 2);
758 }
759
760 {
761 multi_span<int, 5> av = arr;
762 CHECK((av.last<0>().bounds() == static_bounds<0>()));
763 CHECK(av.last<0>().length() == 0);
764 CHECK(av.last(0).length() == 0);
765 }
766
767 {
768 multi_span<int, 5> av = arr;
769 CHECK((av.last<5>().bounds() == static_bounds<5>()));
770 CHECK(av.last<5>().length() == 5);
771 CHECK(av.last(5).length() == 5);
772 }
773
774 {
775 multi_span<int, 5> av = arr;
776 #ifdef CONFIRM_COMPILATION_ERRORS
777 CHECK((av.last<6>().bounds() == static_bounds<6>()));
778 CHECK(av.last<6>().length() == 6);
779 #endif
780 CHECK_THROW(av.last(6).length(), fail_fast);
781 }
782
783 {
784 multi_span<int, dynamic_range> av;
785 CHECK((av.last<0>().bounds() == static_bounds<0>()));
786 CHECK(av.last<0>().length() == 0);
787 CHECK(av.last(0).length() == 0);
788 }
789 }
790
791 TEST(subspan)
792 {
793 int arr[5] = {1, 2, 3, 4, 5};
794
795 {
796 multi_span<int, 5> av = arr;
797 CHECK((av.subspan<2, 2>().bounds() == static_bounds<2>()));
798 CHECK((av.subspan<2, 2>().length() == 2));
799 CHECK(av.subspan(2, 2).length() == 2);
800 CHECK(av.subspan(2, 3).length() == 3);
801 }
802
803 {
804 multi_span<int, 5> av = arr;
805 CHECK((av.subspan<0, 0>().bounds() == static_bounds<0>()));
806 CHECK((av.subspan<0, 0>().length() == 0));
807 CHECK(av.subspan(0, 0).length() == 0);
808 }
809
810 {
811 multi_span<int, 5> av = arr;
812 CHECK((av.subspan<0, 5>().bounds() == static_bounds<5>()));
813 CHECK((av.subspan<0, 5>().length() == 5));
814 CHECK(av.subspan(0, 5).length() == 5);
815 CHECK_THROW(av.subspan(0, 6).length(), fail_fast);
816 CHECK_THROW(av.subspan(1, 5).length(), fail_fast);
817 }
818
819 {
820 multi_span<int, 5> av = arr;
821 CHECK((av.subspan<5, 0>().bounds() == static_bounds<0>()));
822 CHECK((av.subspan<5, 0>().length() == 0));
823 CHECK(av.subspan(5, 0).length() == 0);
824 CHECK_THROW(av.subspan(6, 0).length(), fail_fast);
825 }
826
827 {
828 multi_span<int, dynamic_range> av;
829 CHECK((av.subspan<0, 0>().bounds() == static_bounds<0>()));
830 CHECK((av.subspan<0, 0>().length() == 0));
831 CHECK(av.subspan(0, 0).length() == 0);
832 CHECK_THROW((av.subspan<1, 0>().length()), fail_fast);
833 }
834
835 {
836 multi_span<int> av;
837 CHECK(av.subspan(0).length() == 0);
838 CHECK_THROW(av.subspan(1).length(), fail_fast);
839 }
840
841 {
842 multi_span<int> av = arr;
843 CHECK(av.subspan(0).length() == 5);
844 CHECK(av.subspan(1).length() == 4);
845 CHECK(av.subspan(4).length() == 1);
846 CHECK(av.subspan(5).length() == 0);
847 CHECK_THROW(av.subspan(6).length(), fail_fast);
848 auto av2 = av.subspan(1);
849 for (int i = 0; i < 4; ++i) CHECK(av2[i] == i + 2);
850 }
851
852 {
853 multi_span<int, 5> av = arr;
854 CHECK(av.subspan(0).length() == 5);
855 CHECK(av.subspan(1).length() == 4);
856 CHECK(av.subspan(4).length() == 1);
857 CHECK(av.subspan(5).length() == 0);
858 CHECK_THROW(av.subspan(6).length(), fail_fast);
859 auto av2 = av.subspan(1);
860 for (int i = 0; i < 4; ++i) CHECK(av2[i] == i + 2);
861 }
862 }
863
864 TEST(rank)
865 {
866 int arr[2] = {1, 2};
867
868 {
869 multi_span<int> s;
870 CHECK(s.rank() == 1);
871 }
872
873 {
874 multi_span<int, 2> s = arr;
875 CHECK(s.rank() == 1);
876 }
877
878 int arr2d[1][1] = {};
879 {
880 multi_span<int, 1, 1> s = arr2d;
881 CHECK(s.rank() == 2);
882 }
883 }
884
885 TEST(extent)
886 {
887 {
888 multi_span<int> s;
889 CHECK(s.extent() == 0);
890 CHECK(s.extent(0) == 0);
891 CHECK_THROW(s.extent(1), fail_fast);
892 #ifdef CONFIRM_COMPILATION_ERRORS
893 CHECK(s.extent<1>() == 0);
894 #endif
895 }
896
897 {
898 multi_span<int, 0> s;
899 CHECK(s.extent() == 0);
900 CHECK(s.extent(0) == 0);
901 CHECK_THROW(s.extent(1), fail_fast);
902 }
903
904 {
905 int arr2d[1][2] = {};
906
907 multi_span<int, 1, 2> s = arr2d;
908 CHECK(s.extent() == 1);
909 CHECK(s.extent<0>() == 1);
910 CHECK(s.extent<1>() == 2);
911 CHECK(s.extent(0) == 1);
912 CHECK(s.extent(1) == 2);
913 CHECK_THROW(s.extent(3), fail_fast);
914 }
915
916 {
917 int arr2d[1][2] = {};
918
919 multi_span<int, 0, 2> s = arr2d;
920 CHECK(s.extent() == 0);
921 CHECK(s.extent<0>() == 0);
922 CHECK(s.extent<1>() == 2);
923 CHECK(s.extent(0) == 0);
924 CHECK(s.extent(1) == 2);
925 CHECK_THROW(s.extent(3), fail_fast);
926 }
927 }
928
929 TEST(operator_function_call)
930 {
931 int arr[4] = {1, 2, 3, 4};
932
933 {
934 multi_span<int> s = arr;
935 CHECK(s(0) == 1);
936 CHECK_THROW(s(5), fail_fast);
937 }
938
939 int arr2d[2][3] = {1, 2, 3, 4, 5, 6};
940
941 {
942 multi_span<int, 2, 3> s = arr2d;
943 CHECK(s(0, 0) == 1);
944 CHECK(s(1, 2) == 6);
945 }
946 }
947
948 TEST(comparison_operators)
949 {
950 {
951 int arr[10][2];
952 auto s1 = as_multi_span(arr);
953 multi_span<const int, dynamic_range, 2> s2 = s1;
954
955 CHECK(s1 == s2);
956
957 multi_span<int, 20> s3 = as_multi_span(s1, dim(20));
958 CHECK(s3 == s2 && s3 == s1);
959 }
960
961 {
962 multi_span<int> s1 = nullptr;
963 multi_span<int> s2 = nullptr;
964 CHECK(s1 == s2);
965 CHECK(!(s1 != s2));
966 CHECK(!(s1 < s2));
967 CHECK(s1 <= s2);
968 CHECK(!(s1 > s2));
969 CHECK(s1 >= s2);
970 CHECK(s2 == s1);
971 CHECK(!(s2 != s1));
972 CHECK(!(s2 < s1));
973 CHECK(s2 <= s1);
974 CHECK(!(s2 > s1));
975 CHECK(s2 >= s1);
976 }
977
978 {
979 int arr[] = {2, 1}; // bigger
980
981 multi_span<int> s1 = nullptr;
982 multi_span<int> s2 = arr;
983
984 CHECK(s1 != s2);
985 CHECK(s2 != s1);
986 CHECK(!(s1 == s2));
987 CHECK(!(s2 == s1));
988 CHECK(s1 < s2);
989 CHECK(!(s2 < s1));
990 CHECK(s1 <= s2);
991 CHECK(!(s2 <= s1));
992 CHECK(s2 > s1);
993 CHECK(!(s1 > s2));
994 CHECK(s2 >= s1);
995 CHECK(!(s1 >= s2));
996 }
997
998 {
999 int arr1[] = {1, 2};
1000 int arr2[] = {1, 2};
1001 multi_span<int> s1 = arr1;
1002 multi_span<int> s2 = arr2;
1003
1004 CHECK(s1 == s2);
1005 CHECK(!(s1 != s2));
1006 CHECK(!(s1 < s2));
1007 CHECK(s1 <= s2);
1008 CHECK(!(s1 > s2));
1009 CHECK(s1 >= s2);
1010 CHECK(s2 == s1);
1011 CHECK(!(s2 != s1));
1012 CHECK(!(s2 < s1));
1013 CHECK(s2 <= s1);
1014 CHECK(!(s2 > s1));
1015 CHECK(s2 >= s1);
1016 }
1017
1018 {
1019 int arr[] = {1, 2, 3};
1020
1021 multi_span<int> s1 = {&arr[0], 2}; // shorter
1022 multi_span<int> s2 = arr; // longer
1023
1024 CHECK(s1 != s2);
1025 CHECK(s2 != s1);
1026 CHECK(!(s1 == s2));
1027 CHECK(!(s2 == s1));
1028 CHECK(s1 < s2);
1029 CHECK(!(s2 < s1));
1030 CHECK(s1 <= s2);
1031 CHECK(!(s2 <= s1));
1032 CHECK(s2 > s1);
1033 CHECK(!(s1 > s2));
1034 CHECK(s2 >= s1);
1035 CHECK(!(s1 >= s2));
1036 }
1037
1038 {
1039 int arr1[] = {1, 2}; // smaller
1040 int arr2[] = {2, 1}; // bigger
1041
1042 multi_span<int> s1 = arr1;
1043 multi_span<int> s2 = arr2;
1044
1045 CHECK(s1 != s2);
1046 CHECK(s2 != s1);
1047 CHECK(!(s1 == s2));
1048 CHECK(!(s2 == s1));
1049 CHECK(s1 < s2);
1050 CHECK(!(s2 < s1));
1051 CHECK(s1 <= s2);
1052 CHECK(!(s2 <= s1));
1053 CHECK(s2 > s1);
1054 CHECK(!(s1 > s2));
1055 CHECK(s2 >= s1);
1056 CHECK(!(s1 >= s2));
1057 }
1058 }
1059
1060 TEST(basics)
1061 {
1062 auto ptr = as_multi_span(new int[10], 10);
1063 fill(ptr.begin(), ptr.end(), 99);
1064 for (int num : ptr) {
1065 CHECK(num == 99);
1066 }
1067
1068 delete[] ptr.data();
1069 }
1070
1071 TEST(bounds_checks)
1072 {
1073 int arr[10][2];
1074 auto av = as_multi_span(arr);
1075
1076 fill(begin(av), end(av), 0);
1077
1078 av[2][0] = 1;
1079 av[1][1] = 3;
1080
1081 // out of bounds
1082 CHECK_THROW(av[1][3] = 3, fail_fast);
1083 CHECK_THROW((av[{1, 3}] = 3), fail_fast);
1084
1085 CHECK_THROW(av[10][2], fail_fast);
1086 CHECK_THROW((av[{10, 2}]), fail_fast);
1087
1088 CHECK_THROW(av[-1][0], fail_fast);
1089 CHECK_THROW((av[{-1, 0}]), fail_fast);
1090
1091 CHECK_THROW(av[0][-1], fail_fast);
1092 CHECK_THROW((av[{0, -1}]), fail_fast);
1093 }
1094
1095 void overloaded_func(multi_span<const int, dynamic_range, 3, 5> exp, int expected_value)
1096 {
1097 for (auto val : exp) {
1098 CHECK(val == expected_value);
1099 }
1100 }
1101
1102 void overloaded_func(multi_span<const char, dynamic_range, 3, 5> exp, char expected_value)
1103 {
1104 for (auto val : exp) {
1105 CHECK(val == expected_value);
1106 }
1107 }
1108
1109 void fixed_func(multi_span<int, 3, 3, 5> exp, int expected_value)
1110 {
1111 for (auto val : exp) {
1112 CHECK(val == expected_value);
1113 }
1114 }
1115
1116 TEST(span_parameter_test)
1117 {
1118 auto data = new int[4][3][5];
1119
1120 auto av = as_multi_span(data, 4);
1121
1122 CHECK(av.size() == 60);
1123
1124 fill(av.begin(), av.end(), 34);
1125
1126 int count = 0;
1127 for_each(av.rbegin(), av.rend(), [&](int val) { count += val; });
1128 CHECK(count == 34 * 60);
1129 overloaded_func(av, 34);
1130
1131 overloaded_func(as_multi_span(av, dim(4), dim(3), dim(5)), 34);
1132
1133 // fixed_func(av, 34);
1134 delete[] data;
1135 }
1136
1137 TEST(md_access)
1138 {
1139 auto width = 5, height = 20;
1140
1141 auto imgSize = width * height;
1142 auto image_ptr = new int[imgSize][3];
1143
1144 // size check will be done
1145 auto image_view =
1146 as_multi_span(as_multi_span(image_ptr, imgSize), dim(height), dim(width), dim<3>());
1147
1148 iota(image_view.begin(), image_view.end(), 1);
1149
1150 int expected = 0;
1151 for (auto i = 0; i < height; i++) {
1152 for (auto j = 0; j < width; j++) {
1153 CHECK(expected + 1 == image_view[i][j][0]);
1154 CHECK(expected + 2 == image_view[i][j][1]);
1155 CHECK(expected + 3 == image_view[i][j][2]);
1156
1157 auto val = image_view[{i, j, 0}];
1158 CHECK(expected + 1 == val);
1159 val = image_view[{i, j, 1}];
1160 CHECK(expected + 2 == val);
1161 val = image_view[{i, j, 2}];
1162 CHECK(expected + 3 == val);
1163
1164 expected += 3;
1165 }
1166 }
1167 }
1168
1169 TEST(as_multi_span)
1170 {
1171 {
1172 int* arr = new int[150];
1173
1174 auto av = as_multi_span(arr, dim<10>(), dim(3), dim<5>());
1175
1176 fill(av.begin(), av.end(), 24);
1177 overloaded_func(av, 24);
1178
1179 delete[] arr;
1180
1181 array<int, 15> stdarr{0};
1182 auto av2 = as_multi_span(stdarr);
1183 overloaded_func(as_multi_span(av2, dim(1), dim<3>(), dim<5>()), 0);
1184
1185 string str = "ttttttttttttttt"; // size = 15
1186 auto t = str.data();
1187 (void) t;
1188 auto av3 = as_multi_span(str);
1189 overloaded_func(as_multi_span(av3, dim(1), dim<3>(), dim<5>()), 't');
1190 }
1191
1192 {
1193 string str;
1194 multi_span<char> strspan = as_multi_span(str);
1195 (void) strspan;
1196 const string cstr;
1197 multi_span<const char> cstrspan = as_multi_span(cstr);
1198 (void) cstrspan;
1199 }
1200
1201 {
1202 int a[3][4][5];
1203 auto av = as_multi_span(a);
1204 const int(*b)[4][5];
1205 b = a;
1206 auto bv = as_multi_span(b, 3);
1207
1208 CHECK(av == bv);
1209
1210 const std::array<double, 3> arr = {0.0, 0.0, 0.0};
1211 auto cv = as_multi_span(arr);
1212 (void) cv;
1213
1214 vector<float> vec(3);
1215 auto dv = as_multi_span(vec);
1216 (void) dv;
1217
1218 #ifdef CONFIRM_COMPILATION_ERRORS
1219 auto dv2 = as_multi_span(std::move(vec));
1220 #endif
1221 }
1222 }
1223
1224 TEST(empty_spans)
1225 {
1226 {
1227 multi_span<int, 0> empty_av(nullptr);
1228
1229 CHECK(empty_av.bounds().index_bounds() == index<1>{0});
1230 CHECK_THROW(empty_av[0], fail_fast);
1231 CHECK_THROW(empty_av.begin()[0], fail_fast);
1232 CHECK_THROW(empty_av.cbegin()[0], fail_fast);
1233 for (auto& v : empty_av) {
1234 (void) v;
1235 CHECK(false);
1236 }
1237 }
1238
1239 {
1240 multi_span<int> empty_av = {};
1241 CHECK(empty_av.bounds().index_bounds() == index<1>{0});
1242 CHECK_THROW(empty_av[0], fail_fast);
1243 CHECK_THROW(empty_av.begin()[0], fail_fast);
1244 CHECK_THROW(empty_av.cbegin()[0], fail_fast);
1245 for (auto& v : empty_av) {
1246 (void) v;
1247 CHECK(false);
1248 }
1249 }
1250 }
1251
1252 TEST(index_constructor)
1253 {
1254 auto arr = new int[8];
1255 for (int i = 0; i < 4; ++i) {
1256 arr[2 * i] = 4 + i;
1257 arr[2 * i + 1] = i;
1258 }
1259
1260 multi_span<int, dynamic_range> av(arr, 8);
1261
1262 ptrdiff_t a[1] = {0};
1263 index<1> i = a;
1264
1265 CHECK(av[i] == 4);
1266
1267 auto av2 = as_multi_span(av, dim<4>(), dim(2));
1268 ptrdiff_t a2[2] = {0, 1};
1269 index<2> i2 = a2;
1270
1271 CHECK(av2[i2] == 0);
1272 CHECK(av2[0][i] == 4);
1273
1274 delete[] arr;
1275 }
1276
1277 TEST(index_constructors)
1278 {
1279 {
1280 // components of the same type
1281 index<3> i1(0, 1, 2);
1282 CHECK(i1[0] == 0);
1283
1284 // components of different types
1285 size_t c0 = 0;
1286 size_t c1 = 1;
1287 index<3> i2(c0, c1, 2);
1288 CHECK(i2[0] == 0);
1289
1290 // from array
1291 index<3> i3 = {0, 1, 2};
1292 CHECK(i3[0] == 0);
1293
1294 // from other index of the same size type
1295 index<3> i4 = i3;
1296 CHECK(i4[0] == 0);
1297
1298 // default
1299 index<3> i7;
1300 CHECK(i7[0] == 0);
1301
1302 // default
1303 index<3> i9 = {};
1304 CHECK(i9[0] == 0);
1305 }
1306
1307 {
1308 // components of the same type
1309 index<1> i1(0);
1310 CHECK(i1[0] == 0);
1311
1312 // components of different types
1313 size_t c0 = 0;
1314 index<1> i2(c0);
1315 CHECK(i2[0] == 0);
1316
1317 // from array
1318 index<1> i3 = {0};
1319 CHECK(i3[0] == 0);
1320
1321 // from int
1322 index<1> i4 = 0;
1323 CHECK(i4[0] == 0);
1324
1325 // from other index of the same size type
1326 index<1> i5 = i3;
1327 CHECK(i5[0] == 0);
1328
1329 // default
1330 index<1> i8;
1331 CHECK(i8[0] == 0);
1332
1333 // default
1334 index<1> i9 = {};
1335 CHECK(i9[0] == 0);
1336 }
1337
1338 #ifdef CONFIRM_COMPILATION_ERRORS
1339 {
1340 index<3> i1(0, 1);
1341 index<3> i2(0, 1, 2, 3);
1342 index<3> i3 = {0};
1343 index<3> i4 = {0, 1, 2, 3};
1344 index<1> i5 = {0, 1};
1345 }
1346 #endif
1347 }
1348
1349 TEST(index_operations)
1350 {
1351 ptrdiff_t a[3] = {0, 1, 2};
1352 ptrdiff_t b[3] = {3, 4, 5};
1353 index<3> i = a;
1354 index<3> j = b;
1355
1356 CHECK(i[0] == 0);
1357 CHECK(i[1] == 1);
1358 CHECK(i[2] == 2);
1359
1360 {
1361 index<3> k = i + j;
1362
1363 CHECK(i[0] == 0);
1364 CHECK(i[1] == 1);
1365 CHECK(i[2] == 2);
1366 CHECK(k[0] == 3);
1367 CHECK(k[1] == 5);
1368 CHECK(k[2] == 7);
1369 }
1370
1371 {
1372 index<3> k = i * 3;
1373
1374 CHECK(i[0] == 0);
1375 CHECK(i[1] == 1);
1376 CHECK(i[2] == 2);
1377 CHECK(k[0] == 0);
1378 CHECK(k[1] == 3);
1379 CHECK(k[2] == 6);
1380 }
1381
1382 {
1383 index<3> k = 3 * i;
1384
1385 CHECK(i[0] == 0);
1386 CHECK(i[1] == 1);
1387 CHECK(i[2] == 2);
1388 CHECK(k[0] == 0);
1389 CHECK(k[1] == 3);
1390 CHECK(k[2] == 6);
1391 }
1392
1393 {
1394 index<2> k = details::shift_left(i);
1395
1396 CHECK(i[0] == 0);
1397 CHECK(i[1] == 1);
1398 CHECK(i[2] == 2);
1399 CHECK(k[0] == 1);
1400 CHECK(k[1] == 2);
1401 }
1402 }
1403
1404 void iterate_second_column(multi_span<int, dynamic_range, dynamic_range> av)
1405 {
1406 auto length = av.size() / 2;
1407
1408 // view to the second column
1409 auto section = av.section({0, 1}, {length, 1});
1410
1411 CHECK(section.size() == length);
1412 for (auto i = 0; i < section.size(); ++i) {
1413 CHECK(section[i][0] == av[i][1]);
1414 }
1415
1416 for (auto i = 0; i < section.size(); ++i) {
1417 auto idx = index<2>{i, 0}; // avoid braces inside the CHECK macro
1418 CHECK(section[idx] == av[i][1]);
1419 }
1420
1421 CHECK(section.bounds().index_bounds()[0] == length);
1422 CHECK(section.bounds().index_bounds()[1] == 1);
1423 for (auto i = 0; i < section.bounds().index_bounds()[0]; ++i) {
1424 for (auto j = 0; j < section.bounds().index_bounds()[1]; ++j) {
1425 auto idx = index<2>{i, j}; // avoid braces inside the CHECK macro
1426 CHECK(section[idx] == av[i][1]);
1427 }
1428 }
1429
1430 size_t check_sum = 0;
1431 for (auto i = 0; i < length; ++i) {
1432 check_sum += av[i][1];
1433 }
1434
1435 {
1436 auto idx = 0;
1437 size_t sum = 0;
1438 for (auto num : section) {
1439 CHECK(num == av[idx][1]);
1440 sum += num;
1441 idx++;
1442 }
1443
1444 CHECK(sum == check_sum);
1445 }
1446 {
1447 size_t idx = length - 1;
1448 size_t sum = 0;
1449 for (auto iter = section.rbegin(); iter != section.rend(); ++iter) {
1450 CHECK(*iter == av[idx][1]);
1451 sum += *iter;
1452 idx--;
1453 }
1454
1455 CHECK(sum == check_sum);
1456 }
1457 }
1458
1459 TEST(span_section_iteration)
1460 {
1461 int arr[4][2] = {{4, 0}, {5, 1}, {6, 2}, {7, 3}};
1462
1463 // static bounds
1464 {
1465 multi_span<int, 4, 2> av = arr;
1466 iterate_second_column(av);
1467 }
1468 // first bound is dynamic
1469 {
1470 multi_span<int, dynamic_range, 2> av = arr;
1471 iterate_second_column(av);
1472 }
1473 // second bound is dynamic
1474 {
1475 multi_span<int, 4, dynamic_range> av = arr;
1476 iterate_second_column(av);
1477 }
1478 // both bounds are dynamic
1479 {
1480 multi_span<int, dynamic_range, dynamic_range> av = arr;
1481 iterate_second_column(av);
1482 }
1483 }
1484
1485 TEST(dynamic_span_section_iteration)
1486 {
1487 auto height = 4, width = 2;
1488 auto size = height * width;
1489
1490 auto arr = new int[size];
1491 for (auto i = 0; i < size; ++i) {
1492 arr[i] = i;
1493 }
1494
1495 auto av = as_multi_span(arr, size);
1496
1497 // first bound is dynamic
1498 {
1499 multi_span<int, dynamic_range, 2> av2 = as_multi_span(av, dim(height), dim(width));
1500 iterate_second_column(av2);
1501 }
1502 // second bound is dynamic
1503 {
1504 multi_span<int, 4, dynamic_range> av2 = as_multi_span(av, dim(height), dim(width));
1505 iterate_second_column(av2);
1506 }
1507 // both bounds are dynamic
1508 {
1509 multi_span<int, dynamic_range, dynamic_range> av2 = as_multi_span(av, dim(height), dim(width));
1510 iterate_second_column(av2);
1511 }
1512
1513 delete[] arr;
1514 }
1515
1516 TEST(span_structure_size)
1517 {
1518 double(*arr)[3][4] = new double[100][3][4];
1519 multi_span<double, dynamic_range, 3, 4> av1(arr, 10);
1520
1521 struct EffectiveStructure
1522 {
1523 double* v1;
1524 ptrdiff_t v2;
1525 };
1526 CHECK(sizeof(av1) == sizeof(EffectiveStructure));
1527
1528 CHECK_THROW(av1[10][3][4], fail_fast);
1529
1530 multi_span<const double, dynamic_range, 6, 4> av2 = as_multi_span(av1, dim(5), dim<6>(), dim<4>());
1531 (void) av2;
1532 }
1533
1534 TEST(fixed_size_conversions)
1535 {
1536 int arr[] = {1, 2, 3, 4};
1537
1538 // converting to an multi_span from an equal size array is ok
1539 multi_span<int, 4> av4 = arr;
1540 CHECK(av4.length() == 4);
1541
1542 // converting to dynamic_range a_v is always ok
1543 {
1544 multi_span<int, dynamic_range> av = av4;
1545 (void) av;
1546 }
1547 {
1548 multi_span<int, dynamic_range> av = arr;
1549 (void) av;
1550 }
1551
1552 // initialization or assignment to static multi_span that REDUCES size is NOT ok
1553 #ifdef CONFIRM_COMPILATION_ERRORS
1554 {
1555 multi_span<int, 2> av2 = arr;
1556 }
1557 {
1558 multi_span<int, 2> av2 = av4;
1559 }
1560 #endif
1561
1562 {
1563 multi_span<int, dynamic_range> av = arr;
1564 multi_span<int, 2> av2 = av;
1565 (void) av2;
1566 }
1567
1568 #ifdef CONFIRM_COMPILATION_ERRORS
1569 {
1570 multi_span<int, dynamic_range> av = arr;
1571 multi_span<int, 2, 1> av2 = av.as_multi_span(dim<2>(), dim<2>());
1572 }
1573 #endif
1574
1575 {
1576 multi_span<int, dynamic_range> av = arr;
1577 multi_span<int, 2, 1> av2 = as_multi_span(av, dim(2), dim(2));
1578 auto workaround_macro = [&]() { return av2[{1, 0}] == 2; };
1579 CHECK(workaround_macro());
1580 }
1581
1582 // but doing so explicitly is ok
1583
1584 // you can convert statically
1585 {
1586 multi_span<int, 2> av2 = {arr, 2};
1587 (void) av2;
1588 }
1589 {
1590 multi_span<int, 1> av2 = av4.first<1>();
1591 (void) av2;
1592 }
1593
1594 // ...or dynamically
1595 {
1596 // NB: implicit conversion to multi_span<int,2> from multi_span<int,dynamic_range>
1597 multi_span<int, 1> av2 = av4.first(1);
1598 (void) av2;
1599 }
1600
1601 // initialization or assignment to static multi_span that requires size INCREASE is not ok.
1602 int arr2[2] = {1, 2};
1603
1604 #ifdef CONFIRM_COMPILATION_ERRORS
1605 {
1606 multi_span<int, 4> av4 = arr2;
1607 }
1608 {
1609 multi_span<int, 2> av2 = arr2;
1610 multi_span<int, 4> av4 = av2;
1611 }
1612 #endif
1613 {
1614 auto f = [&]() {
1615 multi_span<int, 4> av9 = {arr2, 2};
1616 (void) av9;
1617 };
1618 CHECK_THROW(f(), fail_fast);
1619 }
1620
1621 // this should fail - we are trying to assign a small dynamic a_v to a fixed_size larger one
1622 multi_span<int, dynamic_range> av = arr2;
1623 auto f = [&]() {
1624 multi_span<int, 4> av2 = av;
1625 (void) av2;
1626 };
1627 CHECK_THROW(f(), fail_fast);
1628 }
1629
1630 TEST(as_writeable_bytes)
1631 {
1632 int a[] = {1, 2, 3, 4};
1633
1634 {
1635 #ifdef CONFIRM_COMPILATION_ERRORS
1636 // you should not be able to get writeable bytes for const objects
1637 multi_span<const int, dynamic_range> av = a;
1638 auto wav = av.as_writeable_bytes();
1639 #endif
1640 }
1641
1642 {
1643 multi_span<int, dynamic_range> av;
1644 auto wav = as_writeable_bytes(av);
1645 CHECK(wav.length() == av.length());
1646 CHECK(wav.length() == 0);
1647 CHECK(wav.size_bytes() == 0);
1648 }
1649
1650 {
1651 multi_span<int, dynamic_range> av = a;
1652 auto wav = as_writeable_bytes(av);
1653 CHECK(wav.data() == (byte*) &a[0]);
1654 CHECK(wav.length() == sizeof(a));
1655 }
1656 }
1657
1658 TEST(iterator)
1659 {
1660 int a[] = {1, 2, 3, 4};
1661
1662 {
1663 multi_span<int, dynamic_range> av = a;
1664 auto wav = as_writeable_bytes(av);
1665 for (auto& b : wav) {
1666 b = byte(0);
1667 }
1668 for (size_t i = 0; i < 4; ++i) {
1669 CHECK(a[i] == 0);
1670 }
1671 }
1672
1673 {
1674 multi_span<int, dynamic_range> av = a;
1675 for (auto& n : av) {
1676 n = 1;
1677 }
1678 for (size_t i = 0; i < 4; ++i) {
1679 CHECK(a[i] == 1);
1680 }
1681 }
1682 }
1683 }
1684
main(int,const char * [])1685 int main(int, const char* []) { return UnitTest::RunAllTests(); }
1686