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