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