1 /////////////////////////////////////////////////////////////////////////////// 2 // 3 // Copyright (c) 2015 Microsoft Corporation. All rights reserved. 4 // 5 // This code is licensed under the MIT License (MIT). 6 // 7 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 8 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 9 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 10 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 11 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 12 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 13 // THE SOFTWARE. 14 // 15 /////////////////////////////////////////////////////////////////////////////// 16 17 #include <catch/catch.hpp> 18 19 #include <gsl/multi_span> 20 21 #include <iostream> 22 #include <list> 23 #include <map> 24 #include <memory> 25 #include <string> 26 #include <vector> 27 28 using namespace std; 29 using namespace gsl; 30 31 namespace 32 { 33 struct BaseClass 34 { 35 }; 36 struct DerivedClass : BaseClass 37 { 38 }; 39 } 40 41 TEST_CASE("span_section_test") 42 { 43 int a[30][4][5]; 44 45 const auto av = as_multi_span(a); 46 const auto sub = av.section({15, 0, 0}, gsl::index<3>{2, 2, 2}); 47 const auto subsub = sub.section({1, 0, 0}, gsl::index<3>{1, 1, 1}); 48 (void) subsub; 49 } 50 51 TEST_CASE("span_section") 52 { 53 std::vector<int> data(5 * 10); 54 std::iota(begin(data), end(data), 0); 55 const multi_span<int, 5, 10> av = as_multi_span(multi_span<int>{data}, dim<5>(), dim<10>()); 56 57 const strided_span<int, 2> av_section_1 = av.section({1, 2}, {3, 4}); 58 CHECK((av_section_1[{0, 0}] == 12)); 59 CHECK((av_section_1[{0, 1}] == 13)); 60 CHECK((av_section_1[{1, 0}] == 22)); 61 CHECK((av_section_1[{2, 3}] == 35)); 62 63 const strided_span<int, 2> av_section_2 = av_section_1.section({1, 2}, {2, 2}); 64 CHECK((av_section_2[{0, 0}] == 24)); 65 CHECK((av_section_2[{0, 1}] == 25)); 66 CHECK((av_section_2[{1, 0}] == 34)); 67 } 68 69 TEST_CASE("strided_span_constructors") 70 { 71 // Check stride constructor 72 { 73 int arr[] = {1, 2, 3, 4, 5, 6, 7, 8, 9}; 74 const int carr[] = {1, 2, 3, 4, 5, 6, 7, 8, 9}; 75 76 strided_span<int, 1> sav1{arr, {{9}, {1}}}; // T -> T 77 CHECK(sav1.bounds().index_bounds() == index<1>{9}); 78 CHECK(sav1.bounds().stride() == 1); 79 CHECK((sav1[0] == 1 && sav1[8] == 9)); 80 81 strided_span<const int, 1> sav2{carr, {{4}, {2}}}; // const T -> const T 82 CHECK(sav2.bounds().index_bounds() == index<1>{4}); 83 CHECK(sav2.bounds().strides() == index<1>{2}); 84 CHECK((sav2[0] == 1 && sav2[3] == 7)); 85 86 strided_span<int, 2> sav3{arr, {{2, 2}, {6, 2}}}; // T -> const T 87 CHECK((sav3.bounds().index_bounds() == index<2>{2, 2})); 88 CHECK((sav3.bounds().strides() == index<2>{6, 2})); 89 CHECK((sav3[{0, 0}] == 1 && sav3[{0, 1}] == 3 && sav3[{1, 0}] == 7)); 90 } 91 92 // Check multi_span constructor 93 { 94 int arr[] = {1, 2}; 95 96 // From non-cv-qualified source 97 { 98 const multi_span<int> src = arr; 99 100 strided_span<int, 1> sav{src, {2, 1}}; 101 CHECK(sav.bounds().index_bounds() == index<1>{2}); 102 CHECK(sav.bounds().strides() == index<1>{1}); 103 CHECK(sav[1] == 2); 104 105 #if _MSC_VER > 1800 106 // strided_span<const int, 1> sav_c{ {src}, {2, 1} }; 107 strided_span<const int, 1> sav_c{multi_span<const int>{src}, 108 strided_bounds<1>{2, 1}}; 109 #else 110 strided_span<const int, 1> sav_c{multi_span<const int>{src}, 111 strided_bounds<1>{2, 1}}; 112 #endif 113 CHECK(sav_c.bounds().index_bounds() == index<1>{2}); 114 CHECK(sav_c.bounds().strides() == index<1>{1}); 115 CHECK(sav_c[1] == 2); 116 117 #if _MSC_VER > 1800 118 strided_span<volatile int, 1> sav_v{src, {2, 1}}; 119 #else 120 strided_span<volatile int, 1> sav_v{multi_span<volatile int>{src}, 121 strided_bounds<1>{2, 1}}; 122 #endif 123 CHECK(sav_v.bounds().index_bounds() == index<1>{2}); 124 CHECK(sav_v.bounds().strides() == index<1>{1}); 125 CHECK(sav_v[1] == 2); 126 127 #if _MSC_VER > 1800 128 strided_span<const volatile int, 1> sav_cv{src, {2, 1}}; 129 #else 130 strided_span<const volatile int, 1> sav_cv{multi_span<const volatile int>{src}, 131 strided_bounds<1>{2, 1}}; 132 #endif 133 CHECK(sav_cv.bounds().index_bounds() == index<1>{2}); 134 CHECK(sav_cv.bounds().strides() == index<1>{1}); 135 CHECK(sav_cv[1] == 2); 136 } 137 138 // From const-qualified source 139 { 140 const multi_span<const int> src{arr}; 141 142 strided_span<const int, 1> sav_c{src, {2, 1}}; 143 CHECK(sav_c.bounds().index_bounds() == index<1>{2}); 144 CHECK(sav_c.bounds().strides() == index<1>{1}); 145 CHECK(sav_c[1] == 2); 146 147 #if _MSC_VER > 1800 148 strided_span<const volatile int, 1> sav_cv{src, {2, 1}}; 149 #else 150 strided_span<const volatile int, 1> sav_cv{multi_span<const volatile int>{src}, 151 strided_bounds<1>{2, 1}}; 152 #endif 153 154 CHECK(sav_cv.bounds().index_bounds() == index<1>{2}); 155 CHECK(sav_cv.bounds().strides() == index<1>{1}); 156 CHECK(sav_cv[1] == 2); 157 } 158 159 // From volatile-qualified source 160 { 161 const multi_span<volatile int> src{arr}; 162 163 strided_span<volatile int, 1> sav_v{src, {2, 1}}; 164 CHECK(sav_v.bounds().index_bounds() == index<1>{2}); 165 CHECK(sav_v.bounds().strides() == index<1>{1}); 166 CHECK(sav_v[1] == 2); 167 168 #if _MSC_VER > 1800 169 strided_span<const volatile int, 1> sav_cv{src, {2, 1}}; 170 #else 171 strided_span<const volatile int, 1> sav_cv{multi_span<const volatile int>{src}, 172 strided_bounds<1>{2, 1}}; 173 #endif 174 CHECK(sav_cv.bounds().index_bounds() == index<1>{2}); 175 CHECK(sav_cv.bounds().strides() == index<1>{1}); 176 CHECK(sav_cv[1] == 2); 177 } 178 179 // From cv-qualified source 180 { 181 const multi_span<const volatile int> src{arr}; 182 183 strided_span<const volatile int, 1> sav_cv{src, {2, 1}}; 184 CHECK(sav_cv.bounds().index_bounds() == index<1>{2}); 185 CHECK(sav_cv.bounds().strides() == index<1>{1}); 186 CHECK(sav_cv[1] == 2); 187 } 188 } 189 190 // Check const-casting constructor 191 { 192 int arr[2] = {4, 5}; 193 194 const multi_span<int, 2> av(arr, 2); 195 multi_span<const int, 2> av2{av}; 196 CHECK(av2[1] == 5); 197 198 static_assert( 199 std::is_convertible<const multi_span<int, 2>, multi_span<const int, 2>>::value, 200 "ctor is not implicit!"); 201 202 const strided_span<int, 1> src{arr, {2, 1}}; 203 strided_span<const int, 1> sav{src}; 204 CHECK(sav.bounds().index_bounds() == index<1>{2}); 205 CHECK(sav.bounds().stride() == 1); 206 CHECK(sav[1] == 5); 207 208 static_assert( 209 std::is_convertible<const strided_span<int, 1>, strided_span<const int, 1>>::value, 210 "ctor is not implicit!"); 211 } 212 213 // Check copy constructor 214 { 215 int arr1[2] = {3, 4}; 216 const strided_span<int, 1> src1{arr1, {2, 1}}; 217 strided_span<int, 1> sav1{src1}; 218 219 CHECK(sav1.bounds().index_bounds() == index<1>{2}); 220 CHECK(sav1.bounds().stride() == 1); 221 CHECK(sav1[0] == 3); 222 223 int arr2[6] = {1, 2, 3, 4, 5, 6}; 224 const strided_span<const int, 2> src2{arr2, {{3, 2}, {2, 1}}}; 225 strided_span<const int, 2> sav2{src2}; 226 CHECK((sav2.bounds().index_bounds() == index<2>{3, 2})); 227 CHECK((sav2.bounds().strides() == index<2>{2, 1})); 228 CHECK((sav2[{0, 0}] == 1 && sav2[{2, 0}] == 5)); 229 } 230 231 // Check const-casting assignment operator 232 { 233 int arr1[2] = {1, 2}; 234 int arr2[6] = {3, 4, 5, 6, 7, 8}; 235 236 const strided_span<int, 1> src{arr1, {{2}, {1}}}; 237 strided_span<const int, 1> sav{arr2, {{3}, {2}}}; 238 strided_span<const int, 1>& sav_ref = (sav = src); 239 CHECK(sav.bounds().index_bounds() == index<1>{2}); 240 CHECK(sav.bounds().strides() == index<1>{1}); 241 CHECK(sav[0] == 1); 242 CHECK(&sav_ref == &sav); 243 } 244 245 // Check copy assignment operator 246 { 247 int arr1[2] = {3, 4}; 248 int arr1b[1] = {0}; 249 const strided_span<int, 1> src1{arr1, {2, 1}}; 250 strided_span<int, 1> sav1{arr1b, {1, 1}}; 251 strided_span<int, 1>& sav1_ref = (sav1 = src1); 252 CHECK(sav1.bounds().index_bounds() == index<1>{2}); 253 CHECK(sav1.bounds().strides() == index<1>{1}); 254 CHECK(sav1[0] == 3); 255 CHECK(&sav1_ref == &sav1); 256 257 const int arr2[6] = {1, 2, 3, 4, 5, 6}; 258 const int arr2b[1] = {0}; 259 const strided_span<const int, 2> src2{arr2, {{3, 2}, {2, 1}}}; 260 strided_span<const int, 2> sav2{arr2b, {{1, 1}, {1, 1}}}; 261 strided_span<const int, 2>& sav2_ref = (sav2 = src2); 262 CHECK((sav2.bounds().index_bounds() == index<2>{3, 2})); 263 CHECK((sav2.bounds().strides() == index<2>{2, 1})); 264 CHECK((sav2[{0, 0}] == 1 && sav2[{2, 0}] == 5)); 265 CHECK(&sav2_ref == &sav2); 266 } 267 } 268 269 TEST_CASE("strided_span_slice") 270 { 271 std::vector<int> data(5 * 10); 272 std::iota(begin(data), end(data), 0); 273 const multi_span<int, 5, 10> src = 274 as_multi_span(multi_span<int>{data}, dim<5>(), dim<10>()); 275 276 const strided_span<int, 2> sav{src, {{5, 10}, {10, 1}}}; 277 #ifdef CONFIRM_COMPILATION_ERRORS 278 const strided_span<const int, 2> csav{{src}, {{5, 10}, {10, 1}}}; 279 #endif 280 const strided_span<const int, 2> csav{multi_span<const int, 5, 10>{src}, 281 {{5, 10}, {10, 1}}}; 282 283 strided_span<int, 1> sav_sl = sav[2]; 284 CHECK(sav_sl[0] == 20); 285 CHECK(sav_sl[9] == 29); 286 287 strided_span<const int, 1> csav_sl = sav[3]; 288 CHECK(csav_sl[0] == 30); 289 CHECK(csav_sl[9] == 39); 290 291 CHECK(sav[4][0] == 40); 292 CHECK(sav[4][9] == 49); 293 } 294 295 TEST_CASE("strided_span_column_major") 296 { 297 // strided_span may be used to accomodate more peculiar 298 // use cases, such as column-major multidimensional array 299 // (aka. "FORTRAN" layout). 300 301 int cm_array[3 * 5] = {1, 4, 7, 10, 13, 2, 5, 8, 11, 14, 3, 6, 9, 12, 15}; 302 strided_span<int, 2> cm_sav{cm_array, {{5, 3}, {1, 5}}}; 303 304 // Accessing elements 305 CHECK((cm_sav[{0, 0}] == 1)); 306 CHECK((cm_sav[{0, 1}] == 2)); 307 CHECK((cm_sav[{1, 0}] == 4)); 308 CHECK((cm_sav[{4, 2}] == 15)); 309 310 // Slice 311 strided_span<int, 1> cm_sl = cm_sav[3]; 312 313 CHECK(cm_sl[0] == 10); 314 CHECK(cm_sl[1] == 11); 315 CHECK(cm_sl[2] == 12); 316 317 // Section 318 strided_span<int, 2> cm_sec = cm_sav.section({2, 1}, {3, 2}); 319 320 CHECK((cm_sec.bounds().index_bounds() == index<2>{3, 2})); 321 CHECK((cm_sec[{0, 0}] == 8)); 322 CHECK((cm_sec[{0, 1}] == 9)); 323 CHECK((cm_sec[{1, 0}] == 11)); 324 CHECK((cm_sec[{2, 1}] == 15)); 325 } 326 327 TEST_CASE("strided_span_bounds") 328 { 329 int arr[] = {0, 1, 2, 3}; 330 multi_span<int> av(arr); 331 332 { 333 // incorrect sections 334 335 CHECK_THROWS_AS(av.section(0, 0)[0], fail_fast); 336 CHECK_THROWS_AS(av.section(1, 0)[0], fail_fast); 337 CHECK_THROWS_AS(av.section(1, 1)[1], fail_fast); 338 339 CHECK_THROWS_AS(av.section(2, 5), fail_fast); 340 CHECK_THROWS_AS(av.section(5, 2), fail_fast); 341 CHECK_THROWS_AS(av.section(5, 0), fail_fast); 342 CHECK_THROWS_AS(av.section(0, 5), fail_fast); 343 CHECK_THROWS_AS(av.section(5, 5), fail_fast); 344 } 345 346 { 347 // zero stride 348 strided_span<int, 1> sav{av, {{4}, {}}}; 349 CHECK(sav[0] == 0); 350 CHECK(sav[3] == 0); 351 CHECK_THROWS_AS(sav[4], fail_fast); 352 } 353 354 { 355 // zero extent 356 strided_span<int, 1> sav{av, {{}, {1}}}; 357 CHECK_THROWS_AS(sav[0], fail_fast); 358 } 359 360 { 361 // zero extent and stride 362 strided_span<int, 1> sav{av, {{}, {}}}; 363 CHECK_THROWS_AS(sav[0], fail_fast); 364 } 365 366 { 367 // strided array ctor with matching strided bounds 368 strided_span<int, 1> sav{arr, {4, 1}}; 369 CHECK(sav.bounds().index_bounds() == index<1>{4}); 370 CHECK(sav[3] == 3); 371 CHECK_THROWS_AS(sav[4], fail_fast); 372 } 373 374 { 375 // strided array ctor with smaller strided bounds 376 strided_span<int, 1> sav{arr, {2, 1}}; 377 CHECK(sav.bounds().index_bounds() == index<1>{2}); 378 CHECK(sav[1] == 1); 379 CHECK_THROWS_AS(sav[2], fail_fast); 380 } 381 382 { 383 // strided array ctor with fitting irregular bounds 384 strided_span<int, 1> sav{arr, {2, 3}}; 385 CHECK(sav.bounds().index_bounds() == index<1>{2}); 386 CHECK(sav[0] == 0); 387 CHECK(sav[1] == 3); 388 CHECK_THROWS_AS(sav[2], fail_fast); 389 } 390 391 { 392 // bounds cross data boundaries - from static arrays 393 CHECK_THROWS_AS((strided_span<int, 1>{arr, {3, 2}}), fail_fast); 394 CHECK_THROWS_AS((strided_span<int, 1>{arr, {3, 3}}), fail_fast); 395 CHECK_THROWS_AS((strided_span<int, 1>{arr, {4, 5}}), fail_fast); 396 CHECK_THROWS_AS((strided_span<int, 1>{arr, {5, 1}}), fail_fast); 397 CHECK_THROWS_AS((strided_span<int, 1>{arr, {5, 5}}), fail_fast); 398 } 399 400 { 401 // bounds cross data boundaries - from array view 402 CHECK_THROWS_AS((strided_span<int, 1>{av, {3, 2}}), fail_fast); 403 CHECK_THROWS_AS((strided_span<int, 1>{av, {3, 3}}), fail_fast); 404 CHECK_THROWS_AS((strided_span<int, 1>{av, {4, 5}}), fail_fast); 405 CHECK_THROWS_AS((strided_span<int, 1>{av, {5, 1}}), fail_fast); 406 CHECK_THROWS_AS((strided_span<int, 1>{av, {5, 5}}), fail_fast); 407 } 408 409 { 410 // bounds cross data boundaries - from dynamic arrays 411 CHECK_THROWS_AS((strided_span<int, 1>{av.data(), 4, {3, 2}}), fail_fast); 412 CHECK_THROWS_AS((strided_span<int, 1>{av.data(), 4, {3, 3}}), fail_fast); 413 CHECK_THROWS_AS((strided_span<int, 1>{av.data(), 4, {4, 5}}), fail_fast); 414 CHECK_THROWS_AS((strided_span<int, 1>{av.data(), 4, {5, 1}}), fail_fast); 415 CHECK_THROWS_AS((strided_span<int, 1>{av.data(), 4, {5, 5}}), fail_fast); 416 CHECK_THROWS_AS((strided_span<int, 1>{av.data(), 2, {2, 2}}), fail_fast); 417 } 418 419 #ifdef CONFIRM_COMPILATION_ERRORS 420 { 421 strided_span<int, 1> sav0{av.data(), {3, 2}}; 422 strided_span<int, 1> sav1{arr, {1}}; 423 strided_span<int, 1> sav2{arr, {1, 1, 1}}; 424 strided_span<int, 1> sav3{av, {1}}; 425 strided_span<int, 1> sav4{av, {1, 1, 1}}; 426 strided_span<int, 2> sav5{av.as_multi_span(dim<2>(), dim<2>()), {1}}; 427 strided_span<int, 2> sav6{av.as_multi_span(dim<2>(), dim<2>()), {1, 1, 1}}; 428 strided_span<int, 2> sav7{av.as_multi_span(dim<2>(), dim<2>()), 429 {{1, 1}, {1, 1}, {1, 1}}}; 430 431 index<1> index{0, 1}; 432 strided_span<int, 1> sav8{arr, {1, {1, 1}}}; 433 strided_span<int, 1> sav9{arr, {{1, 1}, {1, 1}}}; 434 strided_span<int, 1> sav10{av, {1, {1, 1}}}; 435 strided_span<int, 1> sav11{av, {{1, 1}, {1, 1}}}; 436 strided_span<int, 2> sav12{av.as_multi_span(dim<2>(), dim<2>()), {{1}, {1}}}; 437 strided_span<int, 2> sav13{av.as_multi_span(dim<2>(), dim<2>()), {{1}, {1, 1, 1}}}; 438 strided_span<int, 2> sav14{av.as_multi_span(dim<2>(), dim<2>()), {{1, 1, 1}, {1}}}; 439 } 440 #endif 441 } 442 443 TEST_CASE("strided_span_type_conversion") 444 { 445 int arr[] = {0, 1, 2, 3}; 446 multi_span<int> av(arr); 447 448 { 449 strided_span<int, 1> sav{av.data(), av.size(), {av.size() / 2, 2}}; 450 #ifdef CONFIRM_COMPILATION_ERRORS 451 strided_span<long, 1> lsav1 = sav.as_strided_span<long, 1>(); 452 #endif 453 } 454 { 455 strided_span<int, 1> sav{av, {av.size() / 2, 2}}; 456 #ifdef CONFIRM_COMPILATION_ERRORS 457 strided_span<long, 1> lsav1 = sav.as_strided_span<long, 1>(); 458 #endif 459 } 460 461 multi_span<const byte, dynamic_range> bytes = as_bytes(av); 462 463 // retype strided array with regular strides - from raw data 464 { 465 strided_bounds<2> bounds{{2, bytes.size() / 4}, {bytes.size() / 2, 1}}; 466 strided_span<const byte, 2> sav2{bytes.data(), bytes.size(), bounds}; 467 strided_span<const int, 2> sav3 = sav2.as_strided_span<const int>(); 468 CHECK(sav3[0][0] == 0); 469 CHECK(sav3[1][0] == 2); 470 CHECK_THROWS_AS(sav3[1][1], fail_fast); 471 CHECK_THROWS_AS(sav3[0][1], fail_fast); 472 } 473 474 // retype strided array with regular strides - from multi_span 475 { 476 strided_bounds<2> bounds{{2, bytes.size() / 4}, {bytes.size() / 2, 1}}; 477 multi_span<const byte, 2, dynamic_range> bytes2 = 478 as_multi_span(bytes, dim<2>(), dim(bytes.size() / 2)); 479 strided_span<const byte, 2> sav2{bytes2, bounds}; 480 strided_span<int, 2> sav3 = sav2.as_strided_span<int>(); 481 CHECK(sav3[0][0] == 0); 482 CHECK(sav3[1][0] == 2); 483 CHECK_THROWS_AS(sav3[1][1], fail_fast); 484 CHECK_THROWS_AS(sav3[0][1], fail_fast); 485 } 486 487 // retype strided array with not enough elements - last dimension of the array is too small 488 { 489 strided_bounds<2> bounds{{4, 2}, {4, 1}}; 490 multi_span<const byte, 2, dynamic_range> bytes2 = 491 as_multi_span(bytes, dim<2>(), dim(bytes.size() / 2)); 492 strided_span<const byte, 2> sav2{bytes2, bounds}; 493 CHECK_THROWS_AS(sav2.as_strided_span<int>(), fail_fast); 494 } 495 496 // retype strided array with not enough elements - strides are too small 497 { 498 strided_bounds<2> bounds{{4, 2}, {2, 1}}; 499 multi_span<const byte, 2, dynamic_range> bytes2 = 500 as_multi_span(bytes, dim<2>(), dim(bytes.size() / 2)); 501 strided_span<const byte, 2> sav2{bytes2, bounds}; 502 CHECK_THROWS_AS(sav2.as_strided_span<int>(), fail_fast); 503 } 504 505 // retype strided array with not enough elements - last dimension does not divide by the new 506 // typesize 507 { 508 strided_bounds<2> bounds{{2, 6}, {4, 1}}; 509 multi_span<const byte, 2, dynamic_range> bytes2 = 510 as_multi_span(bytes, dim<2>(), dim(bytes.size() / 2)); 511 strided_span<const byte, 2> sav2{bytes2, bounds}; 512 CHECK_THROWS_AS(sav2.as_strided_span<int>(), fail_fast); 513 } 514 515 // retype strided array with not enough elements - strides does not divide by the new 516 // typesize 517 { 518 strided_bounds<2> bounds{{2, 1}, {6, 1}}; 519 multi_span<const byte, 2, dynamic_range> bytes2 = 520 as_multi_span(bytes, dim<2>(), dim(bytes.size() / 2)); 521 strided_span<const byte, 2> sav2{bytes2, bounds}; 522 CHECK_THROWS_AS(sav2.as_strided_span<int>(), fail_fast); 523 } 524 525 // retype strided array with irregular strides - from raw data 526 { 527 strided_bounds<1> bounds{bytes.size() / 2, 2}; 528 strided_span<const byte, 1> sav2{bytes.data(), bytes.size(), bounds}; 529 CHECK_THROWS_AS(sav2.as_strided_span<int>(), fail_fast); 530 } 531 532 // retype strided array with irregular strides - from multi_span 533 { 534 strided_bounds<1> bounds{bytes.size() / 2, 2}; 535 strided_span<const byte, 1> sav2{bytes, bounds}; 536 CHECK_THROWS_AS(sav2.as_strided_span<int>(), fail_fast); 537 } 538 } 539 540 TEST_CASE("empty_strided_spans") 541 { 542 { 543 multi_span<int, 0> empty_av(nullptr); 544 strided_span<int, 1> empty_sav{empty_av, {0, 1}}; 545 546 CHECK(empty_sav.bounds().index_bounds() == index<1>{0}); 547 CHECK_THROWS_AS(empty_sav[0], fail_fast); 548 CHECK_THROWS_AS(empty_sav.begin()[0], fail_fast); 549 CHECK_THROWS_AS(empty_sav.cbegin()[0], fail_fast); 550 551 for (const auto& v : empty_sav) { 552 (void) v; 553 CHECK(false); 554 } 555 } 556 557 { 558 strided_span<int, 1> empty_sav{nullptr, 0, {0, 1}}; 559 560 CHECK(empty_sav.bounds().index_bounds() == index<1>{0}); 561 CHECK_THROWS_AS(empty_sav[0], fail_fast); 562 CHECK_THROWS_AS(empty_sav.begin()[0], fail_fast); 563 CHECK_THROWS_AS(empty_sav.cbegin()[0], fail_fast); 564 565 for (const auto& v : empty_sav) { 566 (void) v; 567 CHECK(false); 568 } 569 } 570 } 571 572 void iterate_every_other_element(multi_span<int, dynamic_range> av) 573 { 574 // pick every other element 575 576 auto length = av.size() / 2; 577 #if _MSC_VER > 1800 578 auto bounds = strided_bounds<1>({length}, {2}); 579 #else 580 auto bounds = strided_bounds<1>(index<1>{length}, index<1>{2}); 581 #endif 582 strided_span<int, 1> strided(&av.data()[1], av.size() - 1, bounds); 583 584 CHECK(strided.size() == length); 585 CHECK(strided.bounds().index_bounds()[0] == length); 586 for (auto i = 0; i < strided.size(); ++i) { 587 CHECK(strided[i] == av[2 * i + 1]); 588 } 589 590 int idx = 0; 591 for (auto num : strided) { 592 CHECK(num == av[2 * idx + 1]); 593 idx++; 594 } 595 } 596 597 TEST_CASE("strided_span_section_iteration") 598 { 599 int arr[8] = {4, 0, 5, 1, 6, 2, 7, 3}; 600 601 // static bounds 602 { 603 multi_span<int, 8> av(arr, 8); 604 iterate_every_other_element(av); 605 } 606 607 // dynamic bounds 608 { 609 multi_span<int, dynamic_range> av(arr, 8); 610 iterate_every_other_element(av); 611 } 612 } 613 614 TEST_CASE("dynamic_strided_span_section_iteration") 615 { 616 auto arr = new int[8]; 617 for (int i = 0; i < 4; ++i) { 618 arr[2 * i] = 4 + i; 619 arr[2 * i + 1] = i; 620 } 621 622 auto av = as_multi_span(arr, 8); 623 iterate_every_other_element(av); 624 625 delete[] arr; 626 } 627 628 void iterate_second_slice(multi_span<int, dynamic_range, dynamic_range, dynamic_range> av) 629 { 630 const int expected[6] = {2, 3, 10, 11, 18, 19}; 631 auto section = av.section({0, 1, 0}, {3, 1, 2}); 632 633 for (auto i = 0; i < section.extent<0>(); ++i) { 634 for (auto j = 0; j < section.extent<1>(); ++j) 635 for (auto k = 0; k < section.extent<2>(); ++k) { 636 auto idx = index<3>{i, j, k}; // avoid braces in the CHECK macro 637 CHECK(section[idx] == expected[2 * i + 2 * j + k]); 638 } 639 } 640 641 for (auto i = 0; i < section.extent<0>(); ++i) { 642 for (auto j = 0; j < section.extent<1>(); ++j) 643 for (auto k = 0; k < section.extent<2>(); ++k) 644 CHECK(section[i][j][k] == expected[2 * i + 2 * j + k]); 645 } 646 647 int i = 0; 648 for (const auto num : section) { 649 CHECK(num == expected[i]); 650 i++; 651 } 652 } 653 654 TEST_CASE("strided_span_section_iteration_3d") 655 { 656 int arr[3][4][2]{}; 657 for (auto i = 0; i < 3; ++i) { 658 for (auto j = 0; j < 4; ++j) 659 for (auto k = 0; k < 2; ++k) arr[i][j][k] = 8 * i + 2 * j + k; 660 } 661 662 { 663 multi_span<int, 3, 4, 2> av = arr; 664 iterate_second_slice(av); 665 } 666 } 667 668 TEST_CASE("dynamic_strided_span_section_iteration_3d") 669 { 670 const auto height = 12, width = 2; 671 const auto size = height * width; 672 673 auto arr = new int[static_cast<std::size_t>(size)]; 674 for (auto i = 0; i < size; ++i) { 675 arr[i] = i; 676 } 677 678 { 679 auto av = as_multi_span(as_multi_span(arr, 24), dim<3>(), dim<4>(), dim<2>()); 680 iterate_second_slice(av); 681 } 682 683 { 684 auto av = as_multi_span(as_multi_span(arr, 24), dim(3), dim<4>(), dim<2>()); 685 iterate_second_slice(av); 686 } 687 688 { 689 auto av = as_multi_span(as_multi_span(arr, 24), dim<3>(), dim(4), dim<2>()); 690 iterate_second_slice(av); 691 } 692 693 { 694 auto av = as_multi_span(as_multi_span(arr, 24), dim<3>(), dim<4>(), dim(2)); 695 iterate_second_slice(av); 696 } 697 delete[] arr; 698 } 699 700 TEST_CASE("strided_span_conversion") 701 { 702 // get an multi_span of 'c' values from the list of X's 703 704 struct X 705 { 706 int a; 707 int b; 708 int c; 709 }; 710 711 X arr[4] = {{0, 1, 2}, {3, 4, 5}, {6, 7, 8}, {9, 10, 11}}; 712 713 int s = sizeof(int) / sizeof(byte); 714 auto d2 = 3 * s; 715 auto d1 = narrow_cast<int>(sizeof(int)) * 12 / d2; 716 717 // convert to 4x12 array of bytes 718 auto av = as_multi_span(as_bytes(as_multi_span(arr, 4)), dim(d1), dim(d2)); 719 720 CHECK(av.bounds().index_bounds()[0] == 4); 721 CHECK(av.bounds().index_bounds()[1] == 12); 722 723 // get the last 4 columns 724 auto section = av.section({0, 2 * s}, {4, s}); // { { arr[0].c[0], arr[0].c[1], arr[0].c[2], 725 // arr[0].c[3] } , { arr[1].c[0], ... } , ... 726 // } 727 728 // convert to array 4x1 array of integers 729 auto cs = section.as_strided_span<int>(); // { { arr[0].c }, {arr[1].c } , ... } 730 731 CHECK(cs.bounds().index_bounds()[0] == 4); 732 CHECK(cs.bounds().index_bounds()[1] == 1); 733 734 // transpose to 1x4 array 735 strided_bounds<2> reverse_bounds{ 736 {cs.bounds().index_bounds()[1], cs.bounds().index_bounds()[0]}, 737 {cs.bounds().strides()[1], cs.bounds().strides()[0]}}; 738 739 strided_span<int, 2> transposed{cs.data(), cs.bounds().total_size(), reverse_bounds}; 740 741 // slice to get a one-dimensional array of c's 742 strided_span<int, 1> result = transposed[0]; 743 744 CHECK(result.bounds().index_bounds()[0] == 4); 745 CHECK_THROWS_AS(result.bounds().index_bounds()[1], fail_fast); 746 747 int i = 0; 748 for (auto& num : result) { 749 CHECK(num == arr[i].c); 750 i++; 751 } 752 } 753