Home | History | Annotate | Download | only in tests
      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 
     28 using namespace std;
     29 using namespace gsl;
     30 
     31 namespace
     32 {
     33 struct BaseClass
     34 {
     35 };
     36 struct DerivedClass : BaseClass
     37 {
     38 };
     39 }
     40 
     41 TEST_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 
     75 TEST_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 
    117 TEST_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 
    167 TEST_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 
    217 TEST_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 
    246 TEST_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 
    296 TEST_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 
    420 TEST_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 
    448 TEST_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 
    507 TEST_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 
    554 TEST_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 
    628 TEST_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 
    655 TEST_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 
    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_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 
    706 TEST_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 
    749 TEST_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 
    791 TEST_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 
    864 TEST_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 
    885 TEST_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 
    929 TEST_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 
    957 TEST_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 
   1069 TEST_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 
   1080 TEST_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 
   1104 void 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 
   1111 void 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 
   1118 void 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 
   1125 TEST_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 
   1146 TEST_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 
   1178 TEST_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 
   1233 TEST_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 
   1261 TEST_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 
   1286 TEST_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 
   1358 TEST_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 
   1413 void 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 
   1468 TEST_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 
   1494 TEST_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 
   1526 TEST_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 
   1545 TEST_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 
   1641 TEST_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 
   1669 TEST_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