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 XTENSOR_FIXED_HPP 11 #define XTENSOR_FIXED_HPP 12 13 #include <algorithm> 14 #include <array> 15 #include <cstddef> 16 #include <utility> 17 #include <vector> 18 19 #include <xtl/xsequence.hpp> 20 21 #include "xcontainer.hpp" 22 #include "xstrides.hpp" 23 #include "xstorage.hpp" 24 #include "xsemantic.hpp" 25 #include "xtensor_config.hpp" 26 27 namespace xtl 28 { 29 namespace detail 30 { 31 template <class T, std::size_t N> 32 struct sequence_builder<xt::const_array<T, N>> 33 { 34 using sequence_type = xt::const_array<T, N>; 35 using value_type = typename sequence_type::value_type; 36 using size_type = typename sequence_type::size_type; 37 makextl::detail::sequence_builder38 inline static sequence_type make(size_type /*size*/, value_type /*v*/) 39 { 40 return sequence_type(); 41 } 42 }; 43 } 44 } 45 46 namespace xt 47 { 48 49 /********************** 50 * xfixed declaration * 51 **********************/ 52 53 template <class ET, class S, layout_type L, bool SH, class Tag> 54 class xfixed_container; 55 56 namespace detail 57 { 58 /************************************************************************************** 59 The following is something we can currently only dream about -- for when we drop 60 support for a lot of the old compilers (e.g. GCC 4.9, MSVC 2017 ;) 61 62 template <class T> 63 constexpr std::size_t calculate_stride(T& shape, std::size_t idx, layout_type L) 64 { 65 if (shape[idx] == 1) 66 { 67 return std::size_t(0); 68 } 69 70 std::size_t data_size = 1; 71 std::size_t stride = 1; 72 if (L == layout_type::row_major) 73 { 74 // because we have a integer sequence that counts 75 // from 0 to sz - 1, we need to "invert" idx here 76 idx = shape.size() - idx; 77 for (std::size_t i = idx; i != 0; --i) 78 { 79 stride = data_size; 80 data_size = stride * shape[i - 1]; 81 } 82 } 83 else 84 { 85 for (std::size_t i = 0; i < idx + 1; ++i) 86 { 87 stride = data_size; 88 data_size = stride * shape[i]; 89 } 90 } 91 return stride; 92 } 93 94 *****************************************************************************************/ 95 96 template <layout_type L, std::size_t I, std::size_t... X> 97 struct calculate_stride; 98 99 template <std::size_t I, std::size_t Y, std::size_t... X> 100 struct calculate_stride<layout_type::column_major, I, Y, X...> 101 { 102 constexpr static std::ptrdiff_t value = Y * calculate_stride<layout_type::column_major, I - 1, X...>::value; 103 }; 104 105 template <std::size_t Y, std::size_t... X> 106 struct calculate_stride<layout_type::column_major, 0, Y, X...> 107 { 108 constexpr static std::ptrdiff_t value = 1; 109 }; 110 111 template <std::size_t I, std::size_t... X> 112 struct calculate_stride_row_major 113 { 114 constexpr static std::ptrdiff_t value = at<sizeof...(X) - I, X...>::value * calculate_stride_row_major<I - 1, X...>::value; 115 }; 116 117 template <std::size_t... X> 118 struct calculate_stride_row_major<0, X...> 119 { 120 constexpr static std::ptrdiff_t value = 1; 121 }; 122 123 template <std::size_t I, std::size_t... X> 124 struct calculate_stride<layout_type::row_major, I, X...> 125 { 126 constexpr static std::ptrdiff_t value = calculate_stride_row_major<sizeof...(X) - I - 1, X...>::value; 127 }; 128 129 namespace workaround 130 { 131 template <layout_type L, size_t I, class SEQ> 132 struct computed_strides; 133 134 template <layout_type L, size_t I, size_t... X> 135 struct computed_strides<L, I, std::index_sequence<X...>> 136 { 137 constexpr static std::ptrdiff_t value = calculate_stride<L, I, X...>::value; 138 }; 139 140 template <layout_type L, size_t I, class SEQ > get_computed_strides(bool cond)141 constexpr std::ptrdiff_t get_computed_strides(bool cond) 142 { 143 return cond ? 0 : computed_strides<L, I, SEQ>::value; 144 } 145 } 146 147 template <layout_type L, class R, std::size_t... X, std::size_t... I> get_strides_impl(const xt::fixed_shape<X...> & shape,std::index_sequence<I...>)148 constexpr R get_strides_impl(const xt::fixed_shape<X...>& shape, std::index_sequence<I...>) 149 { 150 static_assert((L == layout_type::row_major) || (L == layout_type::column_major), 151 "Layout not supported for fixed array"); 152 #if (_MSC_VER >= 1910) 153 using temp_type = std::index_sequence<X...>; 154 return R({ workaround::get_computed_strides<L, I, temp_type>(shape[I] == 1)... }); 155 #else 156 return R({ shape[I] == 1 ? 0 : calculate_stride<L, I, X...>::value... }); 157 #endif 158 } 159 160 template <class S, class T, std::size_t... I> get_backstrides_impl(const S & shape,const T & strides,std::index_sequence<I...>)161 constexpr T get_backstrides_impl(const S& shape, const T& strides, std::index_sequence<I...>) 162 { 163 return T({(strides[I] * std::ptrdiff_t(shape[I] - 1))...}); 164 } 165 166 template <std::size_t... X> 167 struct fixed_compute_size_impl; 168 169 template <std::size_t Y, std::size_t... X> 170 struct fixed_compute_size_impl<Y, X...> 171 { 172 constexpr static std::size_t value = Y * fixed_compute_size_impl<X...>::value; 173 }; 174 175 template <std::size_t X> 176 struct fixed_compute_size_impl<X> 177 { 178 constexpr static std::size_t value = X; 179 }; 180 181 template <> 182 struct fixed_compute_size_impl<> 183 { 184 // support for 0D xtensor fixed (empty shape = xshape<>) 185 constexpr static std::size_t value = 1; 186 }; 187 188 // TODO unify with constexpr compute_size when dropping MSVC 2015 189 template <class T> 190 struct fixed_compute_size; 191 192 template <std::size_t... X> 193 struct fixed_compute_size<xt::fixed_shape<X...>> 194 { 195 constexpr static std::size_t value = fixed_compute_size_impl<X...>::value; 196 }; 197 198 template <class V, std::size_t... X> 199 struct get_init_type_impl; 200 201 template <class V, std::size_t Y> 202 struct get_init_type_impl<V, Y> 203 { 204 using type = V[Y]; 205 }; 206 207 template <class V> 208 struct get_init_type_impl<V> 209 { 210 using type = V[1]; 211 }; 212 213 template <class V, std::size_t Y, std::size_t... X> 214 struct get_init_type_impl<V, Y, X...> 215 { 216 using tmp_type = typename get_init_type_impl<V, X...>::type; 217 using type = tmp_type[Y]; 218 }; 219 } 220 221 template <layout_type L, class R, std::size_t... X> get_strides(const fixed_shape<X...> & shape)222 constexpr R get_strides(const fixed_shape<X...>& shape) noexcept 223 { 224 return detail::get_strides_impl<L, R>(shape, std::make_index_sequence<sizeof...(X)>{}); 225 } 226 227 template <class S, class T> get_backstrides(const S & shape,const T & strides)228 constexpr T get_backstrides(const S& shape, const T& strides) noexcept 229 { 230 return detail::get_backstrides_impl(shape, strides, 231 std::make_index_sequence<std::tuple_size<T>::value>{}); 232 } 233 234 template <class V, class S> 235 struct get_init_type; 236 237 template <class V, std::size_t... X> 238 struct get_init_type<V, fixed_shape<X...>> 239 { 240 using type = typename detail::get_init_type_impl<V, X...>::type; 241 }; 242 243 template <class V, class S> 244 using get_init_type_t = typename get_init_type<V, S>::type; 245 246 template <class ET, class S, layout_type L, bool SH, class Tag> 247 struct xcontainer_inner_types<xfixed_container<ET, S, L, SH, Tag>> 248 { 249 using shape_type = S; 250 using inner_shape_type = typename S::cast_type; 251 using strides_type = get_strides_t<inner_shape_type>; 252 using inner_strides_type = strides_type; 253 using backstrides_type = inner_strides_type; 254 using inner_backstrides_type = backstrides_type; 255 256 // NOTE: 0D (S::size() == 0) results in storage for 1 element (scalar) 257 #if defined(_MSC_VER) && _MSC_VER < 1910 && !defined(_WIN64) 258 // WORKAROUND FOR MSVC 2015 32 bit, fallback to unaligned container for 0D scalar case 259 using storage_type = std::array<ET, detail::fixed_compute_size<S>::value>; 260 #else 261 using storage_type = aligned_array<ET, detail::fixed_compute_size<S>::value>; 262 #endif 263 264 using reference = typename storage_type::reference; 265 using const_reference = typename storage_type::const_reference; 266 using size_type = typename storage_type::size_type; 267 using temporary_type = xfixed_container<ET, S, L, SH, Tag>; 268 static constexpr layout_type layout = L; 269 }; 270 271 template <class ET, class S, layout_type L, bool SH, class Tag> 272 struct xiterable_inner_types<xfixed_container<ET, S, L, SH, Tag>> 273 : xcontainer_iterable_types<xfixed_container<ET, S, L, SH, Tag>> 274 { 275 }; 276 277 /** 278 * @class xfixed_container 279 * @brief Dense multidimensional container with tensor semantic and fixed 280 * dimension. 281 * 282 * The xfixed_container class implements a dense multidimensional container 283 * with tensor semantic and fixed dimension 284 * 285 * @tparam ET The type of the elements. 286 * @tparam S The xshape template paramter of the container. 287 * @tparam L The layout_type of the tensor. 288 * @tparam SH Wether the tensor can be used as a shared expression. 289 * @tparam Tag The expression tag. 290 * @sa xtensor_fixed 291 */ 292 template <class ET, class S, layout_type L, bool SH, class Tag> 293 class xfixed_container : public xcontainer<xfixed_container<ET, S, L, SH, Tag>>, 294 public xcontainer_semantic<xfixed_container<ET, S, L, SH, Tag>> 295 { 296 public: 297 298 using self_type = xfixed_container<ET, S, L, SH, Tag>; 299 using base_type = xcontainer<self_type>; 300 using semantic_base = xcontainer_semantic<self_type>; 301 302 using storage_type = typename base_type::storage_type; 303 using value_type = typename base_type::value_type; 304 using reference = typename base_type::reference; 305 using const_reference = typename base_type::const_reference; 306 using pointer = typename base_type::pointer; 307 using const_pointer = typename base_type::const_pointer; 308 using shape_type = typename base_type::shape_type; 309 using inner_shape_type = typename base_type::inner_shape_type; 310 using strides_type = typename base_type::strides_type; 311 using backstrides_type = typename base_type::backstrides_type; 312 using inner_backstrides_type = typename base_type::inner_backstrides_type; 313 using inner_strides_type = typename base_type::inner_strides_type; 314 using temporary_type = typename semantic_base::temporary_type; 315 using expression_tag = Tag; 316 317 constexpr static std::size_t N = std::tuple_size<shape_type>::value; 318 constexpr static std::size_t rank = N; 319 320 xfixed_container() = default; 321 xfixed_container(const value_type& v); 322 explicit xfixed_container(const inner_shape_type& shape, layout_type l = L); 323 explicit xfixed_container(const inner_shape_type& shape, value_type v, layout_type l = L); 324 325 // remove this enable_if when removing the other value_type constructor 326 template <class IX = std::integral_constant<std::size_t, N>, class EN = std::enable_if_t<IX::value != 0, int>> 327 xfixed_container(nested_initializer_list_t<value_type, N> t); 328 329 ~xfixed_container() = default; 330 331 xfixed_container(const xfixed_container&) = default; 332 xfixed_container& operator=(const xfixed_container&) = default; 333 334 xfixed_container(xfixed_container&&) = default; 335 xfixed_container& operator=(xfixed_container&&) = default; 336 337 template <class E> 338 xfixed_container(const xexpression<E>& e); 339 340 template <class E> 341 xfixed_container& operator=(const xexpression<E>& e); 342 343 template <class ST = std::array<std::size_t, N>> 344 static xfixed_container from_shape(ST&& /*s*/); 345 346 template <class ST = std::array<std::size_t, N>> 347 void resize(ST&& shape, bool force = false) const; 348 template <class ST = shape_type> 349 void resize(ST&& shape, layout_type l) const; 350 template <class ST = shape_type> 351 void resize(ST&& shape, const strides_type& strides) const; 352 353 template <class ST = std::array<std::size_t, N>> 354 auto const& reshape(ST&& shape, layout_type layout = L) const; 355 356 template <class ST> 357 bool broadcast_shape(ST& s, bool reuse_cache = false) const; 358 359 constexpr layout_type layout() const noexcept; 360 bool is_contiguous() const noexcept; 361 362 private: 363 364 storage_type m_storage; 365 366 XTENSOR_CONSTEXPR_ENHANCED_STATIC inner_shape_type m_shape = S(); 367 XTENSOR_CONSTEXPR_ENHANCED_STATIC inner_strides_type m_strides = get_strides<L, inner_strides_type>(S()); 368 XTENSOR_CONSTEXPR_ENHANCED_STATIC inner_backstrides_type m_backstrides = get_backstrides(m_shape, m_strides); 369 370 storage_type& storage_impl() noexcept; 371 const storage_type& storage_impl() const noexcept; 372 373 XTENSOR_CONSTEXPR_RETURN const inner_shape_type& shape_impl() const noexcept; 374 XTENSOR_CONSTEXPR_RETURN const inner_strides_type& strides_impl() const noexcept; 375 XTENSOR_CONSTEXPR_RETURN const inner_backstrides_type& backstrides_impl() const noexcept; 376 377 friend class xcontainer<xfixed_container<ET, S, L, SH, Tag>>; 378 }; 379 380 #ifdef XTENSOR_HAS_CONSTEXPR_ENHANCED 381 // Out of line definitions to prevent linker errors prior to C++17 382 template <class ET, class S, layout_type L, bool SH, class Tag> 383 constexpr typename xfixed_container<ET, S, L, SH, Tag>::inner_shape_type xfixed_container<ET, S, L, SH, Tag>::m_shape; 384 385 template <class ET, class S, layout_type L, bool SH, class Tag> 386 constexpr typename xfixed_container<ET, S, L, SH, Tag>::inner_strides_type xfixed_container<ET, S, L, SH, Tag>::m_strides; 387 388 template <class ET, class S, layout_type L, bool SH, class Tag> 389 constexpr typename xfixed_container<ET, S, L, SH, Tag>::inner_backstrides_type xfixed_container<ET, S, L, SH, Tag>::m_backstrides; 390 #endif 391 392 /**************************************** 393 * xfixed_container_adaptor declaration * 394 ****************************************/ 395 396 template <class EC, class S, layout_type L, bool SH, class Tag> 397 class xfixed_adaptor; 398 399 template <class EC, class S, layout_type L, bool SH, class Tag> 400 struct xcontainer_inner_types<xfixed_adaptor<EC, S, L, SH, Tag>> 401 { 402 using storage_type = std::remove_reference_t<EC>; 403 using reference = typename storage_type::reference; 404 using const_reference = typename storage_type::const_reference; 405 using size_type = typename storage_type::size_type; 406 using shape_type = S; 407 using inner_shape_type = typename S::cast_type; 408 using strides_type = get_strides_t<inner_shape_type>; 409 using backstrides_type = strides_type; 410 using inner_strides_type = strides_type; 411 using inner_backstrides_type = backstrides_type; 412 using temporary_type = xfixed_container<typename storage_type::value_type, S, L, SH, Tag>; 413 static constexpr layout_type layout = L; 414 }; 415 416 template <class EC, class S, layout_type L, bool SH, class Tag> 417 struct xiterable_inner_types<xfixed_adaptor<EC, S, L, SH, Tag>> 418 : xcontainer_iterable_types<xfixed_adaptor<EC, S, L, SH, Tag>> 419 { 420 }; 421 422 /** 423 * @class xfixed_adaptor 424 * @brief Dense multidimensional container adaptor with tensor semantic 425 * and fixed dimension. 426 * 427 * The xfixed_adaptor class implements a dense multidimensional 428 * container adaptor with tensor semantic and fixed dimension. It 429 * is used to provide a multidimensional container semantic and a 430 * tensor semantic to stl-like containers. 431 * 432 * @tparam EC The closure for the container type to adapt. 433 * @tparam S The xshape template parameter for the fixed shape of the adaptor 434 * @tparam L The layout_type of the adaptor. 435 * @tparam SH Wether the adaptor can be used as a shared expression. 436 * @tparam Tag The expression tag. 437 */ 438 template <class EC, class S, layout_type L, bool SH, class Tag> 439 class xfixed_adaptor : public xcontainer<xfixed_adaptor<EC, S, L, SH, Tag>>, 440 public xcontainer_semantic<xfixed_adaptor<EC, S, L, SH, Tag>> 441 { 442 public: 443 444 using container_closure_type = EC; 445 446 using self_type = xfixed_adaptor<EC, S, L, SH, Tag>; 447 using base_type = xcontainer<self_type>; 448 using semantic_base = xcontainer_semantic<self_type>; 449 using storage_type = typename base_type::storage_type; 450 using shape_type = typename base_type::shape_type; 451 using strides_type = typename base_type::strides_type; 452 using backstrides_type = typename base_type::backstrides_type; 453 using inner_shape_type = typename base_type::inner_shape_type; 454 using inner_strides_type = typename base_type::inner_strides_type; 455 using inner_backstrides_type = typename base_type::inner_backstrides_type; 456 using temporary_type = typename semantic_base::temporary_type; 457 using expression_tag = Tag; 458 459 constexpr static std::size_t N = S::size(); 460 461 xfixed_adaptor(storage_type&& data); 462 xfixed_adaptor(const storage_type& data); 463 464 template <class D> 465 xfixed_adaptor(D&& data); 466 467 ~xfixed_adaptor() = default; 468 469 xfixed_adaptor(const xfixed_adaptor&) = default; 470 xfixed_adaptor& operator=(const xfixed_adaptor&); 471 472 xfixed_adaptor(xfixed_adaptor&&) = default; 473 xfixed_adaptor& operator=(xfixed_adaptor&&); 474 xfixed_adaptor& operator=(temporary_type&&); 475 476 template <class E> 477 xfixed_adaptor& operator=(const xexpression<E>& e); 478 479 template <class ST = std::array<std::size_t, N>> 480 void resize(ST&& shape, bool force = false) const; 481 template <class ST = shape_type> 482 void resize(ST&& shape, layout_type l) const; 483 template <class ST = shape_type> 484 void resize(ST&& shape, const strides_type& strides) const; 485 486 template <class ST = std::array<std::size_t, N>> 487 const auto& reshape(ST&& shape, layout_type layout = L) const; 488 489 template <class ST> 490 bool broadcast_shape(ST& s, bool reuse_cache = false) const; 491 492 constexpr layout_type layout() const noexcept; 493 bool is_contiguous() const noexcept; 494 495 private: 496 497 container_closure_type m_storage; 498 499 XTENSOR_CONSTEXPR_ENHANCED_STATIC inner_shape_type m_shape = S(); 500 XTENSOR_CONSTEXPR_ENHANCED_STATIC inner_strides_type m_strides = get_strides<L, inner_strides_type>(S()); 501 XTENSOR_CONSTEXPR_ENHANCED_STATIC inner_backstrides_type m_backstrides = get_backstrides(m_shape, m_strides); 502 503 storage_type& storage_impl() noexcept; 504 const storage_type& storage_impl() const noexcept; 505 506 XTENSOR_CONSTEXPR_RETURN const inner_shape_type& shape_impl() const noexcept; 507 XTENSOR_CONSTEXPR_RETURN const inner_strides_type& strides_impl() const noexcept; 508 XTENSOR_CONSTEXPR_RETURN const inner_backstrides_type& backstrides_impl() const noexcept; 509 510 friend class xcontainer<xfixed_adaptor<EC, S, L, SH, Tag>>; 511 }; 512 513 #ifdef XTENSOR_HAS_CONSTEXPR_ENHANCED 514 // Out of line definitions to prevent linker errors prior to C++17 515 template <class EC, class S, layout_type L, bool SH, class Tag> 516 constexpr typename xfixed_adaptor<EC, S, L, SH, Tag>::inner_shape_type xfixed_adaptor<EC, S, L, SH, Tag>::m_shape; 517 518 template <class EC, class S, layout_type L, bool SH, class Tag> 519 constexpr typename xfixed_adaptor<EC, S, L, SH, Tag>::inner_strides_type xfixed_adaptor<EC, S, L, SH, Tag>::m_strides; 520 521 template <class EC, class S, layout_type L, bool SH, class Tag> 522 constexpr typename xfixed_adaptor<EC, S, L, SH, Tag>::inner_backstrides_type xfixed_adaptor<EC, S, L, SH, Tag>::m_backstrides; 523 #endif 524 525 /************************************ 526 * xfixed_container implementation * 527 ************************************/ 528 529 /** 530 * @name Constructors 531 */ 532 //@{ 533 534 /** 535 * Create an uninitialized xfixed_container. 536 * Note this function is only provided for homogenity, and the shape & layout argument is 537 * disregarded (the template shape is always used). 538 * 539 * @param shape the shape of the xfixed_container (unused!) 540 * @param l the layout_type of the xfixed_container (unused!) 541 */ 542 template <class ET, class S, layout_type L, bool SH, class Tag> xfixed_container(const inner_shape_type & shape,layout_type l)543 inline xfixed_container<ET, S, L, SH, Tag>::xfixed_container(const inner_shape_type& shape, layout_type l) 544 { 545 (void)(shape); 546 (void)(l); 547 XTENSOR_ASSERT(shape.size() == N && std::equal(shape.begin(), shape.end(), m_shape.begin())); 548 XTENSOR_ASSERT(L == l); 549 } 550 551 template <class ET, class S, layout_type L, bool SH, class Tag> xfixed_container(const value_type & v)552 inline xfixed_container<ET, S, L, SH, Tag>::xfixed_container(const value_type& v) 553 { 554 if (this->size() != 1) 555 { 556 XTENSOR_THROW(std::runtime_error, 557 "wrong shape for scalar assignment (has to be xshape<>)."); 558 } 559 m_storage[0] = v; 560 } 561 562 /** 563 * Create an xfixed_container, and initialize with the value of v. 564 * Note, the shape argument to this function is only provided for homogenity, 565 * and the shape argument is disregarded (the template shape is always used). 566 * 567 * @param shape the shape of the xfixed_container (unused!) 568 * @param v the fill value 569 * @param l the layout_type of the xfixed_container (unused!) 570 */ 571 template <class ET, class S, layout_type L, bool SH, class Tag> xfixed_container(const inner_shape_type & shape,value_type v,layout_type l)572 inline xfixed_container<ET, S, L, SH, Tag>::xfixed_container(const inner_shape_type& shape, value_type v, layout_type l) 573 { 574 (void)(shape); 575 (void)(l); 576 XTENSOR_ASSERT(shape.size() == N && std::equal(shape.begin(), shape.end(), m_shape.begin())); 577 XTENSOR_ASSERT(L == l); 578 std::fill(m_storage.begin(), m_storage.end(), v); 579 } 580 581 namespace detail 582 { 583 template <std::size_t X> 584 struct check_initializer_list_shape 585 { 586 template <class T, class S> runxt::detail::check_initializer_list_shape587 static bool run(const T& t, const S& shape) 588 { 589 std::size_t IX = shape.size() - X; 590 bool result = (shape[IX] == t.size()); 591 for (std::size_t i = 0; i < shape[IX]; ++i) 592 { 593 result = result && check_initializer_list_shape<X - 1>::run(t.begin()[i], shape); 594 } 595 return result; 596 } 597 }; 598 599 template <> 600 struct check_initializer_list_shape<0> 601 { 602 template <class T, class S> runxt::detail::check_initializer_list_shape603 static bool run(const T& /*t*/, const S& /*shape*/) 604 { 605 return true; 606 } 607 }; 608 } 609 610 template <class ET, class S, layout_type L, bool SH, class Tag> 611 template <class ST> from_shape(ST && shape)612 inline xfixed_container<ET, S, L, SH, Tag> xfixed_container<ET, S, L, SH, Tag>::from_shape(ST&& shape) 613 { 614 (void) shape; 615 self_type tmp; 616 XTENSOR_ASSERT(shape.size() == N && std::equal(shape.begin(), shape.end(), tmp.shape().begin())); 617 return tmp; 618 } 619 620 /** 621 * Allocates an xfixed_container with shape S with values from a C array. 622 * The type returned by get_init_type_t is raw C array ``value_type[X][Y][Z]`` for ``xt::xshape<X, Y, Z>``. 623 * C arrays can be initialized with the initializer list syntax, but the size is checked at compile 624 * time to prevent errors. 625 * Note: for clang < 3.8 this is an initializer_list and the size is not checked at compile-or runtime. 626 */ 627 template <class ET, class S, layout_type L, bool SH, class Tag> 628 template <class IX, class EN> xfixed_container(nested_initializer_list_t<value_type,N> t)629 inline xfixed_container<ET, S, L, SH, Tag>::xfixed_container(nested_initializer_list_t<value_type, N> t) 630 { 631 XTENSOR_ASSERT_MSG(detail::check_initializer_list_shape<N>::run(t, this->shape()) == true, "initializer list shape does not match fixed shape"); 632 L == layout_type::row_major ? nested_copy(m_storage.begin(), t) : nested_copy(this->template begin<layout_type::row_major>(), t); 633 } 634 //@} 635 636 /** 637 * @name Extended copy semantic 638 */ 639 //@{ 640 /** 641 * The extended copy constructor. 642 */ 643 template <class ET, class S, layout_type L, bool SH, class Tag> 644 template <class E> xfixed_container(const xexpression<E> & e)645 inline xfixed_container<ET, S, L, SH, Tag>::xfixed_container(const xexpression<E>& e) 646 { 647 semantic_base::assign(e); 648 } 649 650 /** 651 * The extended assignment operator. 652 */ 653 template <class ET, class S, layout_type L, bool SH, class Tag> 654 template <class E> operator =(const xexpression<E> & e)655 inline auto xfixed_container<ET, S, L, SH, Tag>::operator=(const xexpression<E>& e) -> self_type& 656 { 657 return semantic_base::operator=(e); 658 } 659 //@} 660 661 /** 662 * Note that the xfixed_container **cannot** be resized. Attempting to resize with a different 663 * size throws an assert in debug mode. 664 */ 665 template <class ET, class S, layout_type L, bool SH, class Tag> 666 template <class ST> resize(ST && shape,bool) const667 inline void xfixed_container<ET, S, L, SH, Tag>::resize(ST&& shape, bool) const 668 { 669 (void)(shape); // remove unused parameter warning if XTENSOR_ASSERT undefined 670 XTENSOR_ASSERT(std::equal(shape.begin(), shape.end(), m_shape.begin()) && shape.size() == m_shape.size()); 671 } 672 673 /** 674 * Note that the xfixed_container **cannot** be resized. Attempting to resize with a different 675 * size throws an assert in debug mode. 676 */ 677 template <class ET, class S, layout_type L, bool SH, class Tag> 678 template <class ST> resize(ST && shape,layout_type l) const679 inline void xfixed_container<ET, S, L, SH, Tag>::resize(ST&& shape, layout_type l) const 680 { 681 (void)(shape); // remove unused parameter warning if XTENSOR_ASSERT undefined 682 (void)(l); 683 XTENSOR_ASSERT(std::equal(shape.begin(), shape.end(), m_shape.begin()) && shape.size() == m_shape.size() && L == l); 684 } 685 686 /** 687 * Note that the xfixed_container **cannot** be resized. Attempting to resize with a different 688 * size throws an assert in debug mode. 689 */ 690 template <class ET, class S, layout_type L, bool SH, class Tag> 691 template <class ST> resize(ST && shape,const strides_type & strides) const692 inline void xfixed_container<ET, S, L, SH, Tag>::resize(ST&& shape, const strides_type& strides) const 693 { 694 (void)(shape); // remove unused parameter warning if XTENSOR_ASSERT undefined 695 (void)(strides); 696 XTENSOR_ASSERT(std::equal(shape.begin(), shape.end(), m_shape.begin()) && shape.size() == m_shape.size()); 697 XTENSOR_ASSERT(std::equal(strides.begin(), strides.end(), m_strides.begin()) && strides.size() == m_strides.size()); 698 } 699 700 /** 701 * Note that the xfixed_container **cannot** be reshaped to a shape different from ``S``. 702 */ 703 template <class ET, class S, layout_type L, bool SH, class Tag> 704 template <class ST> reshape(ST && shape,layout_type layout) const705 inline auto const& xfixed_container<ET, S, L, SH, Tag>::reshape(ST&& shape, layout_type layout) const 706 { 707 if (!(std::equal(shape.begin(), shape.end(), m_shape.begin()) && shape.size() == m_shape.size() && layout == L)) 708 { 709 XTENSOR_THROW(std::runtime_error, "Trying to reshape xtensor_fixed with different shape or layout."); 710 } 711 return *this; 712 } 713 714 template <class ET, class S, layout_type L, bool SH, class Tag> 715 template <class ST> broadcast_shape(ST & shape,bool) const716 inline bool xfixed_container<ET, S, L, SH, Tag>::broadcast_shape(ST& shape, bool) const 717 { 718 return xt::broadcast_shape(m_shape, shape); 719 } 720 721 template <class ET, class S, layout_type L, bool SH, class Tag> layout() const722 constexpr layout_type xfixed_container<ET, S, L, SH, Tag>::layout() const noexcept 723 { 724 return base_type::static_layout; 725 } 726 727 template <class ET, class S, layout_type L, bool SH, class Tag> is_contiguous() const728 inline bool xfixed_container<ET, S, L, SH, Tag>::is_contiguous() const noexcept 729 { 730 using str_type = typename inner_strides_type::value_type; 731 return m_strides.empty() 732 || (layout() == layout_type::row_major && m_strides.back() == str_type(1)) 733 || (layout() == layout_type::column_major && m_strides.front() == str_type(1)); 734 } 735 736 template <class ET, class S, layout_type L, bool SH, class Tag> storage_impl()737 inline auto xfixed_container<ET, S, L, SH, Tag>::storage_impl() noexcept -> storage_type& 738 { 739 return m_storage; 740 } 741 742 template <class ET, class S, layout_type L, bool SH, class Tag> storage_impl() const743 inline auto xfixed_container<ET, S, L, SH, Tag>::storage_impl() const noexcept -> const storage_type& 744 { 745 return m_storage; 746 } 747 748 template <class ET, class S, layout_type L, bool SH, class Tag> shape_impl() const749 XTENSOR_CONSTEXPR_RETURN auto xfixed_container<ET, S, L, SH, Tag>::shape_impl() const noexcept -> const inner_shape_type& 750 { 751 return m_shape; 752 } 753 754 template <class ET, class S, layout_type L, bool SH, class Tag> strides_impl() const755 XTENSOR_CONSTEXPR_RETURN auto xfixed_container<ET, S, L, SH, Tag>::strides_impl() const noexcept -> const inner_strides_type& 756 { 757 return m_strides; 758 } 759 760 template <class ET, class S, layout_type L, bool SH, class Tag> backstrides_impl() const761 XTENSOR_CONSTEXPR_RETURN auto xfixed_container<ET, S, L, SH, Tag>::backstrides_impl() const noexcept -> const inner_backstrides_type& 762 { 763 return m_backstrides; 764 } 765 766 /******************* 767 * xfixed_adaptor * 768 *******************/ 769 770 /** 771 * @name Constructors 772 */ 773 //@{ 774 /** 775 * Constructs an xfixed_adaptor of the given stl-like container. 776 * @param data the container to adapt 777 */ 778 template <class EC, class S, layout_type L, bool SH, class Tag> xfixed_adaptor(storage_type && data)779 inline xfixed_adaptor<EC, S, L, SH, Tag>::xfixed_adaptor(storage_type&& data) 780 : base_type(), m_storage(std::move(data)) 781 { 782 } 783 784 /** 785 * Constructs an xfixed_adaptor of the given stl-like container. 786 * @param data the container to adapt 787 */ 788 template <class EC, class S, layout_type L, bool SH, class Tag> xfixed_adaptor(const storage_type & data)789 inline xfixed_adaptor<EC, S, L, SH, Tag>::xfixed_adaptor(const storage_type& data) 790 : base_type(), m_storage(data) 791 { 792 } 793 794 /** 795 * Constructs an xfixed_adaptor of the given stl-like container, 796 * with the specified shape and layout_type. 797 * @param data the container to adapt 798 */ 799 template <class EC, class S, layout_type L, bool SH, class Tag> 800 template <class D> xfixed_adaptor(D && data)801 inline xfixed_adaptor<EC, S, L, SH, Tag>::xfixed_adaptor(D&& data) 802 : base_type(), m_storage(std::forward<D>(data)) 803 { 804 } 805 //@} 806 807 template <class EC, class S, layout_type L, bool SH, class Tag> operator =(const xfixed_adaptor & rhs)808 inline auto xfixed_adaptor<EC, S, L, SH, Tag>::operator=(const xfixed_adaptor& rhs) -> self_type& 809 { 810 base_type::operator=(rhs); 811 m_storage = rhs.m_storage; 812 return *this; 813 } 814 815 template <class EC, class S, layout_type L, bool SH, class Tag> operator =(xfixed_adaptor && rhs)816 inline auto xfixed_adaptor<EC, S, L, SH, Tag>::operator=(xfixed_adaptor&& rhs) -> self_type& 817 { 818 base_type::operator=(std::move(rhs)); 819 m_storage = rhs.m_storage; 820 return *this; 821 } 822 823 template <class EC, class S, layout_type L, bool SH, class Tag> operator =(temporary_type && rhs)824 inline auto xfixed_adaptor<EC, S, L, SH, Tag>::operator=(temporary_type&& rhs) -> self_type& 825 { 826 m_storage.resize(rhs.storage().size()); 827 std::copy(rhs.storage().cbegin(), rhs.storage().cend(), m_storage.begin()); 828 return *this; 829 } 830 831 /** 832 * @name Extended copy semantic 833 */ 834 //@{ 835 /** 836 * The extended assignment operator. 837 */ 838 template <class EC, class S, layout_type L, bool SH, class Tag> 839 template <class E> operator =(const xexpression<E> & e)840 inline auto xfixed_adaptor<EC, S, L, SH, Tag>::operator=(const xexpression<E>& e) -> self_type& 841 { 842 return semantic_base::operator=(e); 843 } 844 //@} 845 846 /** 847 * Note that the xfixed_adaptor **cannot** be resized. Attempting to resize with a different 848 * size throws an assert in debug mode. 849 */ 850 template <class ET, class S, layout_type L, bool SH, class Tag> 851 template <class ST> resize(ST && shape,bool) const852 inline void xfixed_adaptor<ET, S, L, SH, Tag>::resize(ST&& shape, bool) const 853 { 854 (void)(shape); // remove unused parameter warning if XTENSOR_ASSERT undefined 855 XTENSOR_ASSERT(std::equal(shape.begin(), shape.end(), m_shape.begin()) && shape.size() == m_shape.size()); 856 } 857 858 /** 859 * Note that the xfixed_adaptor **cannot** be resized. Attempting to resize with a different 860 * size throws an assert in debug mode. 861 */ 862 template <class ET, class S, layout_type L, bool SH, class Tag> 863 template <class ST> resize(ST && shape,layout_type l) const864 inline void xfixed_adaptor<ET, S, L, SH, Tag>::resize(ST&& shape, layout_type l) const 865 { 866 (void)(shape); // remove unused parameter warning if XTENSOR_ASSERT undefined 867 (void)(l); 868 XTENSOR_ASSERT(std::equal(shape.begin(), shape.end(), m_shape.begin()) && shape.size() == m_shape.size() && L == l); 869 } 870 871 /** 872 * Note that the xfixed_adaptor **cannot** be resized. Attempting to resize with a different 873 * size throws an assert in debug mode. 874 */ 875 template <class ET, class S, layout_type L, bool SH, class Tag> 876 template <class ST> resize(ST && shape,const strides_type & strides) const877 inline void xfixed_adaptor<ET, S, L, SH, Tag>::resize(ST&& shape, const strides_type& strides) const 878 { 879 (void)(shape); // remove unused parameter warning if XTENSOR_ASSERT undefined 880 (void)(strides); 881 XTENSOR_ASSERT(std::equal(shape.begin(), shape.end(), m_shape.begin()) && shape.size() == m_shape.size()); 882 XTENSOR_ASSERT(std::equal(strides.begin(), strides.end(), m_strides.begin()) && strides.size() == m_strides.size()); 883 } 884 885 /** 886 * Note that the xfixed_container **cannot** be reshaped to a shape different from ``S``. 887 */ 888 template <class ET, class S, layout_type L, bool SH, class Tag> 889 template <class ST> reshape(ST && shape,layout_type layout) const890 inline auto const& xfixed_adaptor<ET, S, L, SH, Tag>::reshape(ST&& shape, layout_type layout) const 891 { 892 if (!(std::equal(shape.begin(), shape.end(), m_shape.begin()) && shape.size() == m_shape.size() && layout == L)) 893 { 894 XTENSOR_THROW(std::runtime_error, "Trying to reshape xtensor_fixed with different shape or layout."); 895 } 896 return *this; 897 } 898 899 template <class ET, class S, layout_type L, bool SH, class Tag> 900 template <class ST> broadcast_shape(ST & shape,bool) const901 inline bool xfixed_adaptor<ET, S, L, SH, Tag>::broadcast_shape(ST& shape, bool) const 902 { 903 return xt::broadcast_shape(m_shape, shape); 904 } 905 906 template <class EC, class S, layout_type L, bool SH, class Tag> storage_impl()907 inline auto xfixed_adaptor<EC, S, L, SH, Tag>::storage_impl() noexcept -> storage_type& 908 { 909 return m_storage; 910 } 911 912 template <class EC, class S, layout_type L, bool SH, class Tag> storage_impl() const913 inline auto xfixed_adaptor<EC, S, L, SH, Tag>::storage_impl() const noexcept -> const storage_type& 914 { 915 return m_storage; 916 } 917 918 template <class EC, class S, layout_type L, bool SH, class Tag> layout() const919 constexpr layout_type xfixed_adaptor<EC, S, L, SH, Tag>::layout() const noexcept 920 { 921 return base_type::static_layout; 922 } 923 924 template <class EC, class S, layout_type L, bool SH, class Tag> is_contiguous() const925 inline bool xfixed_adaptor<EC, S, L, SH, Tag>::is_contiguous() const noexcept 926 { 927 using str_type = typename inner_strides_type::value_type; 928 return m_strides.empty() 929 || (layout() == layout_type::row_major && m_strides.back() == str_type(1)) 930 || (layout() == layout_type::column_major && m_strides.front() == str_type(1)); 931 } 932 933 template <class EC, class S, layout_type L, bool SH, class Tag> shape_impl() const934 XTENSOR_CONSTEXPR_RETURN auto xfixed_adaptor<EC, S, L, SH, Tag>::shape_impl() const noexcept -> const inner_shape_type& 935 { 936 return m_shape; 937 } 938 939 template <class EC, class S, layout_type L, bool SH, class Tag> strides_impl() const940 XTENSOR_CONSTEXPR_RETURN auto xfixed_adaptor<EC, S, L, SH, Tag>::strides_impl() const noexcept -> const inner_strides_type& 941 { 942 return m_strides; 943 } 944 945 template <class EC, class S, layout_type L, bool SH, class Tag> backstrides_impl() const946 XTENSOR_CONSTEXPR_RETURN auto xfixed_adaptor<EC, S, L, SH, Tag>::backstrides_impl() const noexcept -> const inner_backstrides_type& 947 { 948 return m_backstrides; 949 } 950 } 951 952 #endif 953