span_tests.cpp revision 0cf947db7760bf5756e4cb0d47c72a257ed527c5
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 <span.h>
19
20#include <iostream>
21#include <list>
22#include <map>
23#include <memory>
24#include <string>
25#include <vector>
26
27using namespace std;
28using namespace gsl;
29
30namespace
31{
32struct BaseClass
33{
34};
35struct DerivedClass : BaseClass
36{
37};
38}
39
40SUITE(span_tests)
41{
42
43    TEST(default_constructor)
44    {
45        {
46            span<int> s;
47            CHECK(s.length() == 0 && s.data() == nullptr);
48
49            span<const int> cs;
50            CHECK(cs.length() == 0 && cs.data() == nullptr);
51        }
52
53        {
54            span<int, 0> s;
55            CHECK(s.length() == 0 && s.data() == nullptr);
56
57            span<const int, 0> cs;
58            CHECK(cs.length() == 0 && cs.data() == nullptr);
59        }
60
61        {
62#ifdef CONFIRM_COMPILATION_ERRORS
63            span<int, 1> s;
64            CHECK(s.length() == 1 && s.data() == nullptr); // explains why it can't compile
65#endif
66        }
67
68        {
69            span<int> s{};
70            CHECK(s.length() == 0 && s.data() == nullptr);
71
72            span<const int> cs{};
73            CHECK(cs.length() == 0 && cs.data() == nullptr);
74        }
75    }
76
77    TEST(from_nullptr_constructor)
78    {
79        {
80            span<int> s = nullptr;
81            CHECK(s.length() == 0 && s.data() == nullptr);
82
83            span<const int> cs = nullptr;
84            CHECK(cs.length() == 0 && cs.data() == nullptr);
85        }
86
87        {
88            span<int, 0> s = nullptr;
89            CHECK(s.length() == 0 && s.data() == nullptr);
90
91            span<const int, 0> cs = nullptr;
92            CHECK(cs.length() == 0 && cs.data() == nullptr);
93        }
94
95        {
96#ifdef CONFIRM_COMPILATION_ERRORS
97            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            span<int> s{nullptr};
104            CHECK(s.length() == 0 && s.data() == nullptr);
105
106            span<const int> cs{nullptr};
107            CHECK(cs.length() == 0 && cs.data() == nullptr);
108        }
109
110        {
111            span<int*> s{nullptr};
112            CHECK(s.length() == 0 && s.data() == nullptr);
113
114            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            span<int> s{nullptr, 0};
123            CHECK(s.length() == 0 && s.data() == nullptr);
124
125            span<const int> cs{nullptr, 0};
126            CHECK(cs.length() == 0 && cs.data() == nullptr);
127        }
128
129        {
130            span<int, 0> s{nullptr, 0};
131            CHECK(s.length() == 0 && s.data() == nullptr);
132
133            span<const int, 0> cs{nullptr, 0};
134            CHECK(cs.length() == 0 && cs.data() == nullptr);
135        }
136
137        {
138#ifdef CONFIRM_COMPILATION_ERRORS
139            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 = []() { span<int> s{nullptr, 1}; };
146            CHECK_THROW(workaround_macro(), fail_fast);
147
148            auto const_workaround_macro = []() { span<const int> cs{nullptr, 1}; };
149            CHECK_THROW(const_workaround_macro(), fail_fast);
150        }
151
152        {
153            auto workaround_macro = []() { span<int, 0> s{nullptr, 1}; };
154            CHECK_THROW(workaround_macro(), fail_fast);
155
156            auto const_workaround_macro = []() { span<const int, 0> s{nullptr, 1}; };
157            CHECK_THROW(const_workaround_macro(), fail_fast);
158        }
159
160        {
161            span<int*> s{nullptr, 0};
162            CHECK(s.length() == 0 && s.data() == nullptr);
163
164            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            span<int> s = i;
175            CHECK(s.length() == 1 && s.data() == &i);
176            CHECK(s[0] == 5);
177
178            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            span<int, 0> s = j;
187#endif
188        }
189
190        {
191#ifdef CONFIRM_COMPILATION_ERRORS
192            span<int, 0> s = i;
193            CHECK(s.length() == 0 && s.data() == &i);
194#endif
195        }
196
197        {
198            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            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 = [](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            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            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            span<int> s{p, 0};
238            CHECK(s.length() == 0 && s.data() == nullptr);
239        }
240
241        {
242            int* p = nullptr;
243            auto workaround_macro = [=]() { 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            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            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            span<int> s{&arr[0], &arr[0]};
266            CHECK(s.length() == 0 && s.data() == &arr[0]);
267        }
268
269        {
270            span<int, 0> s{&arr[0], &arr[0]};
271            CHECK(s.length() == 0 && s.data() == &arr[0]);
272        }
273
274        {
275            auto workaround_macro = [&]() { 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 = [&]() { span<int> s{&arr[0], p}; };
282            CHECK_THROW(workaround_macro(), fail_fast);
283        }
284
285        {
286            int* p = nullptr;
287            auto workaround_macro = [&]() { span<int> s{p, p}; };
288            CHECK_THROW(workaround_macro(), fail_fast);
289        }
290
291        {
292            int* p = nullptr;
293            auto workaround_macro = [&]() { 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            span<int> s{arr};
304            CHECK(s.length() == 5 && s.data() == &arr[0]);
305        }
306
307        {
308            span<int, 5> s{arr};
309            CHECK(s.length() == 5 && s.data() == &arr[0]);
310        }
311
312        {
313#ifdef CONFIRM_COMPILATION_ERRORS
314            span<int, 6> s{arr};
315#endif
316        }
317
318        {
319            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            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            span<int, 0> s{arr2d};
333            CHECK(s.length() == 0 && s.data() == &arr2d[0][0]);
334        }
335
336        {
337#ifdef CONFIRM_COMPILATION_ERRORS
338            span<int, 5> s{arr2d};
339#endif
340        }
341
342        {
343            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            span<int, 7> s{arr2d};
351#endif
352        }
353
354        {
355            span<int[3]> s{arr2d[0]};
356            CHECK(s.length() == 1 && s.data() == &arr2d[0]);
357        }
358
359        {
360            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            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            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            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            span<int, 11> s{arr3d};
388#endif
389        }
390
391        {
392            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            span<int, 13> s{arr3d};
400#endif
401        }
402
403        {
404            span<int[3][2]> s{arr3d[0]};
405            CHECK(s.length() == 1 && s.data() == &arr3d[0]);
406        }
407
408        {
409            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            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            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            span<double, dynamic_range, 4, 3> s(arr, 10);
434            CHECK(s.length() == 120 && s.data() == &arr[0][0][0]);
435        }
436
437        {
438            span<double> s(arr, 10);
439            CHECK(s.length() == 120 && s.data() == &arr[0][0][0]);
440        }
441
442        {
443            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            span<int> s{arr};
456            CHECK(s.size() == narrow_cast<ptrdiff_t>(arr.size()) && s.data() == arr.data());
457
458            span<const int> cs{arr};
459            CHECK(cs.size() == narrow_cast<ptrdiff_t>(arr.size()) && cs.data() == arr.data());
460        }
461
462        {
463            span<int, 4> s{arr};
464            CHECK(s.size() == narrow_cast<ptrdiff_t>(arr.size()) && s.data() == arr.data());
465
466            span<const int, 4> cs{arr};
467            CHECK(cs.size() == narrow_cast<ptrdiff_t>(arr.size()) && cs.data() == arr.data());
468        }
469
470        {
471            span<int, 2> s{arr};
472            CHECK(s.size() == 2 && s.data() == arr.data());
473
474            span<const int, 2> cs{arr};
475            CHECK(cs.size() == 2 && cs.data() == arr.data());
476        }
477
478        {
479            span<int, 0> s{arr};
480            CHECK(s.size() == 0 && s.data() == arr.data());
481
482            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        //    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            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 = [](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            span<const int> s{arr};
515            CHECK(s.size() == narrow_cast<ptrdiff_t>(arr.size()) && s.data() == arr.data());
516        }
517
518        {
519            span<const int, 4> s{arr};
520            CHECK(s.size() == narrow_cast<ptrdiff_t>(arr.size()) && s.data() == arr.data());
521        }
522
523        {
524            span<const int, 2> s{arr};
525            CHECK(s.size() == 2 && s.data() == arr.data());
526        }
527
528        {
529            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        //    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            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 = [](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            span<int> s{v};
563            CHECK(s.size() == narrow_cast<std::ptrdiff_t>(v.size()) && s.data() == v.data());
564
565            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            span<char> s{str};
575            CHECK(s.size() == narrow_cast<std::ptrdiff_t>(str.size()) && s.data() == str.data());
576#endif
577            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            span<char> s{cstr};
584#endif
585            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 = [](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 = [](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 = [](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 = [](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            span<int> s{m};
626#endif
627        }
628    }
629
630    TEST(from_convertible_span_constructor)
631    {
632#ifdef CONFIRM_COMPILATION_ERRORS
633        span<int, 7, 4, 2> av1(nullptr, b1);
634
635        auto f = [&]() { 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        span<int, dynamic_range> av1 = nullptr;
645        span<int, 7, dynamic_range, 2> av2(av1);
646        span<int, 7, 4, 2> av2(av1);
647#endif
648
649        span<DerivedClass> avd;
650#ifdef CONFIRM_COMPILATION_ERRORS
651        span<BaseClass> avb = avd;
652#endif
653        span<const DerivedClass> avcd = avd;
654        (void) avcd;
655    }
656
657    TEST(copy_move_and_assignment)
658    {
659        span<int> s1;
660        CHECK(s1.empty());
661
662        int arr[] = {3, 4, 5};
663
664        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 = [&]() -> span<int> { return {&arr[1], 2}; };
671        auto use_span = [&](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_span_reshape)
684    {
685        int a[3][4][5];
686        auto av = as_span(a);
687        fn(av.bounds());
688        auto av2 = as_span(av, dim<60>());
689        auto av3 = as_span(av2, dim<3>(), dim<4>(), dim<5>());
690        auto av4 = as_span(av3, dim<4>(), dim<>(3), dim<5>());
691        auto av5 = as_span(av4, dim<3>(), dim<4>(), dim<5>());
692        auto av6 = as_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_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            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            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            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            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            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            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            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            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            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            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            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            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            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            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            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            span<int> av;
837            CHECK(av.subspan(0).length() == 0);
838            CHECK_THROW(av.subspan(1).length(), fail_fast);
839        }
840
841        {
842            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            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            span<int> s;
870            CHECK(s.rank() == 1);
871        }
872
873        {
874            span<int, 2> s = arr;
875            CHECK(s.rank() == 1);
876        }
877
878        int arr2d[1][1] = {};
879        {
880            span<int, 1, 1> s = arr2d;
881            CHECK(s.rank() == 2);
882        }
883    }
884
885    TEST(extent)
886    {
887        {
888            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            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            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            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            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            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_span(arr);
953            span<const int, dynamic_range, 2> s2 = s1;
954
955            CHECK(s1 == s2);
956
957            span<int, 20> s3 = as_span(s1, dim<>(20));
958            CHECK(s3 == s2 && s3 == s1);
959        }
960
961        {
962            auto s1 = nullptr;
963            auto 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            span<int> s1 = nullptr;
982            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            span<int> s1 = arr1;
1002            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            span<int> s1 = {&arr[0], 2}; // shorter
1022            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            span<int> s1 = arr1;
1043            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_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_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
1089    void overloaded_func(span<const int, dynamic_range, 3, 5> exp, int expected_value)
1090    {
1091        for (auto val : exp) {
1092            CHECK(val == expected_value);
1093        }
1094    }
1095
1096    void overloaded_func(span<const char, dynamic_range, 3, 5> exp, char expected_value)
1097    {
1098        for (auto val : exp) {
1099            CHECK(val == expected_value);
1100        }
1101    }
1102
1103    void fixed_func(span<int, 3, 3, 5> exp, int expected_value)
1104    {
1105        for (auto val : exp) {
1106            CHECK(val == expected_value);
1107        }
1108    }
1109
1110    TEST(span_parameter_test)
1111    {
1112        auto data = new int[4][3][5];
1113
1114        auto av = as_span(data, 4);
1115
1116        CHECK(av.size() == 60);
1117
1118        fill(av.begin(), av.end(), 34);
1119
1120        int count = 0;
1121        for_each(av.rbegin(), av.rend(), [&](int val) { count += val; });
1122        CHECK(count == 34 * 60);
1123        overloaded_func(av, 34);
1124
1125        overloaded_func(as_span(av, dim<>(4), dim<>(3), dim<>(5)), 34);
1126
1127        // fixed_func(av, 34);
1128        delete[] data;
1129    }
1130
1131    TEST(md_access)
1132    {
1133        auto width = 5, height = 20;
1134
1135        auto imgSize = width * height;
1136        auto image_ptr = new int[imgSize][3];
1137
1138        // size check will be done
1139        auto image_view =
1140            as_span(as_span(image_ptr, imgSize), dim<>(height), dim<>(width), dim<3>());
1141
1142        iota(image_view.begin(), image_view.end(), 1);
1143
1144        int expected = 0;
1145        for (auto i = 0; i < height; i++) {
1146            for (auto j = 0; j < width; j++) {
1147                CHECK(expected + 1 == image_view[i][j][0]);
1148                CHECK(expected + 2 == image_view[i][j][1]);
1149                CHECK(expected + 3 == image_view[i][j][2]);
1150
1151                auto val = image_view[{i, j, 0}];
1152                CHECK(expected + 1 == val);
1153                val = image_view[{i, j, 1}];
1154                CHECK(expected + 2 == val);
1155                val = image_view[{i, j, 2}];
1156                CHECK(expected + 3 == val);
1157
1158                expected += 3;
1159            }
1160        }
1161    }
1162
1163    TEST(as_span)
1164    {
1165        {
1166            int* arr = new int[150];
1167
1168            auto av = as_span(arr, dim<10>(), dim<>(3), dim<5>());
1169
1170            fill(av.begin(), av.end(), 24);
1171            overloaded_func(av, 24);
1172
1173            delete[] arr;
1174
1175            array<int, 15> stdarr{0};
1176            auto av2 = as_span(stdarr);
1177            overloaded_func(as_span(av2, dim<>(1), dim<3>(), dim<5>()), 0);
1178
1179            string str = "ttttttttttttttt"; // size = 15
1180            auto t = str.data();
1181            (void) t;
1182            auto av3 = as_span(str);
1183            overloaded_func(as_span(av3, dim<>(1), dim<3>(), dim<5>()), 't');
1184        }
1185
1186        {
1187            string str;
1188            span<char> strspan = as_span(str);
1189            (void) strspan;
1190            const string cstr;
1191            span<const char> cstrspan = as_span(cstr);
1192            (void) cstrspan;
1193        }
1194
1195        {
1196            int a[3][4][5];
1197            auto av = as_span(a);
1198            const int(*b)[4][5];
1199            b = a;
1200            auto bv = as_span(b, 3);
1201
1202            CHECK(av == bv);
1203
1204            const std::array<double, 3> arr = {0.0, 0.0, 0.0};
1205            auto cv = as_span(arr);
1206            (void) cv;
1207
1208            vector<float> vec(3);
1209            auto dv = as_span(vec);
1210            (void) dv;
1211
1212#ifdef CONFIRM_COMPILATION_ERRORS
1213            auto dv2 = as_span(std::move(vec));
1214#endif
1215        }
1216    }
1217
1218    TEST(empty_spans)
1219    {
1220        {
1221            span<int, 0> empty_av(nullptr);
1222
1223            CHECK(empty_av.bounds().index_bounds() == index<1>{0});
1224            CHECK_THROW(empty_av[0], fail_fast);
1225            CHECK_THROW(empty_av.begin()[0], fail_fast);
1226            CHECK_THROW(empty_av.cbegin()[0], fail_fast);
1227            for (auto& v : empty_av) {
1228                (void) v;
1229                CHECK(false);
1230            }
1231        }
1232
1233        {
1234            span<int> empty_av = {};
1235            CHECK(empty_av.bounds().index_bounds() == index<1>{0});
1236            CHECK_THROW(empty_av[0], fail_fast);
1237            CHECK_THROW(empty_av.begin()[0], fail_fast);
1238            CHECK_THROW(empty_av.cbegin()[0], fail_fast);
1239            for (auto& v : empty_av) {
1240                (void) v;
1241                CHECK(false);
1242            }
1243        }
1244    }
1245
1246    TEST(index_constructor)
1247    {
1248        auto arr = new int[8];
1249        for (int i = 0; i < 4; ++i) {
1250            arr[2 * i] = 4 + i;
1251            arr[2 * i + 1] = i;
1252        }
1253
1254        span<int, dynamic_range> av(arr, 8);
1255
1256        ptrdiff_t a[1] = {0};
1257        index<1> i = a;
1258
1259        CHECK(av[i] == 4);
1260
1261        auto av2 = as_span(av, dim<4>(), dim<>(2));
1262        ptrdiff_t a2[2] = {0, 1};
1263        index<2> i2 = a2;
1264
1265        CHECK(av2[i2] == 0);
1266        CHECK(av2[0][i] == 4);
1267
1268        delete[] arr;
1269    }
1270
1271    TEST(index_constructors)
1272    {
1273        {
1274            // components of the same type
1275            index<3> i1(0, 1, 2);
1276            CHECK(i1[0] == 0);
1277
1278            // components of different types
1279            size_t c0 = 0;
1280            size_t c1 = 1;
1281            index<3> i2(c0, c1, 2);
1282            CHECK(i2[0] == 0);
1283
1284            // from array
1285            index<3> i3 = {0, 1, 2};
1286            CHECK(i3[0] == 0);
1287
1288            // from other index of the same size type
1289            index<3> i4 = i3;
1290            CHECK(i4[0] == 0);
1291
1292            // default
1293            index<3> i7;
1294            CHECK(i7[0] == 0);
1295
1296            // default
1297            index<3> i9 = {};
1298            CHECK(i9[0] == 0);
1299        }
1300
1301        {
1302            // components of the same type
1303            index<1> i1(0);
1304            CHECK(i1[0] == 0);
1305
1306            // components of different types
1307            size_t c0 = 0;
1308            index<1> i2(c0);
1309            CHECK(i2[0] == 0);
1310
1311            // from array
1312            index<1> i3 = {0};
1313            CHECK(i3[0] == 0);
1314
1315            // from int
1316            index<1> i4 = 0;
1317            CHECK(i4[0] == 0);
1318
1319            // from other index of the same size type
1320            index<1> i5 = i3;
1321            CHECK(i5[0] == 0);
1322
1323            // default
1324            index<1> i8;
1325            CHECK(i8[0] == 0);
1326
1327            // default
1328            index<1> i9 = {};
1329            CHECK(i9[0] == 0);
1330        }
1331
1332#ifdef CONFIRM_COMPILATION_ERRORS
1333        {
1334            index<3> i1(0, 1);
1335            index<3> i2(0, 1, 2, 3);
1336            index<3> i3 = {0};
1337            index<3> i4 = {0, 1, 2, 3};
1338            index<1> i5 = {0, 1};
1339        }
1340#endif
1341    }
1342
1343    TEST(index_operations)
1344    {
1345        ptrdiff_t a[3] = {0, 1, 2};
1346        ptrdiff_t b[3] = {3, 4, 5};
1347        index<3> i = a;
1348        index<3> j = b;
1349
1350        CHECK(i[0] == 0);
1351        CHECK(i[1] == 1);
1352        CHECK(i[2] == 2);
1353
1354        {
1355            index<3> k = i + j;
1356
1357            CHECK(i[0] == 0);
1358            CHECK(i[1] == 1);
1359            CHECK(i[2] == 2);
1360            CHECK(k[0] == 3);
1361            CHECK(k[1] == 5);
1362            CHECK(k[2] == 7);
1363        }
1364
1365        {
1366            index<3> k = i * 3;
1367
1368            CHECK(i[0] == 0);
1369            CHECK(i[1] == 1);
1370            CHECK(i[2] == 2);
1371            CHECK(k[0] == 0);
1372            CHECK(k[1] == 3);
1373            CHECK(k[2] == 6);
1374        }
1375
1376        {
1377            index<3> k = 3 * i;
1378
1379            CHECK(i[0] == 0);
1380            CHECK(i[1] == 1);
1381            CHECK(i[2] == 2);
1382            CHECK(k[0] == 0);
1383            CHECK(k[1] == 3);
1384            CHECK(k[2] == 6);
1385        }
1386
1387        {
1388            index<2> k = details::shift_left(i);
1389
1390            CHECK(i[0] == 0);
1391            CHECK(i[1] == 1);
1392            CHECK(i[2] == 2);
1393            CHECK(k[0] == 1);
1394            CHECK(k[1] == 2);
1395        }
1396    }
1397
1398    void iterate_second_column(span<int, dynamic_range, dynamic_range> av)
1399    {
1400        auto length = av.size() / 2;
1401
1402        // view to the second column
1403        auto section = av.section({0, 1}, {length, 1});
1404
1405        CHECK(section.size() == length);
1406        for (auto i = 0; i < section.size(); ++i) {
1407            CHECK(section[i][0] == av[i][1]);
1408        }
1409
1410        for (auto i = 0; i < section.size(); ++i) {
1411            auto idx = index<2>{i, 0}; // avoid braces inside the CHECK macro
1412            CHECK(section[idx] == av[i][1]);
1413        }
1414
1415        CHECK(section.bounds().index_bounds()[0] == length);
1416        CHECK(section.bounds().index_bounds()[1] == 1);
1417        for (auto i = 0; i < section.bounds().index_bounds()[0]; ++i) {
1418            for (auto j = 0; j < section.bounds().index_bounds()[1]; ++j) {
1419                auto idx = index<2>{i, j}; // avoid braces inside the CHECK macro
1420                CHECK(section[idx] == av[i][1]);
1421            }
1422        }
1423
1424        size_t check_sum = 0;
1425        for (auto i = 0; i < length; ++i) {
1426            check_sum += av[i][1];
1427        }
1428
1429        {
1430            auto idx = 0;
1431            size_t sum = 0;
1432            for (auto num : section) {
1433                CHECK(num == av[idx][1]);
1434                sum += num;
1435                idx++;
1436            }
1437
1438            CHECK(sum == check_sum);
1439        }
1440        {
1441            size_t idx = length - 1;
1442            size_t sum = 0;
1443            for (auto iter = section.rbegin(); iter != section.rend(); ++iter) {
1444                CHECK(*iter == av[idx][1]);
1445                sum += *iter;
1446                idx--;
1447            }
1448
1449            CHECK(sum == check_sum);
1450        }
1451    }
1452
1453    TEST(span_section_iteration)
1454    {
1455        int arr[4][2] = {{4, 0}, {5, 1}, {6, 2}, {7, 3}};
1456
1457        // static bounds
1458        {
1459            span<int, 4, 2> av = arr;
1460            iterate_second_column(av);
1461        }
1462        // first bound is dynamic
1463        {
1464            span<int, dynamic_range, 2> av = arr;
1465            iterate_second_column(av);
1466        }
1467        // second bound is dynamic
1468        {
1469            span<int, 4, dynamic_range> av = arr;
1470            iterate_second_column(av);
1471        }
1472        // both bounds are dynamic
1473        {
1474            span<int, dynamic_range, dynamic_range> av = arr;
1475            iterate_second_column(av);
1476        }
1477    }
1478
1479    TEST(dynamic_span_section_iteration)
1480    {
1481        auto height = 4, width = 2;
1482        auto size = height * width;
1483
1484        auto arr = new int[size];
1485        for (auto i = 0; i < size; ++i) {
1486            arr[i] = i;
1487        }
1488
1489        auto av = as_span(arr, size);
1490
1491        // first bound is dynamic
1492        {
1493            span<int, dynamic_range, 2> av2 = as_span(av, dim<>(height), dim<>(width));
1494            iterate_second_column(av2);
1495        }
1496        // second bound is dynamic
1497        {
1498            span<int, 4, dynamic_range> av2 = as_span(av, dim<>(height), dim<>(width));
1499            iterate_second_column(av2);
1500        }
1501        // both bounds are dynamic
1502        {
1503            span<int, dynamic_range, dynamic_range> av2 = as_span(av, dim<>(height), dim<>(width));
1504            iterate_second_column(av2);
1505        }
1506
1507        delete[] arr;
1508    }
1509
1510    TEST(span_structure_size)
1511    {
1512        double(*arr)[3][4] = new double[100][3][4];
1513        span<double, dynamic_range, 3, 4> av1(arr, 10);
1514
1515        struct EffectiveStructure
1516        {
1517            double* v1;
1518            ptrdiff_t v2;
1519        };
1520        CHECK(sizeof(av1) == sizeof(EffectiveStructure));
1521
1522        CHECK_THROW(av1[10][3][4], fail_fast);
1523
1524        span<const double, dynamic_range, 6, 4> av2 = as_span(av1, dim<>(5), dim<6>(), dim<4>());
1525        (void) av2;
1526    }
1527
1528    TEST(fixed_size_conversions)
1529    {
1530        int arr[] = {1, 2, 3, 4};
1531
1532        // converting to an span from an equal size array is ok
1533        span<int, 4> av4 = arr;
1534        CHECK(av4.length() == 4);
1535
1536        // converting to dynamic_range a_v is always ok
1537        {
1538            span<int, dynamic_range> av = av4;
1539            (void) av;
1540        }
1541        {
1542            span<int, dynamic_range> av = arr;
1543            (void) av;
1544        }
1545
1546// initialization or assignment to static span that REDUCES size is NOT ok
1547#ifdef CONFIRM_COMPILATION_ERRORS
1548        {
1549            span<int, 2> av2 = arr;
1550        }
1551        {
1552            span<int, 2> av2 = av4;
1553        }
1554#endif
1555
1556        {
1557            span<int, dynamic_range> av = arr;
1558            span<int, 2> av2 = av;
1559            (void) av2;
1560        }
1561
1562#ifdef CONFIRM_COMPILATION_ERRORS
1563        {
1564            span<int, dynamic_range> av = arr;
1565            span<int, 2, 1> av2 = av.as_span(dim<2>(), dim<2>());
1566        }
1567#endif
1568
1569        {
1570            span<int, dynamic_range> av = arr;
1571            span<int, 2, 1> av2 = as_span(av, dim<>(2), dim<>(2));
1572            auto workaround_macro = [&]() { return av2[{1, 0}] == 2; };
1573            CHECK(workaround_macro());
1574        }
1575
1576        // but doing so explicitly is ok
1577
1578        // you can convert statically
1579        {
1580            span<int, 2> av2 = {arr, 2};
1581            (void) av2;
1582        }
1583        {
1584            span<int, 1> av2 = av4.first<1>();
1585            (void) av2;
1586        }
1587
1588        // ...or dynamically
1589        {
1590            // NB: implicit conversion to span<int,2> from span<int,dynamic_range>
1591            span<int, 1> av2 = av4.first(1);
1592            (void) av2;
1593        }
1594
1595        // initialization or assignment to static span that requires size INCREASE is not ok.
1596        int arr2[2] = {1, 2};
1597
1598#ifdef CONFIRM_COMPILATION_ERRORS
1599        {
1600            span<int, 4> av4 = arr2;
1601        }
1602        {
1603            span<int, 2> av2 = arr2;
1604            span<int, 4> av4 = av2;
1605        }
1606#endif
1607        {
1608            auto f = [&]() {
1609                span<int, 4> av4 = {arr2, 2};
1610                (void) av4;
1611            };
1612            CHECK_THROW(f(), fail_fast);
1613        }
1614
1615        // this should fail - we are trying to assign a small dynamic a_v to a fixed_size larger one
1616        span<int, dynamic_range> av = arr2;
1617        auto f = [&]() {
1618            span<int, 4> av2 = av;
1619            (void) av2;
1620        };
1621        CHECK_THROW(f(), fail_fast);
1622    }
1623
1624    TEST(as_writeable_bytes)
1625    {
1626        int a[] = {1, 2, 3, 4};
1627
1628        {
1629#ifdef CONFIRM_COMPILATION_ERRORS
1630            // you should not be able to get writeable bytes for const objects
1631            span<const int, dynamic_range> av = a;
1632            auto wav = av.as_writeable_bytes();
1633#endif
1634        }
1635
1636        {
1637            span<int, dynamic_range> av;
1638            auto wav = as_writeable_bytes(av);
1639            CHECK(wav.length() == av.length());
1640            CHECK(wav.length() == 0);
1641            CHECK(wav.size_bytes() == 0);
1642        }
1643
1644        {
1645            span<int, dynamic_range> av = a;
1646            auto wav = as_writeable_bytes(av);
1647            CHECK(wav.data() == (byte*) &a[0]);
1648            CHECK(wav.length() == sizeof(a));
1649        }
1650    }
1651
1652    TEST(iterator)
1653    {
1654        int a[] = {1, 2, 3, 4};
1655
1656        {
1657            span<int, dynamic_range> av = a;
1658            auto wav = as_writeable_bytes(av);
1659            for (auto& b : wav) {
1660                b = byte(0);
1661            }
1662            for (size_t i = 0; i < 4; ++i) {
1663                CHECK(a[i] == 0);
1664            }
1665        }
1666
1667        {
1668            span<int, dynamic_range> av = a;
1669            for (auto& n : av) {
1670                n = 1;
1671            }
1672            for (size_t i = 0; i < 4; ++i) {
1673                CHECK(a[i] == 1);
1674            }
1675        }
1676    }
1677}
1678
1679int main(int, const char* []) { return UnitTest::RunAllTests(); }
1680