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_SCALAR_HPP 11 #define XTENSOR_SCALAR_HPP 12 13 #include <array> 14 #include <cstddef> 15 #include <utility> 16 17 #include <xtl/xtype_traits.hpp> 18 19 #include "xaccessible.hpp" 20 #include "xexpression.hpp" 21 #include "xiterable.hpp" 22 #include "xlayout.hpp" 23 #include "xtensor_simd.hpp" 24 25 namespace xt 26 { 27 28 /********************* 29 * xscalar extension * 30 *********************/ 31 32 namespace extension 33 { 34 template <class Tag, class CT> 35 struct xscalar_base_impl; 36 37 template <class CT> 38 struct xscalar_base_impl<xtensor_expression_tag, CT> 39 { 40 using type = xtensor_empty_base; 41 }; 42 43 template <class CT> 44 struct xscalar_base : xscalar_base_impl<get_expression_tag_t<std::decay_t<CT>>, CT> 45 { 46 }; 47 48 template <class CT> 49 using xscalar_base_t = typename xscalar_base<CT>::type; 50 } 51 52 /*********** 53 * xscalar * 54 ***********/ 55 56 // xscalar is a cheap wrapper for a scalar value as an xexpression. 57 template <class CT> 58 class xscalar; 59 60 template <bool is_const, class CT> 61 class xscalar_stepper; 62 63 template <bool is_const, class CT> 64 class xdummy_iterator; 65 66 template <class CT> 67 struct xiterable_inner_types<xscalar<CT>> 68 { 69 using value_type = std::decay_t<CT>; 70 using inner_shape_type = std::array<std::size_t, 0>; 71 using shape_type = inner_shape_type; 72 using const_stepper = xscalar_stepper<true, CT>; 73 using stepper = xscalar_stepper<false, CT>; 74 }; 75 76 template <class CT> 77 struct xcontainer_inner_types<xscalar<CT>> 78 { 79 using value_type = std::decay_t<CT>; 80 using reference = value_type&; 81 using const_reference = const value_type&; 82 using size_type = std::size_t; 83 }; 84 85 template <class CT> 86 class xscalar : public xsharable_expression<xscalar<CT>>, 87 private xiterable<xscalar<CT>>, 88 private xaccessible<xscalar<CT>>, 89 public extension::xscalar_base_t<CT> 90 { 91 public: 92 93 using self_type = xscalar<CT>; 94 using xexpression_type = std::decay_t<CT>; 95 using extension_base = extension::xscalar_base_t<CT>; 96 using accessible_base = xaccessible<self_type>; 97 using expression_tag = typename extension_base::expression_tag; 98 using inner_types = xcontainer_inner_types<self_type>; 99 100 using value_type = typename inner_types::value_type; 101 using reference = typename inner_types::reference; 102 using const_reference = typename inner_types::const_reference; 103 using pointer = value_type*; 104 using const_pointer = const value_type*; 105 using size_type = typename inner_types::size_type; 106 using difference_type = std::ptrdiff_t; 107 using simd_value_type = xt_simd::simd_type<value_type>; 108 using bool_load_type = xt::bool_load_type<value_type>; 109 110 using iterable_base = xiterable<self_type>; 111 using inner_shape_type = typename iterable_base::inner_shape_type; 112 using shape_type = inner_shape_type; 113 114 using stepper = typename iterable_base::stepper; 115 using const_stepper = typename iterable_base::const_stepper; 116 117 template <layout_type L> 118 using layout_iterator = typename iterable_base::template layout_iterator<L>; 119 template <layout_type L> 120 using const_layout_iterator = typename iterable_base::template const_layout_iterator<L>; 121 122 template <layout_type L> 123 using reverse_layout_iterator = typename iterable_base::template reverse_layout_iterator<L>; 124 template <layout_type L> 125 using const_reverse_layout_iterator = typename iterable_base::template const_reverse_layout_iterator<L>; 126 127 template <class S, layout_type L> 128 using broadcast_iterator = typename iterable_base::template broadcast_iterator<S, L>; 129 template <class S, layout_type L> 130 using const_broadcast_iterator = typename iterable_base::template const_broadcast_iterator<S, L>; 131 132 template <class S, layout_type L> 133 using reverse_broadcast_iterator = typename iterable_base::template reverse_broadcast_iterator<S, L>; 134 template <class S, layout_type L> 135 using const_reverse_broadcast_iterator = typename iterable_base::template const_reverse_broadcast_iterator<S, L>; 136 137 using iterator = value_type*; 138 using const_iterator = const value_type*; 139 using reverse_iterator = std::reverse_iterator<iterator>; 140 using const_reverse_iterator = std::reverse_iterator<const_iterator>; 141 142 using dummy_iterator = xdummy_iterator<false, CT>; 143 using const_dummy_iterator = xdummy_iterator<true, CT>; 144 145 static constexpr layout_type static_layout = layout_type::any; 146 static constexpr bool contiguous_layout = true; 147 148 xscalar() noexcept; 149 xscalar(CT value) noexcept; 150 151 operator value_type&() noexcept; 152 operator const value_type&() const noexcept; 153 154 size_type size() const noexcept; 155 const shape_type& shape() const noexcept; 156 size_type shape(size_type i) const noexcept; 157 layout_type layout() const noexcept; 158 bool is_contiguous() const noexcept; 159 using accessible_base::dimension; 160 using accessible_base::shape; 161 162 template <class... Args> 163 reference operator()(Args...) noexcept; 164 template <class... Args> 165 reference unchecked(Args...) noexcept; 166 167 template <class... Args> 168 const_reference operator()(Args...) const noexcept; 169 template <class... Args> 170 const_reference unchecked(Args...) const noexcept; 171 172 using accessible_base::at; 173 using accessible_base::operator[]; 174 using accessible_base::periodic; 175 using accessible_base::in_bounds; 176 using accessible_base::front; 177 using accessible_base::back; 178 179 template <class It> 180 reference element(It, It) noexcept; 181 182 template <class It> 183 const_reference element(It, It) const noexcept; 184 185 xexpression_type& expression() noexcept; 186 const xexpression_type& expression() const noexcept; 187 188 template <class S> 189 bool broadcast_shape(S& shape, bool reuse_cache = false) const noexcept; 190 191 template <class S> 192 bool has_linear_assign(const S& strides) const noexcept; 193 194 template <layout_type L = XTENSOR_DEFAULT_TRAVERSAL> 195 iterator begin() noexcept; 196 template <layout_type L = XTENSOR_DEFAULT_TRAVERSAL> 197 iterator end() noexcept; 198 199 template <layout_type L = XTENSOR_DEFAULT_TRAVERSAL> 200 const_iterator begin() const noexcept; 201 template <layout_type L = XTENSOR_DEFAULT_TRAVERSAL> 202 const_iterator end() const noexcept; 203 template <layout_type L = XTENSOR_DEFAULT_TRAVERSAL> 204 const_iterator cbegin() const noexcept; 205 template <layout_type L = XTENSOR_DEFAULT_TRAVERSAL> 206 const_iterator cend() const noexcept; 207 208 template <layout_type L = XTENSOR_DEFAULT_TRAVERSAL> 209 reverse_iterator rbegin() noexcept; 210 template <layout_type L = XTENSOR_DEFAULT_TRAVERSAL> 211 reverse_iterator rend() noexcept; 212 213 template <layout_type L = XTENSOR_DEFAULT_TRAVERSAL> 214 const_reverse_iterator rbegin() const noexcept; 215 template <layout_type L = XTENSOR_DEFAULT_TRAVERSAL> 216 const_reverse_iterator rend() const noexcept; 217 template <layout_type L = XTENSOR_DEFAULT_TRAVERSAL> 218 const_reverse_iterator crbegin() const noexcept; 219 template <layout_type L = XTENSOR_DEFAULT_TRAVERSAL> 220 const_reverse_iterator crend() const noexcept; 221 222 template <class S, layout_type L = XTENSOR_DEFAULT_TRAVERSAL> 223 broadcast_iterator<S, L> begin(const S& shape) noexcept; 224 template <class S, layout_type L = XTENSOR_DEFAULT_TRAVERSAL> 225 broadcast_iterator<S, L> end(const S& shape) noexcept; 226 227 template <class S, layout_type L = XTENSOR_DEFAULT_TRAVERSAL> 228 const_broadcast_iterator<S, L> begin(const S& shape) const noexcept; 229 template <class S, layout_type L = XTENSOR_DEFAULT_TRAVERSAL> 230 const_broadcast_iterator<S, L> end(const S& shape) const noexcept; 231 template <class S, layout_type L = XTENSOR_DEFAULT_TRAVERSAL> 232 const_broadcast_iterator<S, L> cbegin(const S& shape) const noexcept; 233 template <class S, layout_type L = XTENSOR_DEFAULT_TRAVERSAL> 234 const_broadcast_iterator<S, L> cend(const S& shape) const noexcept; 235 236 237 template <class S, layout_type L = XTENSOR_DEFAULT_TRAVERSAL> 238 reverse_broadcast_iterator<S, L> rbegin(const S& shape) noexcept; 239 template <class S, layout_type L = XTENSOR_DEFAULT_TRAVERSAL> 240 reverse_broadcast_iterator<S, L> rend(const S& shape) noexcept; 241 242 template <class S, layout_type L = XTENSOR_DEFAULT_TRAVERSAL> 243 const_reverse_broadcast_iterator<S, L> rbegin(const S& shape) const noexcept; 244 template <class S, layout_type L = XTENSOR_DEFAULT_TRAVERSAL> 245 const_reverse_broadcast_iterator<S, L> rend(const S& shape) const noexcept; 246 template <class S, layout_type L = XTENSOR_DEFAULT_TRAVERSAL> 247 const_reverse_broadcast_iterator<S, L> crbegin(const S& shape) const noexcept; 248 template <class S, layout_type L = XTENSOR_DEFAULT_TRAVERSAL> 249 const_reverse_broadcast_iterator<S, L> crend(const S& shape) const noexcept; 250 251 iterator storage_begin() noexcept; 252 iterator storage_end() noexcept; 253 254 const_iterator storage_begin() const noexcept; 255 const_iterator storage_end() const noexcept; 256 const_iterator storage_cbegin() const noexcept; 257 const_iterator storage_cend() const noexcept; 258 259 reverse_iterator storage_rbegin() noexcept; 260 reverse_iterator storage_rend() noexcept; 261 262 const_reverse_iterator storage_rbegin() const noexcept; 263 const_reverse_iterator storage_rend() const noexcept; 264 const_reverse_iterator storage_crbegin() const noexcept; 265 const_reverse_iterator storage_crend() const noexcept; 266 267 template <class S> 268 stepper stepper_begin(const S& shape) noexcept; 269 template <class S> 270 stepper stepper_end(const S& shape, layout_type l) noexcept; 271 272 template <class S> 273 const_stepper stepper_begin(const S& shape) const noexcept; 274 template <class S> 275 const_stepper stepper_end(const S& shape, layout_type l) const noexcept; 276 277 dummy_iterator dummy_begin() noexcept; 278 dummy_iterator dummy_end() noexcept; 279 280 const_dummy_iterator dummy_begin() const noexcept; 281 const_dummy_iterator dummy_end() const noexcept; 282 283 reference data_element(size_type i) noexcept; 284 const_reference data_element(size_type i) const noexcept; 285 286 reference flat(size_type i) noexcept; 287 const_reference flat(size_type i) const noexcept; 288 289 template <class align, class simd = simd_value_type> 290 void store_simd(size_type i, const simd& e); 291 template <class align, class requested_type = value_type, 292 std::size_t N = xt_simd::simd_traits<requested_type>::size> 293 xt_simd::simd_return_type<value_type, requested_type> 294 load_simd(size_type i) const; 295 296 private: 297 298 CT m_value; 299 300 friend class xconst_iterable<self_type>; 301 friend class xiterable<self_type>; 302 friend class xaccessible<self_type>; 303 friend class xconst_accessible<self_type>; 304 }; 305 306 namespace detail 307 { 308 template <class E> 309 struct is_xscalar_impl : std::false_type 310 { 311 }; 312 313 template <class E> 314 struct is_xscalar_impl<xscalar<E>> : std::true_type 315 { 316 }; 317 } 318 319 template <class E> 320 using is_xscalar = detail::is_xscalar_impl<E>; 321 322 namespace detail 323 { 324 template <class... E> 325 struct all_xscalar 326 { 327 static constexpr bool value = xtl::conjunction<is_xscalar<std::decay_t<E>>...>::value; 328 }; 329 } 330 331 // Note: MSVC bug workaround. Cannot just define 332 // template <class... E> 333 // using all_xscalar = xtl::conjunction<is_xscalar<std::decay_t<E>>...>; 334 335 template <class... E> 336 using all_xscalar = detail::all_xscalar<E...>; 337 338 /****************** 339 * xref and xcref * 340 ******************/ 341 342 template <class T> 343 xscalar<T&> xref(T& t); 344 345 template <class T> 346 xscalar<const T&> xcref(T& t); 347 348 /******************* 349 * xscalar_stepper * 350 *******************/ 351 352 template <bool is_const, class CT> 353 class xscalar_stepper 354 { 355 public: 356 357 using self_type = xscalar_stepper<is_const, CT>; 358 using storage_type = std::conditional_t<is_const, 359 const xscalar<CT>, 360 xscalar<CT>>; 361 362 using value_type = typename storage_type::value_type; 363 using reference = std::conditional_t<is_const, 364 typename storage_type::const_reference, 365 typename storage_type::reference>; 366 using pointer = std::conditional_t<is_const, 367 typename storage_type::const_pointer, 368 typename storage_type::pointer>; 369 using size_type = typename storage_type::size_type; 370 using difference_type = typename storage_type::difference_type; 371 using shape_type = typename storage_type::shape_type; 372 373 template <class requested_type> 374 using simd_return_type = xt_simd::simd_return_type<value_type, requested_type>; 375 376 xscalar_stepper(storage_type* c) noexcept; 377 378 reference operator*() const noexcept; 379 380 void step(size_type dim, size_type n = 1) noexcept; 381 void step_back(size_type dim, size_type n = 1) noexcept; 382 void reset(size_type dim) noexcept; 383 void reset_back(size_type dim) noexcept; 384 385 void to_begin() noexcept; 386 void to_end(layout_type l) noexcept; 387 388 template <class T> 389 simd_return_type<T> step_simd(); 390 391 void step_leading(); 392 393 private: 394 395 storage_type* p_c; 396 }; 397 398 /******************* 399 * xdummy_iterator * 400 *******************/ 401 402 namespace detail 403 { 404 template <bool is_const, class CT> 405 using dummy_reference_t = std::conditional_t<is_const, 406 typename xscalar<CT>::const_reference, 407 typename xscalar<CT>::reference>; 408 409 template <bool is_const, class CT> 410 using dummy_pointer_t = std::conditional_t<is_const, 411 typename xscalar<CT>::const_pointer, 412 typename xscalar<CT>::pointer>; 413 } 414 415 template <bool is_const, class CT> 416 class xdummy_iterator 417 : public xtl::xrandom_access_iterator_base<xdummy_iterator<is_const, CT>, 418 typename xscalar<CT>::value_type, 419 typename xscalar<CT>::difference_type, 420 detail::dummy_pointer_t<is_const, CT>, 421 detail::dummy_reference_t<is_const, CT>> 422 { 423 public: 424 425 using self_type = xdummy_iterator<is_const, CT>; 426 using storage_type = std::conditional_t<is_const, 427 const xscalar<CT>, 428 xscalar<CT>>; 429 430 using value_type = typename storage_type::value_type; 431 using reference = detail::dummy_reference_t<is_const, CT>; 432 using pointer = detail::dummy_pointer_t<is_const, CT>; 433 using difference_type = typename storage_type::difference_type; 434 using iterator_category = std::random_access_iterator_tag; 435 436 explicit xdummy_iterator(storage_type* c) noexcept; 437 438 self_type& operator++() noexcept; 439 self_type& operator--() noexcept; 440 441 self_type& operator+=(difference_type n) noexcept; 442 self_type& operator-=(difference_type n) noexcept; 443 444 difference_type operator-(const self_type& rhs) const noexcept; 445 446 reference operator*() const noexcept; 447 448 bool equal(const self_type& rhs) const noexcept; 449 bool less_than(const self_type& rhs) const noexcept; 450 451 private: 452 453 storage_type* p_c; 454 }; 455 456 template <bool is_const, class CT> 457 bool operator==(const xdummy_iterator<is_const, CT>& lhs, 458 const xdummy_iterator<is_const, CT>& rhs) noexcept; 459 460 template <bool is_const, class CT> 461 bool operator<(const xdummy_iterator<is_const, CT>& lhs, 462 const xdummy_iterator<is_const, CT>& rhs) noexcept; 463 464 template <class T> 465 struct is_not_xdummy_iterator : std::true_type 466 { 467 }; 468 469 template <bool is_const, class CT> 470 struct is_not_xdummy_iterator<xdummy_iterator<is_const, CT>> : std::false_type 471 { 472 }; 473 474 /***************************** 475 * linear_begin / linear_end * 476 *****************************/ 477 478 template <class CT> linear_begin(xscalar<CT> & c)479 XTENSOR_CONSTEXPR_RETURN auto linear_begin(xscalar<CT>& c) noexcept -> decltype(c.dummy_begin()) 480 { 481 return c.dummy_begin(); 482 } 483 484 template <class CT> linear_end(xscalar<CT> & c)485 XTENSOR_CONSTEXPR_RETURN auto linear_end(xscalar<CT>& c) noexcept -> decltype(c.dummy_end()) 486 { 487 return c.dummy_end(); 488 } 489 490 template <class CT> linear_begin(const xscalar<CT> & c)491 XTENSOR_CONSTEXPR_RETURN auto linear_begin(const xscalar<CT>& c) noexcept -> decltype(c.dummy_begin()) 492 { 493 return c.dummy_begin(); 494 } 495 496 template <class CT> linear_end(const xscalar<CT> & c)497 XTENSOR_CONSTEXPR_RETURN auto linear_end(const xscalar<CT>& c) noexcept -> decltype(c.dummy_end()) 498 { 499 return c.dummy_end(); 500 } 501 502 /************************** 503 * xscalar implementation * 504 **************************/ 505 506 // This constructor will not compile when CT is a reference type. 507 template <class CT> xscalar()508 inline xscalar<CT>::xscalar() noexcept 509 : m_value() 510 { 511 } 512 513 template <class CT> xscalar(CT value)514 inline xscalar<CT>::xscalar(CT value) noexcept 515 : m_value(value) 516 { 517 } 518 519 template <class CT> operator value_type&()520 inline xscalar<CT>::operator value_type&() noexcept 521 { 522 return m_value; 523 } 524 525 template <class CT> operator const value_type&() const526 inline xscalar<CT>::operator const value_type&() const noexcept 527 { 528 return m_value; 529 } 530 531 template <class CT> size() const532 inline auto xscalar<CT>::size() const noexcept -> size_type 533 { 534 return 1; 535 } 536 537 template <class CT> shape() const538 inline auto xscalar<CT>::shape() const noexcept -> const shape_type& 539 { 540 static std::array<size_type, 0> zero_shape; 541 return zero_shape; 542 } 543 544 template <class CT> shape(size_type) const545 inline auto xscalar<CT>::shape(size_type) const noexcept -> size_type 546 { 547 return 0; 548 } 549 550 template <class CT> layout() const551 inline layout_type xscalar<CT>::layout() const noexcept 552 { 553 return static_layout; 554 } 555 556 template <class CT> is_contiguous() const557 inline bool xscalar<CT>::is_contiguous() const noexcept 558 { 559 return true; 560 } 561 562 template <class CT> 563 template <class... Args> operator ()(Args...)564 inline auto xscalar<CT>::operator()(Args...) noexcept -> reference 565 { 566 XTENSOR_CHECK_DIMENSION((std::array<int, 0>()), Args()...); 567 return m_value; 568 } 569 570 template <class CT> 571 template <class... Args> unchecked(Args...)572 inline auto xscalar<CT>::unchecked(Args...) noexcept -> reference 573 { 574 return m_value; 575 } 576 577 template <class CT> 578 template <class... Args> operator ()(Args...) const579 inline auto xscalar<CT>::operator()(Args...) const noexcept -> const_reference 580 { 581 XTENSOR_CHECK_DIMENSION((std::array<int, 0>()), Args()...); 582 return m_value; 583 } 584 585 template <class CT> 586 template <class... Args> unchecked(Args...) const587 inline auto xscalar<CT>::unchecked(Args...) const noexcept -> const_reference 588 { 589 return m_value; 590 } 591 592 template <class CT> 593 template <class It> element(It,It)594 inline auto xscalar<CT>::element(It, It) noexcept -> reference 595 { 596 return m_value; 597 } 598 599 template <class CT> 600 template <class It> element(It,It) const601 inline auto xscalar<CT>::element(It, It) const noexcept -> const_reference 602 { 603 return m_value; 604 } 605 606 template <class CT> expression()607 inline auto xscalar<CT>::expression() noexcept -> xexpression_type& 608 { 609 return m_value; 610 } 611 612 template <class CT> expression() const613 inline auto xscalar<CT>::expression() const noexcept -> const xexpression_type& 614 { 615 return m_value; 616 } 617 618 template <class CT> 619 template <class S> broadcast_shape(S &,bool) const620 inline bool xscalar<CT>::broadcast_shape(S&, bool) const noexcept 621 { 622 return true; 623 } 624 625 template <class CT> 626 template <class S> has_linear_assign(const S &) const627 inline bool xscalar<CT>::has_linear_assign(const S&) const noexcept 628 { 629 return true; 630 } 631 632 template <class CT> 633 template <layout_type L> begin()634 inline auto xscalar<CT>::begin() noexcept -> iterator 635 { 636 return &m_value; 637 } 638 639 template <class CT> 640 template <layout_type L> end()641 inline auto xscalar<CT>::end() noexcept -> iterator 642 { 643 return &m_value + 1; 644 } 645 646 template <class CT> 647 template <layout_type L> begin() const648 inline auto xscalar<CT>::begin() const noexcept -> const_iterator 649 { 650 return &m_value; 651 } 652 653 template <class CT> 654 template <layout_type L> end() const655 inline auto xscalar<CT>::end() const noexcept -> const_iterator 656 { 657 return &m_value + 1; 658 } 659 660 template <class CT> 661 template <layout_type L> cbegin() const662 inline auto xscalar<CT>::cbegin() const noexcept -> const_iterator 663 { 664 return &m_value; 665 } 666 667 template <class CT> 668 template <layout_type L> cend() const669 inline auto xscalar<CT>::cend() const noexcept -> const_iterator 670 { 671 return &m_value + 1; 672 } 673 674 template <class CT> 675 template <layout_type L> rbegin()676 inline auto xscalar<CT>::rbegin() noexcept -> reverse_iterator 677 { 678 return reverse_iterator(end()); 679 } 680 681 template <class CT> 682 template <layout_type L> rend()683 inline auto xscalar<CT>::rend() noexcept -> reverse_iterator 684 { 685 return reverse_iterator(begin()); 686 } 687 688 template <class CT> 689 template <layout_type L> rbegin() const690 inline auto xscalar<CT>::rbegin() const noexcept -> const_reverse_iterator 691 { 692 return crbegin(); 693 } 694 695 template <class CT> 696 template <layout_type L> rend() const697 inline auto xscalar<CT>::rend() const noexcept -> const_reverse_iterator 698 { 699 return crend(); 700 } 701 702 template <class CT> 703 template <layout_type L> crbegin() const704 inline auto xscalar<CT>::crbegin() const noexcept -> const_reverse_iterator 705 { 706 return const_reverse_iterator(cend()); 707 } 708 709 template <class CT> 710 template <layout_type L> crend() const711 inline auto xscalar<CT>::crend() const noexcept -> const_reverse_iterator 712 { 713 return const_reverse_iterator(cbegin()); 714 } 715 716 /***************************** 717 * Broadcasting iterator api * 718 *****************************/ 719 720 template <class CT> 721 template <class S, layout_type L> begin(const S & shape)722 inline auto xscalar<CT>::begin(const S& shape) noexcept -> broadcast_iterator<S, L> 723 { 724 return iterable_base::template begin<S, L>(shape); 725 } 726 727 template <class CT> 728 template <class S, layout_type L> end(const S & shape)729 inline auto xscalar<CT>::end(const S& shape) noexcept -> broadcast_iterator<S, L> 730 { 731 return iterable_base::template end<S, L>(shape); 732 } 733 734 template <class CT> 735 template <class S, layout_type L> begin(const S & shape) const736 inline auto xscalar<CT>::begin(const S& shape) const noexcept -> const_broadcast_iterator<S, L> 737 { 738 return iterable_base::template begin<S, L>(shape); 739 } 740 741 template <class CT> 742 template <class S, layout_type L> end(const S & shape) const743 inline auto xscalar<CT>::end(const S& shape) const noexcept -> const_broadcast_iterator<S, L> 744 { 745 return iterable_base::template end<S, L>(shape); 746 } 747 748 template <class CT> 749 template <class S, layout_type L> cbegin(const S & shape) const750 inline auto xscalar<CT>::cbegin(const S& shape) const noexcept -> const_broadcast_iterator<S, L> 751 { 752 return iterable_base::template cbegin<S, L>(shape); 753 } 754 755 template <class CT> 756 template <class S, layout_type L> cend(const S & shape) const757 inline auto xscalar<CT>::cend(const S& shape) const noexcept -> const_broadcast_iterator<S, L> 758 { 759 return iterable_base::template cend<S, L>(shape); 760 } 761 762 template <class CT> 763 template <class S, layout_type L> rbegin(const S & shape)764 inline auto xscalar<CT>::rbegin(const S& shape) noexcept -> reverse_broadcast_iterator<S, L> 765 { 766 return iterable_base::template rbegin<S, L>(shape); 767 } 768 769 template <class CT> 770 template <class S, layout_type L> rend(const S & shape)771 inline auto xscalar<CT>::rend(const S& shape) noexcept -> reverse_broadcast_iterator<S, L> 772 { 773 return iterable_base::template rend<S, L>(shape); 774 } 775 776 template <class CT> 777 template <class S, layout_type L> rbegin(const S & shape) const778 inline auto xscalar<CT>::rbegin(const S& shape) const noexcept -> const_reverse_broadcast_iterator<S, L> 779 { 780 return iterable_base::template rbegin<S, L>(shape); 781 } 782 783 template <class CT> 784 template <class S, layout_type L> rend(const S & shape) const785 inline auto xscalar<CT>::rend(const S& shape) const noexcept -> const_reverse_broadcast_iterator<S, L> 786 { 787 return iterable_base::template rend<S, L>(shape); 788 } 789 790 template <class CT> 791 template <class S, layout_type L> crbegin(const S & shape) const792 inline auto xscalar<CT>::crbegin(const S& shape) const noexcept -> const_reverse_broadcast_iterator<S, L> 793 { 794 return iterable_base::template crbegin<S, L>(shape); 795 } 796 797 template <class CT> 798 template <class S, layout_type L> crend(const S & shape) const799 inline auto xscalar<CT>::crend(const S& shape) const noexcept -> const_reverse_broadcast_iterator<S, L> 800 { 801 return iterable_base::template crend<S, L>(shape); 802 } 803 804 template <class CT> storage_begin()805 inline auto xscalar<CT>::storage_begin() noexcept -> iterator 806 { 807 return this->template begin<XTENSOR_DEFAULT_LAYOUT>(); 808 } 809 810 template <class CT> storage_end()811 inline auto xscalar<CT>::storage_end() noexcept -> iterator 812 { 813 return this->template end<XTENSOR_DEFAULT_LAYOUT>(); 814 } 815 816 template <class CT> storage_begin() const817 inline auto xscalar<CT>::storage_begin() const noexcept -> const_iterator 818 { 819 return this->template begin<XTENSOR_DEFAULT_LAYOUT>(); 820 } 821 822 template <class CT> storage_end() const823 inline auto xscalar<CT>::storage_end() const noexcept -> const_iterator 824 { 825 return this->template end<XTENSOR_DEFAULT_LAYOUT>(); 826 } 827 828 template <class CT> storage_cbegin() const829 inline auto xscalar<CT>::storage_cbegin() const noexcept -> const_iterator 830 { 831 return this->template cbegin<XTENSOR_DEFAULT_LAYOUT>(); 832 } 833 834 template <class CT> storage_cend() const835 inline auto xscalar<CT>::storage_cend() const noexcept -> const_iterator 836 { 837 return this->template cend<XTENSOR_DEFAULT_LAYOUT>(); 838 } 839 840 template <class CT> storage_rbegin()841 inline auto xscalar<CT>::storage_rbegin() noexcept -> reverse_iterator 842 { 843 return this->template rbegin<XTENSOR_DEFAULT_LAYOUT>(); 844 } 845 846 template <class CT> storage_rend()847 inline auto xscalar<CT>::storage_rend() noexcept -> reverse_iterator 848 { 849 return this->template rend<XTENSOR_DEFAULT_LAYOUT>(); 850 } 851 852 template <class CT> storage_rbegin() const853 inline auto xscalar<CT>::storage_rbegin() const noexcept -> const_reverse_iterator 854 { 855 return this->template rbegin<XTENSOR_DEFAULT_LAYOUT>(); 856 } 857 858 template <class CT> storage_rend() const859 inline auto xscalar<CT>::storage_rend() const noexcept -> const_reverse_iterator 860 { 861 return this->template rend<XTENSOR_DEFAULT_LAYOUT>(); 862 } 863 864 template <class CT> storage_crbegin() const865 inline auto xscalar<CT>::storage_crbegin() const noexcept -> const_reverse_iterator 866 { 867 return this->template crbegin<XTENSOR_DEFAULT_LAYOUT>(); 868 } 869 870 template <class CT> storage_crend() const871 inline auto xscalar<CT>::storage_crend() const noexcept -> const_reverse_iterator 872 { 873 return this->template crend<XTENSOR_DEFAULT_LAYOUT>(); 874 } 875 876 template <class CT> 877 template <class S> stepper_begin(const S &)878 inline auto xscalar<CT>::stepper_begin(const S&) noexcept -> stepper 879 { 880 return stepper(this, false); 881 } 882 883 template <class CT> 884 template <class S> stepper_end(const S &,layout_type)885 inline auto xscalar<CT>::stepper_end(const S&, layout_type) noexcept -> stepper 886 { 887 return stepper(this); 888 } 889 890 template <class CT> 891 template <class S> stepper_begin(const S &) const892 inline auto xscalar<CT>::stepper_begin(const S&) const noexcept -> const_stepper 893 { 894 return const_stepper(this); 895 } 896 897 template <class CT> 898 template <class S> stepper_end(const S &,layout_type) const899 inline auto xscalar<CT>::stepper_end(const S&, layout_type) const noexcept -> const_stepper 900 { 901 return const_stepper(this); 902 } 903 904 template <class CT> dummy_begin()905 inline auto xscalar<CT>::dummy_begin() noexcept -> dummy_iterator 906 { 907 return dummy_iterator(this); 908 } 909 910 template <class CT> dummy_end()911 inline auto xscalar<CT>::dummy_end() noexcept -> dummy_iterator 912 { 913 return dummy_iterator(this); 914 } 915 916 template <class CT> dummy_begin() const917 inline auto xscalar<CT>::dummy_begin() const noexcept -> const_dummy_iterator 918 { 919 return const_dummy_iterator(this); 920 } 921 922 template <class CT> dummy_end() const923 inline auto xscalar<CT>::dummy_end() const noexcept -> const_dummy_iterator 924 { 925 return const_dummy_iterator(this); 926 } 927 928 template <class CT> data_element(size_type)929 inline auto xscalar<CT>::data_element(size_type) noexcept -> reference 930 { 931 return m_value; 932 } 933 934 template <class CT> data_element(size_type) const935 inline auto xscalar<CT>::data_element(size_type) const noexcept -> const_reference 936 { 937 return m_value; 938 } 939 940 template <class CT> flat(size_type)941 inline auto xscalar<CT>::flat(size_type) noexcept -> reference 942 { 943 return m_value; 944 } 945 946 template <class CT> flat(size_type) const947 inline auto xscalar<CT>::flat(size_type) const noexcept -> const_reference 948 { 949 return m_value; 950 } 951 952 template <class CT> 953 template <class align, class simd> store_simd(size_type,const simd & e)954 inline void xscalar<CT>::store_simd(size_type, const simd& e) 955 { 956 m_value = static_cast<value_type>(e[0]); 957 } 958 959 template <class CT> 960 template <class align, class requested_type, std::size_t N> load_simd(size_type) const961 inline auto xscalar<CT>::load_simd(size_type) const 962 -> xt_simd::simd_return_type<value_type, requested_type> 963 { 964 return xt_simd::broadcast_as<requested_type>(m_value); 965 } 966 967 template <class T> xref(T & t)968 inline xscalar<T&> xref(T& t) 969 { 970 return xscalar<T&>(t); 971 } 972 973 template <class T> xcref(T & t)974 inline xscalar<const T&> xcref(T& t) 975 { 976 return xscalar<const T&>(t); 977 } 978 979 /********************************** 980 * xscalar_stepper implementation * 981 **********************************/ 982 983 template <bool is_const, class CT> xscalar_stepper(storage_type * c)984 inline xscalar_stepper<is_const, CT>::xscalar_stepper(storage_type* c) noexcept 985 : p_c(c) 986 { 987 } 988 989 template <bool is_const, class CT> operator *() const990 inline auto xscalar_stepper<is_const, CT>::operator*() const noexcept -> reference 991 { 992 return p_c->operator()(); 993 } 994 995 template <bool is_const, class CT> step(size_type,size_type)996 inline void xscalar_stepper<is_const, CT>::step(size_type /*dim*/, size_type /*n*/) noexcept 997 { 998 } 999 1000 template <bool is_const, class CT> step_back(size_type,size_type)1001 inline void xscalar_stepper<is_const, CT>::step_back(size_type /*dim*/, size_type /*n*/) noexcept 1002 { 1003 } 1004 1005 template <bool is_const, class CT> reset(size_type)1006 inline void xscalar_stepper<is_const, CT>::reset(size_type /*dim*/) noexcept 1007 { 1008 } 1009 1010 template <bool is_const, class CT> reset_back(size_type)1011 inline void xscalar_stepper<is_const, CT>::reset_back(size_type /*dim*/) noexcept 1012 { 1013 } 1014 1015 template <bool is_const, class CT> to_begin()1016 inline void xscalar_stepper<is_const, CT>::to_begin() noexcept 1017 { 1018 } 1019 1020 template <bool is_const, class CT> to_end(layout_type)1021 inline void xscalar_stepper<is_const, CT>::to_end(layout_type /*l*/) noexcept 1022 { 1023 } 1024 1025 template <bool is_const, class CT> 1026 template <class T> step_simd()1027 inline auto xscalar_stepper<is_const, CT>::step_simd() -> simd_return_type<T> 1028 { 1029 return simd_return_type<T>(p_c->operator()()); 1030 } 1031 1032 template <bool is_const, class CT> step_leading()1033 inline void xscalar_stepper<is_const, CT>::step_leading() 1034 { 1035 } 1036 1037 /********************************** 1038 * xdummy_iterator implementation * 1039 **********************************/ 1040 1041 template <bool is_const, class CT> xdummy_iterator(storage_type * c)1042 inline xdummy_iterator<is_const, CT>::xdummy_iterator(storage_type* c) noexcept 1043 : p_c(c) 1044 { 1045 } 1046 1047 template <bool is_const, class CT> operator ++()1048 inline auto xdummy_iterator<is_const, CT>::operator++() noexcept -> self_type& 1049 { 1050 return *this; 1051 } 1052 1053 template <bool is_const, class CT> operator --()1054 inline auto xdummy_iterator<is_const, CT>::operator--() noexcept -> self_type& 1055 { 1056 return *this; 1057 } 1058 1059 template <bool is_const, class CT> operator +=(difference_type)1060 inline auto xdummy_iterator<is_const, CT>::operator+=(difference_type) noexcept -> self_type& 1061 { 1062 return *this; 1063 } 1064 1065 template <bool is_const, class CT> operator -=(difference_type)1066 inline auto xdummy_iterator<is_const, CT>::operator-=(difference_type) noexcept -> self_type& 1067 { 1068 return *this; 1069 } 1070 1071 template <bool is_const, class CT> operator -(const self_type &) const1072 inline auto xdummy_iterator<is_const, CT>::operator-(const self_type&) const noexcept -> difference_type 1073 { 1074 return 0; 1075 } 1076 1077 template <bool is_const, class CT> operator *() const1078 inline auto xdummy_iterator<is_const, CT>::operator*() const noexcept -> reference 1079 { 1080 return p_c->operator()(); 1081 } 1082 1083 template <bool is_const, class CT> equal(const self_type & rhs) const1084 inline bool xdummy_iterator<is_const, CT>::equal(const self_type& rhs) const noexcept 1085 { 1086 return p_c == rhs.p_c; 1087 } 1088 1089 template <bool is_const, class CT> less_than(const self_type & rhs) const1090 inline bool xdummy_iterator<is_const, CT>::less_than(const self_type& rhs) const noexcept 1091 { 1092 return p_c < rhs.p_c; 1093 } 1094 1095 template <bool is_const, class CT> operator ==(const xdummy_iterator<is_const,CT> & lhs,const xdummy_iterator<is_const,CT> & rhs)1096 inline bool operator==(const xdummy_iterator<is_const, CT>& lhs, 1097 const xdummy_iterator<is_const, CT>& rhs) noexcept 1098 { 1099 return lhs.equal(rhs); 1100 } 1101 1102 template <bool is_const, class CT> operator <(const xdummy_iterator<is_const,CT> & lhs,const xdummy_iterator<is_const,CT> & rhs)1103 inline bool operator<(const xdummy_iterator<is_const, CT>& lhs, 1104 const xdummy_iterator<is_const, CT>& rhs) noexcept 1105 { 1106 return lhs.less_than(rhs); 1107 } 1108 } 1109 1110 #endif 1111