1 /*************************************************************************** 2 * Copyright (c) Johan Mabille, Sylvain Corlay and Wolf Vollprecht * 3 * Copyright (c) QuantStack * 4 * * 5 * Distributed under the terms of the BSD 3-Clause License. * 6 * * 7 * The full license is in the file LICENSE, distributed with this software. * 8 ****************************************************************************/ 9 10 #ifndef TEST_COMMON_HPP 11 #define TEST_COMMON_HPP 12 13 #include <sstream> 14 15 #include "xtensor/xlayout.hpp" 16 #include "xtensor/xmanipulation.hpp" 17 #include "xtensor/xreducer.hpp" // tuple_idx_of 18 19 #include "test_common_macros.hpp" 20 21 // the tests used to be implemented with gtest 22 // testing::Types<...> and testing::Test 23 // where introduced to keep compatible 24 // with the gtest test where we can 25 namespace testing 26 { 27 template<class ... ARGS> 28 using Types = std::tuple<ARGS ...>; 29 30 struct Test{}; 31 } 32 33 namespace xt 34 { 35 template<class C> stringify(const C & container)36 std::string stringify(const C & container) 37 { 38 std::size_t i = 0; 39 std::stringstream ss; 40 ss << "["; 41 for(auto && c : container) 42 { 43 if(i + 1 == container.size()) 44 { 45 ss<<c; 46 } 47 else 48 { 49 ss<<c<<","; 50 } 51 ++i; 52 } 53 ss << "]"; 54 return ss.str(); 55 } 56 57 template <class T, class A, class AV> operator ==(const uvector<T,A> & lhs,const std::vector<T,AV> & rhs)58 bool operator==(const uvector<T, A>& lhs, const std::vector<T, AV>& rhs) 59 { 60 return lhs.size() == rhs.size() && std::equal(lhs.begin(), lhs.end(), rhs.begin()); 61 } 62 63 template <class T, class A, class AV> operator ==(const std::vector<T,AV> & lhs,const uvector<T,A> & rhs)64 bool operator==(const std::vector<T, AV>& lhs, const uvector<T, A>& rhs) 65 { 66 return rhs == lhs; 67 } 68 69 template <class C = dynamic_shape<std::size_t>> 70 struct layout_result 71 { 72 using vector_type = uvector<int, XTENSOR_DEFAULT_ALLOCATOR(int)>; 73 using size_type = typename C::value_type; 74 using difference_type = typename C::difference_type; 75 using shape_type = C; 76 using strides_type = get_strides_t<C>; 77 78 using assigner_type = std::vector<std::vector<vector_type>>; 79 layout_resultxt::layout_result80 inline layout_result() 81 { 82 m_shape = {3, 2, 4}; 83 m_assigner.resize(m_shape[0]); 84 for (size_type i = 0; i < m_shape[0]; ++i) 85 { 86 m_assigner[i].resize(m_shape[1]); 87 } 88 m_assigner[0][0] = {-1, 1, 2, 3}; 89 m_assigner[0][1] = {4, 5, 6, 7}; 90 m_assigner[1][0] = {8, 9, 10, 11}; 91 m_assigner[1][1] = {12, 13, 14, 15}; 92 m_assigner[2][0] = {16, 17, 18, 19}; 93 m_assigner[2][1] = {20, 21, 22, 23}; 94 } 95 96 shape_type m_shape; 97 strides_type m_strides; 98 strides_type m_backstrides; 99 vector_type m_data; 100 layout_type m_layout; 101 assigner_type m_assigner; 102 sizext::layout_result103 inline size_type size() const { return m_data.size(); } shapext::layout_result104 inline const shape_type& shape() const { return m_shape; } stridesxt::layout_result105 inline const strides_type& strides() const { return m_strides; } backstridesxt::layout_result106 inline const strides_type& backstrides() const { return m_backstrides; } layoutxt::layout_result107 inline layout_type layout() const { return m_layout; } storagext::layout_result108 inline const vector_type& storage() const { return m_data; } 109 }; 110 111 template <class C = dynamic_shape<std::size_t>> 112 struct row_major_result : layout_result<C> 113 { row_major_resultxt::row_major_result114 inline row_major_result() 115 { 116 this->m_strides = {8, 4, 1}; 117 this->m_backstrides = {16, 4, 3}; 118 this->m_data = {-1, 1, 2, 3, 4, 5, 6, 7, 8, 9, 119 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 120 20, 21, 22, 23}; 121 this->m_layout = layout_type::row_major; 122 } 123 }; 124 125 template <class C = dynamic_shape<std::size_t>> 126 struct column_major_result : layout_result<C> 127 { column_major_resultxt::column_major_result128 inline column_major_result() 129 { 130 this->m_strides = {1, 3, 6}; 131 this->m_backstrides = {2, 3, 18}; 132 this->m_data = {-1, 8, 16, 4, 12, 20, 133 1, 9, 17, 5, 13, 21, 134 2, 10, 18, 6, 14, 22, 135 3, 11, 19, 7, 15, 23}; 136 this->m_layout = layout_type::column_major; 137 } 138 }; 139 140 template <class C = dynamic_shape<std::size_t>> 141 struct central_major_result : layout_result<C> 142 { central_major_resultxt::central_major_result143 inline central_major_result() 144 { 145 this->m_strides = {8, 1, 2}; 146 this->m_backstrides = {16, 1, 6}; 147 this->m_data = {-1, 4, 1, 5, 2, 6, 3, 7, 148 8, 12, 9, 13, 10, 14, 11, 15, 149 16, 20, 17, 21, 18, 22, 19, 23}; 150 this->m_layout = layout_type::dynamic; 151 } 152 }; 153 154 template <class C = dynamic_shape<std::size_t>> 155 struct unit_shape_result 156 { 157 using vector_type = std::vector<int>; 158 using size_type = typename C::value_type; 159 using difference_type = typename C::difference_type; 160 using shape_type = C; 161 using strides_type = get_strides_t<C>; 162 163 using assigner_type = std::vector<std::vector<vector_type>>; 164 unit_shape_resultxt::unit_shape_result165 inline unit_shape_result() 166 { 167 m_shape = {3, 1, 4}; 168 m_strides = {4, 0, 1}; 169 m_backstrides = {8, 0, 3}; 170 m_data = {-1, 1, 2, 3, 8, 9, 10, 11, 16, 17, 18, 19}; 171 m_layout = layout_type::dynamic; 172 m_assigner.resize(m_shape[0]); 173 for (std::size_t i = 0; i < m_shape[0]; ++i) 174 { 175 m_assigner[i].resize(m_shape[1]); 176 } 177 m_assigner[0][0] = {-1, 1, 2, 3}; 178 m_assigner[1][0] = {8, 9, 10, 11}; 179 m_assigner[2][0] = {16, 17, 18, 19}; 180 } 181 182 shape_type m_shape; 183 strides_type m_strides; 184 strides_type m_backstrides; 185 vector_type m_data; 186 layout_type m_layout; 187 assigner_type m_assigner; 188 sizext::unit_shape_result189 inline size_type size() const { return m_data.size(); } shapext::unit_shape_result190 inline const shape_type& shape() const { return m_shape; } stridesxt::unit_shape_result191 inline const strides_type& strides() const { return m_strides; } backstridesxt::unit_shape_result192 inline const strides_type& backstrides() const { return m_backstrides; } layoutxt::unit_shape_result193 inline layout_type layout() const { return m_layout; } storagext::unit_shape_result194 inline const vector_type& storage() const { return m_data; } 195 }; 196 197 template <class V, class R> compare_shape(V & vec,const R & result,bool compare_layout=true)198 void compare_shape(V& vec, const R& result, bool compare_layout = true) 199 { 200 EXPECT_TRUE(std::equal(vec.shape().cbegin(), vec.shape().cend(), result.shape().cbegin())); 201 EXPECT_TRUE(std::equal(vec.strides().cbegin(), vec.strides().cend(), result.strides().cbegin())); 202 EXPECT_TRUE(std::equal(vec.backstrides().cbegin(), vec.backstrides().cend(), result.backstrides().cbegin())); 203 EXPECT_EQ(vec.size(), result.size()); 204 if (compare_layout) 205 { 206 EXPECT_EQ(vec.layout(), result.layout()); 207 } 208 } 209 210 template <class V, class C = dynamic_shape<std::size_t>> test_resize(V & vec)211 void test_resize(V& vec) 212 { 213 { 214 INFO("row_major resize"); 215 row_major_result<C> rm; 216 vec.resize(rm.m_shape, layout_type::row_major); 217 compare_shape(vec, rm); 218 } 219 220 { 221 INFO("different types resize"); 222 row_major_result<C> rm; 223 auto v_copy_a = vec; 224 auto v_copy_b = vec; 225 std::array<std::size_t, 3> ar = {3, 2, 4}; 226 std::vector<std::size_t> vr = {3, 2, 4}; 227 v_copy_a.resize(ar, true); 228 compare_shape(v_copy_a, rm); 229 v_copy_b.resize(vr, true); 230 compare_shape(v_copy_b, rm); 231 } 232 233 { 234 INFO("column_major resize"); 235 column_major_result<C> cm; 236 vec.resize(cm.m_shape, layout_type::column_major); 237 compare_shape(vec, cm); 238 } 239 240 { 241 INFO("central_major resize"); 242 central_major_result<C> cem; 243 vec.resize(cem.m_shape, cem.m_strides); 244 compare_shape(vec, cem); 245 } 246 247 { 248 INFO("unit_shape resize"); 249 unit_shape_result<C> usr; 250 vec.resize(usr.m_shape, layout_type::row_major); 251 compare_shape(vec, usr, false); 252 EXPECT_EQ(vec.layout(), layout_type::row_major); 253 } 254 } 255 256 template <class V, class C = std::vector<std::size_t>> test_reshape(V & vec)257 void test_reshape(V& vec) 258 { 259 { 260 INFO("row_major reshape"); 261 row_major_result<C> rm; 262 auto shape = rm.m_shape; 263 std::size_t sz = compute_size(shape); 264 std::fill(shape.begin(), shape.end(), 1); 265 shape[0] = sz; 266 vec.resize(shape); 267 vec.reshape(rm.m_shape, layout_type::row_major); 268 compare_shape(vec, rm); 269 dynamic_shape<signed long long> signed_shape; 270 std::copy(rm.m_shape.begin(), rm.m_shape.end(), std::back_inserter(signed_shape)); 271 signed_shape[1] = -1; 272 vec.resize(shape); 273 vec.reshape(signed_shape, layout_type::row_major); 274 compare_shape(vec, rm); 275 276 vec.resize(shape); 277 vec.reshape({ 3, -1, 4 }, layout_type::row_major); 278 compare_shape(vec, rm); 279 280 auto & vec_ref = vec.reshape({ 3, -1, 4 }, layout_type::row_major); 281 compare_shape(vec_ref, rm); 282 283 shape = rm.m_shape; 284 shape.front() += 123; 285 XT_EXPECT_THROW(vec_ref.reshape(shape), std::runtime_error); 286 } 287 } 288 289 template <class V> test_throwing_reshape(V & vec)290 void test_throwing_reshape(V& vec) 291 { 292 { 293 INFO("throwing reshape"); 294 vec = xt::arange(6); 295 XT_EXPECT_THROW(vec.reshape({2}), std::runtime_error); 296 } 297 } 298 299 template <class V, class C = std::vector<std::size_t>> test_transpose(V & vec)300 void test_transpose(V& vec) 301 { 302 using shape_type = typename V::shape_type; 303 using strides_type = typename V::strides_type; 304 305 { 306 INFO("transpose"); 307 shape_type shape_new = vec.shape(); 308 auto vt = transpose(vec); 309 std::reverse(shape_new.begin(), shape_new.end()); 310 EXPECT_EQ(vt.shape(), shape_new); 311 } 312 313 { 314 INFO("transpose with data"); 315 row_major_result<C> rm; 316 vec.resize(rm.shape(), layout_type::row_major); 317 318 assign_array(vec, rm.m_assigner); 319 EXPECT_TRUE(std::equal(vec.storage().cbegin(), vec.storage().cend(), rm.m_data.cbegin())); 320 321 auto vec_copy = vec; 322 323 shape_type shape_new(rm.shape()); 324 auto vt = transpose(vec); 325 std::reverse(shape_new.begin(), shape_new.end()); 326 EXPECT_EQ(vt.shape(), shape_new); 327 EXPECT_TRUE(std::equal(vt.storage().cbegin(), vt.storage().cend(), rm.m_data.cbegin())); 328 329 strides_type new_strides = {rm.m_strides[2], 330 rm.m_strides[1], 331 rm.m_strides[0]}; 332 EXPECT_EQ(vt.strides(), new_strides); 333 334 strides_type new_backstrides = {rm.m_backstrides[2], 335 rm.m_backstrides[1], 336 rm.m_backstrides[0]}; 337 EXPECT_EQ(vt.backstrides(), new_backstrides); 338 339 EXPECT_EQ(vec_copy(0, 0, 0), vt(0, 0, 0)); 340 EXPECT_EQ(vec_copy(0, 1, 0), vt(0, 1, 0)); 341 EXPECT_EQ(vec_copy(1, 1, 0), vt(0, 1, 1)); 342 EXPECT_EQ(vec_copy(1, 1, 2), vt(2, 1, 1)); 343 } 344 345 { 346 INFO("transpose with permutation"); 347 row_major_result<C> rm; 348 vec.resize(rm.shape(), layout_type::row_major); 349 350 assign_array(vec, rm.m_assigner); 351 EXPECT_TRUE(std::equal(vec.storage().cbegin(), vec.storage().cend(), rm.m_data.cbegin())); 352 353 auto vec_copy = vec; 354 355 shape_type a = vec.shape(); 356 auto vt = transpose(vec, {1, 0, 2}); 357 shape_type shape_new = {a[1], a[0], a[2]}; 358 EXPECT_TRUE(std::equal(vt.shape().cbegin(), vt.shape().cend(), shape_new.begin())); 359 EXPECT_TRUE(std::equal(vt.storage().cbegin(), vt.storage().cend(), rm.m_data.cbegin())); 360 361 strides_type new_strides = {rm.m_strides[1], 362 rm.m_strides[0], 363 rm.m_strides[2]}; 364 EXPECT_EQ(vt.strides(), new_strides); 365 366 strides_type new_backstrides = {rm.m_backstrides[1], 367 rm.m_backstrides[0], 368 rm.m_backstrides[2]}; 369 EXPECT_EQ(vt.backstrides(), new_backstrides); 370 371 EXPECT_EQ(vec_copy(0, 0, 0), vt(0, 0, 0)); 372 EXPECT_EQ(vec_copy(0, 1, 0), vt(1, 0, 0)); 373 EXPECT_EQ(vec_copy(1, 1, 0), vt(1, 1, 0)); 374 EXPECT_EQ(vec_copy(1, 1, 2), vt(1, 1, 2)); 375 376 // Compilation check only 377 std::vector<std::size_t> perm = {1, 0, 2}; 378 transpose(vec, perm); 379 } 380 381 { 382 INFO("transpose permutation throws"); 383 row_major_result<C> rm; 384 vec.reshape(rm.shape(), layout_type::row_major); 385 386 XT_EXPECT_THROW(transpose(vec, {1, 1, 0}, check_policy::full()), transpose_error); 387 XT_EXPECT_THROW(transpose(vec, {1, 0, 2, 3}, check_policy::full()), transpose_error); 388 XT_EXPECT_THROW(transpose(vec, {1, 2}, check_policy::full()), transpose_error); 389 XT_EXPECT_THROW(transpose(vec, {3, 0, 1}, check_policy::full()), transpose_error); 390 } 391 } 392 393 template <class V1, class V2> assign_array(V1 & dst,const V2 & src)394 void assign_array(V1& dst, const V2& src) 395 { 396 for (std::size_t i = 0; i < dst.shape()[0]; ++i) 397 { 398 for (std::size_t j = 0; j < dst.shape()[1]; ++j) 399 { 400 for (std::size_t k = 0; k < dst.shape()[2]; ++k) 401 { 402 dst(i, j, k) = src[i][j][k]; 403 } 404 } 405 } 406 } 407 408 template <class V1, class V2> safe_assign_array(V1 & dst,const V2 & src)409 void safe_assign_array(V1& dst, const V2& src) 410 { 411 for (std::size_t i = 0; i < dst.shape()[0]; ++i) 412 { 413 for (std::size_t j = 0; j < dst.shape()[1]; ++j) 414 { 415 for (std::size_t k = 0; k < dst.shape()[2]; ++k) 416 { 417 dst.at(i, j, k) = src[i][j][k]; 418 } 419 } 420 } 421 } 422 template <class V> test_bound_check(V & vec)423 void test_bound_check(V& vec) 424 { 425 #if XTENSOR_ENABLE_ASSERT 426 XT_EXPECT_ANY_THROW(vec(10, 10, 10)); 427 #else 428 (void)vec; 429 #endif 430 } 431 432 template <class V> test_access_check(V & vec)433 void test_access_check(V& vec) 434 { 435 XT_EXPECT_ANY_THROW(vec.at(10, 10, 10)); 436 XT_EXPECT_ANY_THROW(vec.at(0, 0, 0, 0, 0, 0)); 437 } 438 439 template <class V, class C = dynamic_shape<std::size_t>> test_access(V & vec)440 void test_access(V& vec) 441 { 442 { 443 INFO("row_major access"); 444 row_major_result<C> rm; 445 vec.resize(rm.m_shape, layout_type::row_major); 446 assign_array(vec, rm.m_assigner); 447 EXPECT_TRUE(std::equal(vec.storage().cbegin(), vec.storage().cend(), rm.m_data.cbegin())); 448 EXPECT_EQ(vec(0, 1, 1), vec(1, 1)); 449 EXPECT_EQ(vec(2, 1, 3), vec(2, 2, 2, 1, 3)); 450 test_bound_check(vec); 451 } 452 453 { 454 INFO("column_major access"); 455 column_major_result<C> cm; 456 vec.resize(cm.m_shape, layout_type::column_major); 457 assign_array(vec, cm.m_assigner); 458 EXPECT_TRUE(std::equal(vec.storage().cbegin(), vec.storage().cend(), cm.m_data.cbegin())); 459 EXPECT_EQ(vec(0, 1, 1), vec(1, 1)); 460 EXPECT_EQ(vec(2, 1, 3), vec(2, 2, 2, 1, 3)); 461 test_bound_check(vec); 462 } 463 464 { 465 INFO("central_major access"); 466 central_major_result<C> cem; 467 vec.resize(cem.m_shape, cem.m_strides); 468 assign_array(vec, cem.m_assigner); 469 EXPECT_TRUE(std::equal(vec.storage().cbegin(), vec.storage().cend(), cem.m_data.cbegin())); 470 EXPECT_EQ(vec(0, 1, 1), vec(1, 1)); 471 EXPECT_EQ(vec(2, 1, 3), vec(2, 2, 2, 1, 3)); 472 test_bound_check(vec); 473 } 474 475 { 476 INFO("unit_shape access"); 477 unit_shape_result<C> usr; 478 vec.resize(usr.m_shape, layout_type::row_major); 479 assign_array(vec, usr.m_assigner); 480 EXPECT_TRUE(std::equal(vec.storage().cbegin(), vec.storage().cend(), usr.m_data.cbegin())); 481 EXPECT_EQ(vec(0, 1, 0), vec(1, 0)); 482 EXPECT_EQ(vec(2, 0, 3), vec(2, 2, 2, 0, 3)); 483 test_bound_check(vec); 484 } 485 } 486 487 template <class V, class C = dynamic_shape<std::size_t>> test_unchecked(V & vec)488 void test_unchecked(V& vec) 489 { 490 { 491 INFO("row_major access"); 492 row_major_result<C> rm; 493 vec.resize(rm.m_shape, layout_type::row_major); 494 assign_array(vec, rm.m_assigner); 495 EXPECT_TRUE(std::equal(vec.storage().cbegin(), vec.storage().cend(), rm.m_data.cbegin())); 496 EXPECT_EQ(vec.unchecked(0, 1, 1), vec(0, 1, 1)); 497 } 498 499 { 500 INFO("column_major access"); 501 column_major_result<C> cm; 502 vec.resize(cm.m_shape, layout_type::column_major); 503 assign_array(vec, cm.m_assigner); 504 EXPECT_TRUE(std::equal(vec.storage().cbegin(), vec.storage().cend(), cm.m_data.cbegin())); 505 EXPECT_EQ(vec.unchecked(0, 1, 1), vec(0, 1, 1)); 506 } 507 508 { 509 INFO("central_major access"); 510 central_major_result<C> cem; 511 vec.resize(cem.m_shape, cem.m_strides); 512 assign_array(vec, cem.m_assigner); 513 EXPECT_TRUE(std::equal(vec.storage().cbegin(), vec.storage().cend(), cem.m_data.cbegin())); 514 EXPECT_EQ(vec.unchecked(0, 1, 1), vec(0, 1, 1)); 515 } 516 517 { 518 INFO("unit_shape access"); 519 unit_shape_result<C> usr; 520 vec.resize(usr.m_shape, layout_type::row_major); 521 assign_array(vec, usr.m_assigner); 522 EXPECT_TRUE(std::equal(vec.storage().cbegin(), vec.storage().cend(), usr.m_data.cbegin())); 523 EXPECT_EQ(vec.unchecked(0, 1, 0), vec(0, 1, 0)); 524 } 525 } 526 527 template <class V, class C = dynamic_shape<std::size_t>> test_at(V & vec)528 void test_at(V& vec) 529 { 530 { 531 INFO("row_major access"); 532 row_major_result<C> rm; 533 vec.resize(rm.m_shape, layout_type::row_major); 534 safe_assign_array(vec, rm.m_assigner); 535 EXPECT_TRUE(std::equal(vec.storage().cbegin(), vec.storage().cend(), rm.m_data.cbegin())); 536 test_access_check(vec); 537 } 538 539 { 540 INFO("column_major access"); 541 column_major_result<C> cm; 542 vec.resize(cm.m_shape, layout_type::column_major); 543 safe_assign_array(vec, cm.m_assigner); 544 EXPECT_TRUE(std::equal(vec.storage().cbegin(), vec.storage().cend(), cm.m_data.cbegin())); 545 test_access_check(vec); 546 } 547 548 { 549 INFO("central_major access"); 550 central_major_result<C> cem; 551 vec.resize(cem.m_shape, cem.m_strides); 552 safe_assign_array(vec, cem.m_assigner); 553 EXPECT_TRUE(std::equal(vec.storage().cbegin(), vec.storage().cend(), cem.m_data.cbegin())); 554 test_access_check(vec); 555 } 556 557 { 558 INFO("unit_shape access"); 559 unit_shape_result<C> usr; 560 vec.resize(usr.m_shape, layout_type::row_major); 561 safe_assign_array(vec, usr.m_assigner); 562 EXPECT_TRUE(std::equal(vec.storage().cbegin(), vec.storage().cend(), usr.m_data.cbegin())); 563 test_access_check(vec); 564 } 565 } 566 567 template <class V, class C = dynamic_shape<std::size_t>> test_element(V & vec)568 void test_element(V& vec) 569 { 570 { 571 INFO("row_major access"); 572 row_major_result<C> rm; 573 vec.resize(rm.m_shape, layout_type::row_major); 574 assign_array(vec, rm.m_assigner); 575 EXPECT_EQ(vec.storage(), rm.m_data); 576 std::vector<std::size_t> index1 = {0, 1, 1}; 577 std::vector<std::size_t> index2 = {1, 1}; 578 std::vector<std::size_t> index3 = {2, 1, 3}; 579 std::vector<std::size_t> index4 = {2, 2, 2, 1, 3}; 580 EXPECT_EQ(vec.element(index1.begin(), index1.end()), vec.element(index2.begin(), index2.end())); 581 EXPECT_EQ(vec.element(index3.begin(), index3.end()), vec.element(index4.begin(), index4.end())); 582 test_bound_check(vec); 583 } 584 585 { 586 INFO("column_major access"); 587 column_major_result<C> cm; 588 vec.resize(cm.m_shape, layout_type::column_major); 589 assign_array(vec, cm.m_assigner); 590 EXPECT_EQ(vec.storage(), cm.m_data); 591 std::vector<std::size_t> index1 = {0, 1, 1}; 592 std::vector<std::size_t> index2 = {1, 1}; 593 std::vector<std::size_t> index3 = {2, 1, 3}; 594 std::vector<std::size_t> index4 = {2, 2, 2, 1, 3}; 595 EXPECT_EQ(vec.element(index1.begin(), index1.end()), vec.element(index2.begin(), index2.end())); 596 EXPECT_EQ(vec.element(index3.begin(), index3.end()), vec.element(index4.begin(), index4.end())); 597 test_bound_check(vec); 598 } 599 600 { 601 INFO("central_major access"); 602 central_major_result<C> cem; 603 vec.resize(cem.m_shape, cem.m_strides); 604 assign_array(vec, cem.m_assigner); 605 EXPECT_EQ(vec.storage(), cem.m_data); 606 std::vector<std::size_t> index1 = {0, 1, 1}; 607 std::vector<std::size_t> index2 = {1, 1}; 608 std::vector<std::size_t> index3 = {2, 1, 3}; 609 std::vector<std::size_t> index4 = {2, 2, 2, 1, 3}; 610 EXPECT_EQ(vec.element(index1.begin(), index1.end()), vec.element(index2.begin(), index2.end())); 611 EXPECT_EQ(vec.element(index3.begin(), index3.end()), vec.element(index4.begin(), index4.end())); 612 test_bound_check(vec); 613 } 614 615 { 616 INFO("unit_shape access"); 617 unit_shape_result<C> usr; 618 vec.resize(usr.m_shape, layout_type::row_major); 619 assign_array(vec, usr.m_assigner); 620 EXPECT_EQ(vec.storage(), usr.m_data); 621 std::vector<std::size_t> index1 = {0, 1, 0}; 622 std::vector<std::size_t> index2 = {1, 0}; 623 std::vector<std::size_t> index3 = {2, 0, 3}; 624 std::vector<std::size_t> index4 = {2, 2, 2, 0, 3}; 625 EXPECT_EQ(vec.element(index1.begin(), index1.end()), vec.element(index2.begin(), index2.end())); 626 EXPECT_EQ(vec.element(index3.begin(), index3.end()), vec.element(index4.begin(), index4.end())); 627 test_bound_check(vec); 628 } 629 } 630 631 template <class V1, class V2> indexed_assign_array(V1 & dst,const V2 & src)632 void indexed_assign_array(V1& dst, const V2& src) 633 { 634 xindex index(dst.dimension()); 635 for (std::size_t i = 0; i < dst.shape()[0]; ++i) 636 { 637 index[0] = i; 638 for (std::size_t j = 0; j < dst.shape()[1]; ++j) 639 { 640 index[1] = j; 641 for (std::size_t k = 0; k < dst.shape()[2]; ++k) 642 { 643 index[2] = k; 644 dst[index] = src[i][j][k]; 645 } 646 } 647 } 648 } 649 650 template <class V, class C = dynamic_shape<std::size_t>> test_indexed_access(V & vec)651 void test_indexed_access(V& vec) 652 { 653 xindex index1 = {1, 1}; 654 xindex index2 = {2, 2, 2, 1, 3}; 655 { 656 INFO("row_major access"); 657 row_major_result<C> rm; 658 vec.resize(rm.m_shape, layout_type::row_major); 659 indexed_assign_array(vec, rm.m_assigner); 660 EXPECT_TRUE(std::equal(vec.storage().cbegin(), vec.storage().cend(), rm.m_data.cbegin())); 661 EXPECT_EQ(vec(0, 1, 1), vec[index1]); 662 EXPECT_EQ(vec(0, 1, 1), (vec[{1, 1}])); 663 EXPECT_EQ(vec(2, 1, 3), vec[index2]); 664 EXPECT_EQ(vec(2, 1, 3), (vec[{2, 2, 2, 1, 3}])); 665 } 666 667 { 668 INFO("column_major access"); 669 column_major_result<C> cm; 670 vec.resize(cm.m_shape, layout_type::column_major); 671 indexed_assign_array(vec, cm.m_assigner); 672 EXPECT_TRUE(std::equal(vec.storage().cbegin(), vec.storage().cend(), cm.m_data.cbegin())); 673 EXPECT_EQ(vec(0, 1, 1), vec[index1]); 674 EXPECT_EQ(vec(0, 1, 1), (vec[{1, 1}])); 675 EXPECT_EQ(vec(2, 1, 3), vec[index2]); 676 EXPECT_EQ(vec(2, 1, 3), (vec[{2, 2, 2, 1, 3}])); 677 } 678 679 { 680 INFO("central_major access"); 681 central_major_result<C> cem; 682 vec.resize(cem.m_shape, cem.m_strides); 683 indexed_assign_array(vec, cem.m_assigner); 684 EXPECT_TRUE(std::equal(vec.storage().cbegin(), vec.storage().cend(), cem.m_data.cbegin())); 685 EXPECT_EQ(vec(0, 1, 1), vec[index1]); 686 EXPECT_EQ(vec(0, 1, 1), (vec[{1, 1}])); 687 EXPECT_EQ(vec(2, 1, 3), vec[index2]); 688 EXPECT_EQ(vec(2, 1, 3), (vec[{2, 2, 2, 1, 3}])); 689 } 690 691 { 692 INFO("unit_shape access"); 693 unit_shape_result<C> usr; 694 vec.resize(usr.m_shape, layout_type::row_major); 695 indexed_assign_array(vec, usr.m_assigner); 696 EXPECT_TRUE(std::equal(vec.storage().cbegin(), vec.storage().cend(), usr.m_data.cbegin())); 697 xindex id1 = {1, 0}; 698 xindex id2 = {2, 2, 2, 0, 3}; 699 EXPECT_EQ(vec(0, 1, 0), vec[id1]); 700 EXPECT_EQ(vec(0, 1, 0), (vec[{1, 0}])); 701 EXPECT_EQ(vec(2, 0, 3), vec[id2]); 702 EXPECT_EQ(vec(2, 0, 3), (vec[{2, 2, 2, 0, 3}])); 703 } 704 } 705 706 template <class V> test_broadcast(V & vec)707 void test_broadcast(V& vec) 708 { 709 using shape_type = typename V::shape_type; 710 711 shape_type s = {3, 1, 4, 2}; 712 vec.resize(s); 713 714 { 715 INFO("same shape"); 716 shape_type s1 = s; 717 bool res = vec.broadcast_shape(s1); 718 EXPECT_EQ(s1, s); 719 EXPECT_TRUE(res); 720 } 721 722 { 723 INFO("different shape"); 724 shape_type s2 = {3, 5, 1, 2}; 725 shape_type s2r = {3, 5, 4, 2}; 726 bool res = vec.broadcast_shape(s2); 727 EXPECT_EQ(s2, s2r); 728 EXPECT_FALSE(res); 729 } 730 731 { 732 INFO("incompatible shapes"); 733 shape_type s4 = {2, 1, 3, 2}; 734 XT_EXPECT_THROW(vec.broadcast_shape(s4), broadcast_error); 735 } 736 } 737 738 template <class V> test_broadcast2(V & vec)739 void test_broadcast2(V& vec) 740 { 741 using shape_type = typename V::shape_type; 742 743 shape_type s = {3, 1, 4, 2}; 744 vec.resize(s); 745 746 { 747 INFO("different dimensions"); 748 shape_type s3 = {5, 3, 1, 4, 2}; 749 shape_type s3r = s3; 750 bool res = vec.broadcast_shape(s3); 751 EXPECT_EQ(s3, s3r); 752 EXPECT_FALSE(res); 753 } 754 } 755 756 template <class VRM, class VCM, class C = dynamic_shape<std::size_t>> test_iterator(VRM & vecrm,VCM & veccm)757 void test_iterator(VRM& vecrm, VCM& veccm) 758 { 759 { 760 INFO("row_major storage iterator"); 761 row_major_result<C> rm; 762 vecrm.resize(rm.m_shape, layout_type::row_major); 763 std::copy(rm.storage().cbegin(), rm.storage().cend(), vecrm.template begin<layout_type::row_major>()); 764 EXPECT_TRUE(std::equal(rm.storage().cbegin(), rm.storage().cend(), vecrm.storage().cbegin())); 765 EXPECT_EQ(vecrm.template end<layout_type::row_major>(), vecrm.storage().end()); 766 } 767 768 { 769 INFO("column_major storage iterator"); 770 column_major_result<C> cm; 771 veccm.resize(cm.m_shape, layout_type::column_major); 772 std::copy(cm.storage().cbegin(), cm.storage().cend(), veccm.template begin<layout_type::column_major>()); 773 EXPECT_TRUE(std::equal(cm.storage().cbegin(), cm.storage().cend(), veccm.storage().cbegin())); 774 EXPECT_EQ(veccm.template end<layout_type::column_major>(), veccm.storage().end()); 775 } 776 } 777 778 template <class V> test_fill(V & vec)779 void test_fill(V& vec) 780 { 781 using value_type = typename V::value_type; 782 vec.resize({ 3, 4 }); 783 value_type v(4); 784 vec.fill(v); 785 for (auto it = vec.cbegin(); it != vec.cend(); ++it) 786 { 787 EXPECT_EQ(*it, v); 788 } 789 } 790 791 template <class V, class C = dynamic_shape<std::size_t>> test_xiterator(V & vec)792 void test_xiterator(V& vec) 793 { 794 row_major_result<C> rm; 795 vec.resize(rm.m_shape, layout_type::row_major); 796 indexed_assign_array(vec, rm.m_assigner); 797 size_t nb_iter = vec.size() / 2; 798 using shape_type = std::vector<size_t>; 799 800 { 801 INFO("broadcast_iterator"); 802 auto iter = vec.template begin<layout_type::row_major>(); 803 auto iter_end = vec.template end<layout_type::row_major>(); 804 for (size_t i = 0; i < nb_iter; ++i) 805 { 806 ++iter; 807 } 808 EXPECT_EQ(vec.storage()[nb_iter], *iter); 809 for (size_t i = 0; i < nb_iter; ++i) 810 { 811 ++iter; 812 } 813 EXPECT_EQ(iter, iter_end); 814 } 815 816 { 817 INFO("shaped_xiterator"); 818 shape_type shape(rm.m_shape.size() + 1); 819 std::copy(rm.m_shape.begin(), rm.m_shape.end(), shape.begin() + 1); 820 shape[0] = 2; 821 auto iter = vec.template begin<layout_type::row_major>(shape); 822 auto iter_end = vec.template end<layout_type::row_major>(shape); 823 for (size_t i = 0; i < 2 * nb_iter; ++i) 824 { 825 ++iter; 826 } 827 EXPECT_EQ(vec.storage()[0], *iter); 828 for (size_t i = 0; i < 2 * nb_iter; ++i) 829 { 830 ++iter; 831 } 832 EXPECT_EQ(iter, iter_end); 833 } 834 835 { 836 INFO("column broadcast_iterator"); 837 auto iter = vec.template begin<layout_type::column_major>(); 838 auto iter_end = vec.template end<layout_type::column_major>(); 839 for (size_t i = 0; i < nb_iter; ++i) 840 { 841 ++iter; 842 } 843 EXPECT_EQ(vec(0, 0, 2), *iter); 844 for (size_t i = 0; i < nb_iter; ++i) 845 { 846 ++iter; 847 } 848 EXPECT_EQ(iter, iter_end); 849 } 850 851 { 852 INFO("column shaped_xiterator"); 853 shape_type shape(rm.m_shape.size() + 1); 854 std::copy(rm.m_shape.begin(), rm.m_shape.end(), shape.begin() + 1); 855 shape[0] = 2; 856 auto iter = vec.template begin<layout_type::column_major>(shape); 857 auto iter_end = vec.template end<layout_type::column_major>(shape); 858 for (size_t i = 0; i < 2 * nb_iter; ++i) 859 { 860 ++iter; 861 } 862 EXPECT_EQ(vec(0, 0, 2), *iter); 863 for (size_t i = 0; i < 2 * nb_iter; ++i) 864 { 865 ++iter; 866 } 867 EXPECT_EQ(iter, iter_end); 868 } 869 } 870 871 template <class V, class C = dynamic_shape<std::size_t>> test_reverse_xiterator(V & vec)872 void test_reverse_xiterator(V& vec) 873 { 874 row_major_result<C> rm; 875 vec.resize(rm.m_shape, layout_type::row_major); 876 indexed_assign_array(vec, rm.m_assigner); 877 size_t nb_iter = vec.size() / 2; 878 879 { 880 INFO("broadcast_iterator"); 881 auto iter = vec.template rbegin<layout_type::row_major>(); 882 auto iter_end = vec.template rend<layout_type::row_major>(); 883 for (size_t i = 0; i < nb_iter; ++i) 884 { 885 ++iter; 886 } 887 EXPECT_EQ(vec.storage()[nb_iter - 1], *iter); 888 for (size_t i = 0; i < nb_iter; ++i) 889 { 890 ++iter; 891 } 892 EXPECT_EQ(iter, iter_end); 893 } 894 895 { 896 INFO("shaped_xiterator"); 897 using shape_type = std::vector<size_t>; 898 shape_type shape(rm.m_shape.size() + 1); 899 std::copy(rm.m_shape.begin(), rm.m_shape.end(), shape.begin() + 1); 900 shape[0] = 2; 901 auto iter = vec.template rbegin<layout_type::row_major>(shape); 902 auto iter_end = vec.template rend<layout_type::row_major>(shape); 903 for (size_t i = 0; i < 2 * nb_iter; ++i) 904 { 905 ++iter; 906 } 907 EXPECT_EQ(vec.storage()[2 * nb_iter - 1], *iter); 908 for (size_t i = 0; i < 2 * nb_iter; ++i) 909 { 910 ++iter; 911 } 912 EXPECT_EQ(iter, iter_end); 913 } 914 } 915 916 // C: container type (xarray<int>, xtensor<int>) 917 // SIT: storage iterator (int*, std::vector<int>::iterator) 918 // SCIT: storage const iterator (const int*, std::vector<int>::const_iterator) 919 template <class C, class SIT, class SCIT> test_iterator_types()920 void test_iterator_types() 921 { 922 using stepper = xstepper<C>; 923 using const_stepper = xstepper<const C>; 924 using shape_type = typename C::shape_type; 925 926 using rm_layout_iterator = typename C::template layout_iterator<layout_type::row_major>; 927 using rm_const_layout_iterator = typename C::template const_layout_iterator<layout_type::row_major>; 928 using rm_reverse_layout_iterator = typename C::template reverse_layout_iterator<layout_type::row_major>; 929 using rm_const_reverse_layout_iterator = typename C::template const_reverse_layout_iterator<layout_type::row_major>; 930 931 using exp_rm_layout_iterator = xiterator<stepper, shape_type*, layout_type::row_major>; 932 using exp_rm_const_layout_iterator = xiterator<const_stepper, shape_type*, layout_type::row_major>; 933 using exp_rm_reverse_layout_iterator = std::reverse_iterator<rm_layout_iterator>; 934 using exp_rm_const_reverse_layout_iterator = std::reverse_iterator<rm_const_layout_iterator>; 935 936 EXPECT_TRUE((std::is_same<rm_layout_iterator, exp_rm_layout_iterator>::value)); 937 EXPECT_TRUE((std::is_same<rm_const_layout_iterator, exp_rm_const_layout_iterator>::value)); 938 EXPECT_TRUE((std::is_same<rm_reverse_layout_iterator, exp_rm_reverse_layout_iterator>::value)); 939 EXPECT_TRUE((std::is_same<rm_const_reverse_layout_iterator, exp_rm_const_reverse_layout_iterator>::value)); 940 941 using cm_layout_iterator = typename C::template layout_iterator<layout_type::column_major>; 942 using cm_const_layout_iterator = typename C::template const_layout_iterator<layout_type::column_major>; 943 using cm_reverse_layout_iterator = typename C::template reverse_layout_iterator<layout_type::column_major>; 944 using cm_const_reverse_layout_iterator = typename C::template const_reverse_layout_iterator<layout_type::column_major>; 945 946 using exp_cm_layout_iterator = xiterator<stepper, shape_type*, layout_type::column_major>; 947 using exp_cm_const_layout_iterator = xiterator<const_stepper, shape_type*, layout_type::column_major>; 948 using exp_cm_reverse_layout_iterator = std::reverse_iterator<cm_layout_iterator>; 949 using exp_cm_const_reverse_layout_iterator = std::reverse_iterator<cm_const_layout_iterator>; 950 951 EXPECT_TRUE((std::is_same<cm_layout_iterator, exp_cm_layout_iterator>::value)); 952 EXPECT_TRUE((std::is_same<cm_const_layout_iterator, exp_cm_const_layout_iterator>::value)); 953 EXPECT_TRUE((std::is_same<cm_reverse_layout_iterator, exp_cm_reverse_layout_iterator>::value)); 954 EXPECT_TRUE((std::is_same<cm_const_reverse_layout_iterator, exp_cm_const_reverse_layout_iterator>::value)); 955 956 using storage_iterator = typename C::storage_iterator; 957 using const_storage_iterator = typename C::const_storage_iterator; 958 using reverse_storage_iterator = typename C::reverse_storage_iterator; 959 using const_reverse_storage_iterator = typename C::const_reverse_storage_iterator; 960 961 using exp_storage_iterator = SIT; 962 using exp_const_storage_iterator = SCIT; 963 using exp_reverse_storage_iterator = std::reverse_iterator<SIT>; 964 using exp_const_reverse_storage_iterator = std::reverse_iterator<SCIT>; 965 966 EXPECT_TRUE((std::is_same<storage_iterator, exp_storage_iterator>::value)); 967 EXPECT_TRUE((std::is_same<const_storage_iterator, exp_const_storage_iterator>::value)); 968 EXPECT_TRUE((std::is_same<reverse_storage_iterator, exp_reverse_storage_iterator>::value)); 969 EXPECT_TRUE((std::is_same<const_reverse_storage_iterator, exp_const_reverse_storage_iterator>::value)); 970 } 971 } 972 973 #endif 974