multi_span_tests.cpp revision a9dcbe04ff330ef8297191d19951d4a313b2115a
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 <array_view.h> 19#include <numeric> 20#include <array> 21#include <string> 22#include <vector> 23#include <list> 24#include <iostream> 25#include <functional> 26#include <algorithm> 27 28 29using namespace std; 30using namespace Guide; 31 32namespace 33{ 34 void use(int&) {} 35 struct BaseClass {}; 36 struct DerivedClass : BaseClass {}; 37} 38 39SUITE(array_view_tests) 40{ 41 TEST(basics) 42 { 43 auto ptr = as_array_view(new int[10], 10); 44 fill(ptr.begin(), ptr.end(), 99); 45 for (int num : ptr) 46 { 47 CHECK(num == 99); 48 } 49 50 delete[] ptr.data(); 51 52 53 static_bounds<size_t, 4, dynamic_range, 2> bounds{ 3 }; 54 55#ifdef CONFIRM_COMPILATION_ERRORS 56 array_view<int, 4, dynamic_range, 2> av(nullptr, bounds); 57 av.extent(); 58 av.extent<2>(); 59 av[8][4][3]; 60#endif 61 } 62 63 TEST (array_view_convertible) 64 { 65#ifdef CONFIRM_COMPILATION_ERRORS 66 array_view<int, 7, 4, 2> av1(nullptr, b1); 67#endif 68 69 auto f = [&]() { array_view<int, 7, 4, 2> av1(nullptr); }; 70 CHECK_THROW(f(), fail_fast); 71 72 array_view<int, 7, dynamic_range, 2> av1(nullptr); 73 74#ifdef CONFIRM_COMPILATION_ERRORS 75 static_bounds<size_t, 7, dynamic_range, 2> b12(b11); 76 b12 = b11; 77 b11 = b12; 78 79 array_view<int, dynamic_range> av1 = nullptr; 80 array_view<int, 7, dynamic_range, 2> av2(av1); 81 array_view<int, 7, 4, 2> av2(av1); 82#endif 83 84 array_view<DerivedClass> avd; 85#ifdef CONFIRM_COMPILATION_ERRORS 86 array_view<BaseClass> avb = avd; 87#endif 88 array_view<const DerivedClass> avcd = avd; 89 } 90 91 TEST(boundary_checks) 92 { 93 int arr[10][2]; 94 auto av = as_array_view(arr); 95 96 fill(begin(av), end(av), 0); 97 98 av[2][0] = 1; 99 av[1][1] = 3; 100 101 // out of bounds 102 CHECK_THROW(av[1][3] = 3, fail_fast); 103 CHECK_THROW((av[{1, 3}] = 3), fail_fast); 104 105 CHECK_THROW(av[10][2], fail_fast); 106 CHECK_THROW((av[{10,2}]), fail_fast); 107 } 108 109 void overloaded_func(array_view<const int, dynamic_range, 3, 5> exp, int expected_value) { 110 for (auto val : exp) 111 { 112 CHECK(val == expected_value); 113 } 114 } 115 116 void overloaded_func(array_view<const char, dynamic_range, 3, 5> exp, char expected_value) { 117 for (auto val : exp) 118 { 119 CHECK(val == expected_value); 120 } 121 } 122 123 void fixed_func(array_view<int, 3, 3, 5> exp, int expected_value) { 124 for (auto val : exp) 125 { 126 CHECK(val == expected_value); 127 } 128 } 129 130 TEST(array_view_parameter_test) 131 { 132 auto data = new int[4][3][5]; 133 134 auto av = as_array_view(data, 4); 135 136 CHECK(av.size() == 60); 137 138 fill(av.begin(), av.end(), 34); 139 140 int count = 0; 141 for_each(av.rbegin(), av.rend(), [&](int val) { count += val; }); 142 CHECK(count == 34 * 60); 143 overloaded_func(av, 34); 144 145 overloaded_func(av.as_array_view(dim<>(4), dim<>(3), dim<>(5)), 34); 146 147 //fixed_func(av, 34); 148 delete[] data; 149 } 150 151 152 TEST(md_access) 153 { 154 unsigned int width = 5, height = 20; 155 156 unsigned int imgSize = width * height; 157 auto image_ptr = new int[imgSize][3]; 158 159 // size check will be done 160 auto image_view = as_array_view(image_ptr, imgSize).as_array_view(dim<>(height), dim<>(width), dim<3>()); 161 162 iota(image_view.begin(), image_view.end(), 1); 163 164 int expected = 0; 165 for (unsigned int i = 0; i < height; i++) 166 { 167 for (unsigned int j = 0; j < width; j++) 168 { 169 CHECK(expected + 1 == image_view[i][j][0]); 170 CHECK(expected + 2 == image_view[i][j][1]); 171 CHECK(expected + 3 == image_view[i][j][2]); 172 173 auto val = image_view[{i, j, 0}]; 174 CHECK(expected + 1 == val); 175 val = image_view[{i, j, 1}]; 176 CHECK(expected + 2 == val); 177 val = image_view[{i, j, 2}]; 178 CHECK(expected + 3 == val); 179 180 expected += 3; 181 } 182 } 183 } 184 185 TEST(array_view_factory_test) 186 { 187 { 188 int * arr = new int[150]; 189 190 auto av = as_array_view(arr, dim<10>(), dim<>(3), dim<5>()); 191 192 fill(av.begin(), av.end(), 24); 193 overloaded_func(av, 24); 194 195 delete[] arr; 196 197 198 array<int, 15> stdarr{ 0 }; 199 auto av2 = as_array_view(stdarr); 200 overloaded_func(av2.as_array_view(dim<>(1), dim<3>(), dim<5>()), 0); 201 202 203 string str = "ttttttttttttttt"; // size = 15 204 auto t = str.data(); 205 auto av3 = as_array_view(str); 206 overloaded_func(av3.as_array_view(dim<>(1), dim<3>(), dim<5>()), 't'); 207 } 208 209 { 210 int a[3][4][5]; 211 auto av = as_array_view(a); 212 const int (*b)[4][5]; 213 b = a; 214 auto bv = as_array_view(b, 3); 215 216 CHECK(av == bv); 217 218 const std::array<double, 3> arr = {0.0, 0.0, 0.0}; 219 auto cv = as_array_view(arr); 220 221 vector<float> vec(3); 222 auto dv = as_array_view(vec); 223 224#ifdef CONFIRM_COMPILATION_ERRORS 225 auto dv2 = as_array_view(std::move(vec)); 226#endif 227 } 228 } 229 230 TEST (array_view_reshape_test) 231 { 232 int a[3][4][5]; 233 auto av = as_array_view(a); 234 auto av2 = av.as_array_view(dim<60>()); 235 auto av3 = av2.as_array_view(dim<3>(), dim<4>(), dim<5>()); 236 auto av4 = av3.as_array_view(dim<4>(), dim<>(3), dim<5>()); 237 auto av5 = av4.as_array_view(dim<3>(), dim<4>(), dim<5>()); 238 auto av6 = av5.as_array_view(dim<12>(), dim<>(5)); 239 240 fill(av6.begin(), av6.end(), 1); 241 242 auto av7 = av6.as_bytes(); 243 244 auto av8 = av7.as_array_view<int>(); 245 246 CHECK(av8.size() == av6.size()); 247 for (size_t i = 0; i < av8.size(); i++) 248 { 249 CHECK(av8[i] == 1); 250 } 251 252#ifdef CONFIRM_COMPILATION_ERRORS 253 struct Foo {char c[11];}; 254 auto av9 = av7.as_array_view<Foo>(); 255#endif 256 } 257 258 259 TEST (array_view_section_test) 260 { 261 int a[30][4][5]; 262 263 auto av = as_array_view(a); 264 auto sub = av.section({15, 0, 0}, Guide::index<3>{2, 2, 2}); 265 auto subsub = sub.section({1, 0, 0}, Guide::index<3>{1, 1, 1}); 266 } 267 268 269 TEST(constructors) 270 { 271 array_view<int, dynamic_range> av(nullptr); 272 CHECK(av.length() == 0); 273 274 array_view<int, dynamic_range> av2; 275 CHECK(av2.length() == 0); 276 277 array_view<int, dynamic_range> av3(nullptr, 0); 278 CHECK(av3.length() == 0); 279 280 // Constructing from a nullptr + length is specifically disallowed 281 auto f = [&]() {array_view<int, dynamic_range> av4(nullptr, 2);}; 282 CHECK_THROW(f(), fail_fast); 283 284 int arr1[2][3]; 285 array_view<int, 2, dynamic_range> av5(arr1); 286 287 array<int, 15> arr2; 288 array_view<int, 15> av6(arr2); 289 290 vector<int> vec1(19); 291 array_view<int> av7(vec1); 292 CHECK(av7.length() == 19); 293 294 295 array_view<int> av8; 296 CHECK(av8.length() == 0); 297 array_view<int> av9(arr2); 298 CHECK(av9.length() == 15); 299 300 301#ifdef CONFIRM_COMPILATION_ERRORS 302 array_view<int, 4> av10; 303 DerivedClass *p = nullptr; 304 array_view<BaseClass> av11(p, 0); 305#endif 306 307 308 } 309 310 TEST(copyandassignment) 311 { 312 array_view<int, dynamic_range> av1; 313 314 int arr[] = {3, 4, 5}; 315 av1 = arr; 316 array_view<array_view_options<const int, unsigned char>, dynamic_range> av2; 317 av2 = av1; 318 } 319 320 TEST(array_view_first) 321 { 322 int arr[5] = { 1, 2, 3, 4, 5 }; 323 324 { 325 array_view<int, 5> av = arr; 326 CHECK((av.first<2>().bounds() == static_bounds<size_t, 2>())); 327 CHECK(av.first<2>().length() == 2); 328 CHECK(av.first(2).length() == 2); 329 } 330 331 { 332 array_view<int, 5> av = arr; 333 CHECK((av.first<0>().bounds() == static_bounds<size_t, 0>())); 334 CHECK(av.first<0>().length() == 0); 335 CHECK(av.first(0).length() == 0); 336 } 337 338 { 339 array_view<int, 5> av = arr; 340 CHECK((av.first<5>().bounds() == static_bounds<size_t, 5>())); 341 CHECK(av.first<5>().length() == 5); 342 CHECK(av.first(5).length() == 5); 343 } 344 345 { 346 array_view<int, 5> av = arr; 347#ifdef CONFIRM_COMPILATION_ERRORS 348 CHECK(av.first<6>().bounds() == static_bounds<size_t, 6>()); 349 CHECK(av.first<6>().length() == 6); 350#endif 351 CHECK_THROW(av.first(6).length(), fail_fast); 352 } 353 354 { 355 array_view<int, dynamic_range> av; 356 CHECK((av.first<0>().bounds() == static_bounds<size_t, 0>())); 357 CHECK(av.first<0>().length() == 0); 358 CHECK(av.first(0).length() == 0); 359 } 360 } 361 362 TEST(array_view_last) 363 { 364 int arr[5] = { 1, 2, 3, 4, 5 }; 365 366 { 367 array_view<int, 5> av = arr; 368 CHECK((av.last<2>().bounds() == static_bounds<size_t, 2>())); 369 CHECK(av.last<2>().length() == 2); 370 CHECK(av.last(2).length() == 2); 371 } 372 373 { 374 array_view<int, 5> av = arr; 375 CHECK((av.last<0>().bounds() == static_bounds<size_t, 0>())); 376 CHECK(av.last<0>().length() == 0); 377 CHECK(av.last(0).length() == 0); 378 } 379 380 { 381 array_view<int, 5> av = arr; 382 CHECK((av.last<5>().bounds() == static_bounds<size_t, 5>())); 383 CHECK(av.last<5>().length() == 5); 384 CHECK(av.last(5).length() == 5); 385 } 386 387 388 { 389 array_view<int, 5> av = arr; 390#ifdef CONFIRM_COMPILATION_ERRORS 391 CHECK((av.last<6>().bounds() == static_bounds<size_t, 6>())); 392 CHECK(av.last<6>().length() == 6); 393#endif 394 CHECK_THROW(av.last(6).length(), fail_fast); 395 } 396 397 { 398 array_view<int, dynamic_range> av; 399 CHECK((av.last<0>().bounds() == static_bounds<size_t, 0>())); 400 CHECK(av.last<0>().length() == 0); 401 CHECK(av.last(0).length() == 0); 402 } 403 } 404 405 TEST(custmized_array_view_size) 406 { 407 double (*arr)[3][4] = new double[100][3][4]; 408 array_view<array_view_options<double, char>, dynamic_range, 3, 4> av1(arr, (char)10); 409 410 struct EffectiveStructure 411 { 412 double* v1; 413 char v2; 414 }; 415 CHECK(sizeof(av1) == sizeof(EffectiveStructure)); 416 417 CHECK_THROW(av1[10][3][4], fail_fast); 418 419 array_view<const double, dynamic_range, 6, 4> av2 = av1.as_array_view(dim<>(5), dim<6>(), dim<4>()); 420 421 } 422 423 TEST(array_view_sub) 424 { 425 int arr[5] = { 1, 2, 3, 4, 5 }; 426 427 { 428 array_view<int, 5> av = arr; 429 CHECK((av.sub<2,2>().bounds() == static_bounds<size_t, 2>())); 430 CHECK((av.sub<2,2>().length() == 2)); 431 CHECK(av.sub(2,2).length() == 2); 432 } 433 434 435 { 436 array_view<int, 5> av = arr; 437 CHECK((av.sub<0,0>().bounds() == static_bounds<size_t, 0>())); 438 CHECK((av.sub<0,0>().length() == 0)); 439 CHECK(av.sub(0,0).length() == 0); 440 } 441 442 { 443 array_view<int, 5> av = arr; 444 CHECK((av.sub<0,5>().bounds() == static_bounds<size_t, 5>())); 445 CHECK((av.sub<0,5>().length() == 5)); 446 CHECK(av.sub(0,5).length() == 5); 447 } 448 449 { 450 array_view<int, 5> av = arr; 451#ifdef CONFIRM_COMPILATION_ERRORS 452 CHECK((av.sub<5,0>().bounds() == static_bounds<size_t, 0>())); 453 CHECK((av.sub<5,0>().length() == 0)); 454#endif 455 CHECK_THROW(av.sub(5,0).length(), fail_fast); 456 } 457 458 { 459 array_view<int, dynamic_range> av; 460 CHECK((av.sub<0,0>().bounds() == static_bounds<size_t, 0>())); 461 CHECK((av.sub<0,0>().length() == 0)); 462 CHECK(av.sub(0,0).length() == 0); 463 } 464 } 465 466 void AssertNullEmptyProperties(array_view<int, dynamic_range>& av) 467 { 468 CHECK(av.length() == 0); 469 CHECK(av.data() == nullptr); 470 CHECK(!av); 471 } 472 473 template <class T, class U> 474 void AssertContentsMatch(T a1, U a2) 475 { 476 CHECK(a1.length() == a2.length()); 477 for (size_t i = 0; i < a1.length(); ++i) 478 CHECK(a1[i] == a2[i]); 479 } 480 481 TEST(TestNullConstruction) 482 { 483 array_view<int, dynamic_range> av; 484 AssertNullEmptyProperties(av); 485 486 array_view<int, dynamic_range> av2(nullptr); 487 AssertNullEmptyProperties(av2); 488 } 489 490 TEST(ArrayConstruction) 491 { 492 int a[] = { 1, 2, 3, 4 }; 493 494 array_view<int, dynamic_range> av = { &a[1], 3 }; 495 CHECK(av.length() == 3); 496 497 array_view<int, dynamic_range> av3 = { a, 2 }; 498 CHECK(av3.length() == 2); 499 500 array_view<int, dynamic_range> av2 = a; 501 CHECK(av2.length() == 4); 502 } 503 504 TEST(NonConstConstConversions) 505 { 506 int a[] = { 1, 2, 3, 4 }; 507 508#ifdef CONFIRM_COMPILATION_ERRORS 509 array_view<const int, dynamic_range> cav = a; 510 array_view<int, dynamic_range> av = cav; 511#else 512 array_view<int, dynamic_range> av = a; 513 array_view<const int, dynamic_range> cav = av; 514#endif 515 AssertContentsMatch(av, cav); 516 } 517 518 TEST(FixedSizeConversions) 519 { 520 int arr[] = { 1, 2, 3, 4 }; 521 522 // converting to an array_view from an equal size array is ok 523 array_view<int, 4> av4 = arr; 524 CHECK(av4.length() == 4); 525 526 // converting to dynamic_range a_v is always ok 527 { 528 array_view<int, dynamic_range> av = av4; 529 } 530 { 531 array_view<int, dynamic_range> av = arr; 532 } 533 534 // initialization or assignment to static array_view that REDUCES size is NOT ok 535#ifdef CONFIRM_COMPILATION_ERRORS 536 { 537 array_view<int, 2> av2 = arr; 538 } 539 { 540 array_view<int, 2> av2 = av4; 541 } 542#endif 543 544 { 545 array_view<int, dynamic_range> av = arr; 546 array_view<int, 2> av2 = av; 547 } 548 549#ifdef CONFIRM_COMPILATION_ERRORS 550 { 551 array_view<int, dynamic_range> av = arr; 552 array_view<int, 2, 1> av2 = av.as_array_view(dim<2>(), dim<2>()); 553 } 554#endif 555 556 { 557 array_view<int, dynamic_range> av = arr; 558 auto f = [&]() {array_view<int, 2, 1> av2 = av.as_array_view(dim<>(2), dim<>(2));}; 559 CHECK_THROW(f(), fail_fast); 560 } 561 562 // but doing so explicitly is ok 563 564 // you can convert statically 565 { 566 array_view<int, 2> av2 = {arr, 2}; 567 } 568 { 569 array_view<int, 1> av2 = av4.first<1>(); 570 } 571 572 // ...or dynamically 573 { 574 // NB: implicit conversion to array_view<int,2> from array_view<int,dynamic_range> 575 array_view<int, 1> av2 = av4.first(1); 576 } 577 578 // initialization or assignment to static array_view that requires size INCREASE is not ok. 579 int arr2[2] = { 1, 2 }; 580 581#ifdef CONFIRM_COMPILATION_ERRORS 582 { 583 array_view<int, 4> av4 = arr2; 584 } 585 { 586 array_view<int, 2> av2 = arr2; 587 array_view<int, 4> av4 = av2; 588 } 589#endif 590 { 591 auto f = [&]() {array_view<int, 4> av4 = {arr2, 2};}; 592 CHECK_THROW(f(), fail_fast); 593 } 594 595 // this should fail - we are trying to assign a small dynamic a_v to a fixed_size larger one 596 array_view<int, dynamic_range> av = arr2; 597 auto f = [&](){ array_view<int, 4> av2 = av; }; 598 CHECK_THROW(f(), fail_fast); 599 } 600 601 TEST(AsWriteableBytes) 602 { 603 int a[] = { 1, 2, 3, 4 }; 604 605 { 606#ifdef CONFIRM_COMPILATION_ERRORS 607 // you should not be able to get writeable bytes for const objects 608 array_view<const int, dynamic_range> av = a; 609 auto wav = av.as_writeable_bytes(); 610#endif 611 } 612 613 { 614 array_view<int, dynamic_range> av; 615 auto wav = av.as_writeable_bytes(); 616 CHECK(wav.length() == av.length()); 617 CHECK(wav.length() == 0); 618 CHECK(wav.bytes() == 0); 619 } 620 621 { 622 array_view<int, dynamic_range> av = a; 623 auto wav = av.as_writeable_bytes(); 624 CHECK(wav.data() == (byte*)&a[0]); 625 CHECK(wav.length() == sizeof(a)); 626 } 627 628 } 629 630 631 TEST(ArrayViewComparison) 632 { 633 int arr[10][2]; 634 auto av1 = as_array_view(arr); 635 array_view<const int, dynamic_range, 2> av2 = av1; 636 637 CHECK(av1 == av2); 638 639 array_view<array_view_options<int, char>, 20> av3 = av1.as_array_view(dim<>(20)); 640 CHECK(av3 == av2 && av3 == av1); 641 642 } 643} 644 645int main(int, const char *[]) 646{ 647 return UnitTest::RunAllTests(); 648} 649