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