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