/*************************************************************************** * Copyright (c) Johan Mabille, Sylvain Corlay and Wolf Vollprecht * * Copyright (c) QuantStack * * * * Distributed under the terms of the BSD 3-Clause License. * * * * The full license is in the file LICENSE, distributed with this software. * ****************************************************************************/ #ifndef XTENSOR_SCALAR_HPP #define XTENSOR_SCALAR_HPP #include #include #include #include #include "xaccessible.hpp" #include "xexpression.hpp" #include "xiterable.hpp" #include "xlayout.hpp" #include "xtensor_simd.hpp" namespace xt { /********************* * xscalar extension * *********************/ namespace extension { template struct xscalar_base_impl; template struct xscalar_base_impl { using type = xtensor_empty_base; }; template struct xscalar_base : xscalar_base_impl>, CT> { }; template using xscalar_base_t = typename xscalar_base::type; } /*********** * xscalar * ***********/ // xscalar is a cheap wrapper for a scalar value as an xexpression. template class xscalar; template class xscalar_stepper; template class xdummy_iterator; template struct xiterable_inner_types> { using value_type = std::decay_t; using inner_shape_type = std::array; using shape_type = inner_shape_type; using const_stepper = xscalar_stepper; using stepper = xscalar_stepper; }; template struct xcontainer_inner_types> { using value_type = std::decay_t; using reference = value_type&; using const_reference = const value_type&; using size_type = std::size_t; }; template class xscalar : public xsharable_expression>, private xiterable>, private xaccessible>, public extension::xscalar_base_t { public: using self_type = xscalar; using xexpression_type = std::decay_t; using extension_base = extension::xscalar_base_t; using accessible_base = xaccessible; using expression_tag = typename extension_base::expression_tag; using inner_types = xcontainer_inner_types; using value_type = typename inner_types::value_type; using reference = typename inner_types::reference; using const_reference = typename inner_types::const_reference; using pointer = value_type*; using const_pointer = const value_type*; using size_type = typename inner_types::size_type; using difference_type = std::ptrdiff_t; using simd_value_type = xt_simd::simd_type; using bool_load_type = xt::bool_load_type; using iterable_base = xiterable; using inner_shape_type = typename iterable_base::inner_shape_type; using shape_type = inner_shape_type; using stepper = typename iterable_base::stepper; using const_stepper = typename iterable_base::const_stepper; template using layout_iterator = typename iterable_base::template layout_iterator; template using const_layout_iterator = typename iterable_base::template const_layout_iterator; template using reverse_layout_iterator = typename iterable_base::template reverse_layout_iterator; template using const_reverse_layout_iterator = typename iterable_base::template const_reverse_layout_iterator; template using broadcast_iterator = typename iterable_base::template broadcast_iterator; template using const_broadcast_iterator = typename iterable_base::template const_broadcast_iterator; template using reverse_broadcast_iterator = typename iterable_base::template reverse_broadcast_iterator; template using const_reverse_broadcast_iterator = typename iterable_base::template const_reverse_broadcast_iterator; using iterator = value_type*; using const_iterator = const value_type*; using reverse_iterator = std::reverse_iterator; using const_reverse_iterator = std::reverse_iterator; using dummy_iterator = xdummy_iterator; using const_dummy_iterator = xdummy_iterator; static constexpr layout_type static_layout = layout_type::any; static constexpr bool contiguous_layout = true; xscalar() noexcept; xscalar(CT value) noexcept; operator value_type&() noexcept; operator const value_type&() const noexcept; size_type size() const noexcept; const shape_type& shape() const noexcept; size_type shape(size_type i) const noexcept; layout_type layout() const noexcept; bool is_contiguous() const noexcept; using accessible_base::dimension; using accessible_base::shape; template reference operator()(Args...) noexcept; template reference unchecked(Args...) noexcept; template const_reference operator()(Args...) const noexcept; template const_reference unchecked(Args...) const noexcept; using accessible_base::at; using accessible_base::operator[]; using accessible_base::back; using accessible_base::front; using accessible_base::in_bounds; using accessible_base::periodic; template reference element(It, It) noexcept; template const_reference element(It, It) const noexcept; xexpression_type& expression() noexcept; const xexpression_type& expression() const noexcept; template bool broadcast_shape(S& shape, bool reuse_cache = false) const noexcept; template bool has_linear_assign(const S& strides) const noexcept; template iterator begin() noexcept; template iterator end() noexcept; template const_iterator begin() const noexcept; template const_iterator end() const noexcept; template const_iterator cbegin() const noexcept; template const_iterator cend() const noexcept; template reverse_iterator rbegin() noexcept; template reverse_iterator rend() noexcept; template const_reverse_iterator rbegin() const noexcept; template const_reverse_iterator rend() const noexcept; template const_reverse_iterator crbegin() const noexcept; template const_reverse_iterator crend() const noexcept; template broadcast_iterator begin(const S& shape) noexcept; template broadcast_iterator end(const S& shape) noexcept; template const_broadcast_iterator begin(const S& shape) const noexcept; template const_broadcast_iterator end(const S& shape) const noexcept; template const_broadcast_iterator cbegin(const S& shape) const noexcept; template const_broadcast_iterator cend(const S& shape) const noexcept; template reverse_broadcast_iterator rbegin(const S& shape) noexcept; template reverse_broadcast_iterator rend(const S& shape) noexcept; template const_reverse_broadcast_iterator rbegin(const S& shape) const noexcept; template const_reverse_broadcast_iterator rend(const S& shape) const noexcept; template const_reverse_broadcast_iterator crbegin(const S& shape) const noexcept; template const_reverse_broadcast_iterator crend(const S& shape) const noexcept; iterator linear_begin() noexcept; iterator linear_end() noexcept; const_iterator linear_begin() const noexcept; const_iterator linear_end() const noexcept; const_iterator linear_cbegin() const noexcept; const_iterator linear_cend() const noexcept; reverse_iterator linear_rbegin() noexcept; reverse_iterator linear_rend() noexcept; const_reverse_iterator linear_rbegin() const noexcept; const_reverse_iterator linear_rend() const noexcept; const_reverse_iterator linear_crbegin() const noexcept; const_reverse_iterator linear_crend() const noexcept; template stepper stepper_begin(const S& shape) noexcept; template stepper stepper_end(const S& shape, layout_type l) noexcept; template const_stepper stepper_begin(const S& shape) const noexcept; template const_stepper stepper_end(const S& shape, layout_type l) const noexcept; dummy_iterator dummy_begin() noexcept; dummy_iterator dummy_end() noexcept; const_dummy_iterator dummy_begin() const noexcept; const_dummy_iterator dummy_end() const noexcept; reference data_element(size_type i) noexcept; const_reference data_element(size_type i) const noexcept; reference flat(size_type i) noexcept; const_reference flat(size_type i) const noexcept; template void store_simd(size_type i, const simd& e); template ::size> xt_simd::simd_return_type load_simd(size_type i) const; private: CT m_value; friend class xconst_iterable; friend class xiterable; friend class xaccessible; friend class xconst_accessible; }; namespace detail { template struct is_xscalar_impl : std::false_type { }; template struct is_xscalar_impl> : std::true_type { }; } template using is_xscalar = detail::is_xscalar_impl; namespace detail { template struct all_xscalar { static constexpr bool value = xtl::conjunction>...>::value; }; } // Note: MSVC bug workaround. Cannot just define // template // using all_xscalar = xtl::conjunction>...>; template using all_xscalar = detail::all_xscalar; /****************** * xref and xcref * ******************/ template xscalar xref(T& t); template xscalar xcref(T& t); /******************* * xscalar_stepper * *******************/ template class xscalar_stepper { public: using self_type = xscalar_stepper; using storage_type = std::conditional_t, xscalar>; using value_type = typename storage_type::value_type; using reference = std:: conditional_t; using pointer = std::conditional_t; using size_type = typename storage_type::size_type; using difference_type = typename storage_type::difference_type; using shape_type = typename storage_type::shape_type; template using simd_return_type = xt_simd::simd_return_type; xscalar_stepper(storage_type* c) noexcept; reference operator*() const noexcept; void step(size_type dim, size_type n = 1) noexcept; void step_back(size_type dim, size_type n = 1) noexcept; void reset(size_type dim) noexcept; void reset_back(size_type dim) noexcept; void to_begin() noexcept; void to_end(layout_type l) noexcept; template simd_return_type step_simd(); void step_leading(); private: storage_type* p_c; }; /******************* * xdummy_iterator * *******************/ namespace detail { template using dummy_reference_t = std:: conditional_t::const_reference, typename xscalar::reference>; template using dummy_pointer_t = std:: conditional_t::const_pointer, typename xscalar::pointer>; } template class xdummy_iterator : public xtl::xrandom_access_iterator_base< xdummy_iterator, typename xscalar::value_type, typename xscalar::difference_type, detail::dummy_pointer_t, detail::dummy_reference_t> { public: using self_type = xdummy_iterator; using storage_type = std::conditional_t, xscalar>; using value_type = typename storage_type::value_type; using reference = detail::dummy_reference_t; using pointer = detail::dummy_pointer_t; using difference_type = typename storage_type::difference_type; using iterator_category = std::random_access_iterator_tag; explicit xdummy_iterator(storage_type* c) noexcept; self_type& operator++() noexcept; self_type& operator--() noexcept; self_type& operator+=(difference_type n) noexcept; self_type& operator-=(difference_type n) noexcept; difference_type operator-(const self_type& rhs) const noexcept; reference operator*() const noexcept; bool equal(const self_type& rhs) const noexcept; bool less_than(const self_type& rhs) const noexcept; private: storage_type* p_c; }; template bool operator==(const xdummy_iterator& lhs, const xdummy_iterator& rhs) noexcept; template bool operator<(const xdummy_iterator& lhs, const xdummy_iterator& rhs) noexcept; template struct is_not_xdummy_iterator : std::true_type { }; template struct is_not_xdummy_iterator> : std::false_type { }; /***************************** * linear_begin / linear_end * *****************************/ template XTENSOR_CONSTEXPR_RETURN auto linear_begin(xscalar& c) noexcept -> decltype(c.dummy_begin()) { return c.dummy_begin(); } template XTENSOR_CONSTEXPR_RETURN auto linear_end(xscalar& c) noexcept -> decltype(c.dummy_end()) { return c.dummy_end(); } template XTENSOR_CONSTEXPR_RETURN auto linear_begin(const xscalar& c) noexcept -> decltype(c.dummy_begin()) { return c.dummy_begin(); } template XTENSOR_CONSTEXPR_RETURN auto linear_end(const xscalar& c) noexcept -> decltype(c.dummy_end()) { return c.dummy_end(); } /************************** * xscalar implementation * **************************/ // This constructor will not compile when CT is a reference type. template inline xscalar::xscalar() noexcept : m_value() { } template inline xscalar::xscalar(CT value) noexcept : m_value(value) { } template inline xscalar::operator value_type&() noexcept { return m_value; } template inline xscalar::operator const value_type&() const noexcept { return m_value; } template inline auto xscalar::size() const noexcept -> size_type { return 1; } template inline auto xscalar::shape() const noexcept -> const shape_type& { static std::array zero_shape; return zero_shape; } template inline auto xscalar::shape(size_type) const noexcept -> size_type { return 0; } template inline layout_type xscalar::layout() const noexcept { return static_layout; } template inline bool xscalar::is_contiguous() const noexcept { return true; } template template inline auto xscalar::operator()(Args...) noexcept -> reference { XTENSOR_CHECK_DIMENSION((std::array()), Args()...); return m_value; } template template inline auto xscalar::unchecked(Args...) noexcept -> reference { return m_value; } template template inline auto xscalar::operator()(Args...) const noexcept -> const_reference { XTENSOR_CHECK_DIMENSION((std::array()), Args()...); return m_value; } template template inline auto xscalar::unchecked(Args...) const noexcept -> const_reference { return m_value; } template template inline auto xscalar::element(It, It) noexcept -> reference { return m_value; } template template inline auto xscalar::element(It, It) const noexcept -> const_reference { return m_value; } template inline auto xscalar::expression() noexcept -> xexpression_type& { return m_value; } template inline auto xscalar::expression() const noexcept -> const xexpression_type& { return m_value; } template template inline bool xscalar::broadcast_shape(S&, bool) const noexcept { return true; } template template inline bool xscalar::has_linear_assign(const S&) const noexcept { return true; } template template inline auto xscalar::begin() noexcept -> iterator { return &m_value; } template template inline auto xscalar::end() noexcept -> iterator { return &m_value + 1; } template template inline auto xscalar::begin() const noexcept -> const_iterator { return &m_value; } template template inline auto xscalar::end() const noexcept -> const_iterator { return &m_value + 1; } template template inline auto xscalar::cbegin() const noexcept -> const_iterator { return &m_value; } template template inline auto xscalar::cend() const noexcept -> const_iterator { return &m_value + 1; } template template inline auto xscalar::rbegin() noexcept -> reverse_iterator { return reverse_iterator(end()); } template template inline auto xscalar::rend() noexcept -> reverse_iterator { return reverse_iterator(begin()); } template template inline auto xscalar::rbegin() const noexcept -> const_reverse_iterator { return crbegin(); } template template inline auto xscalar::rend() const noexcept -> const_reverse_iterator { return crend(); } template template inline auto xscalar::crbegin() const noexcept -> const_reverse_iterator { return const_reverse_iterator(cend()); } template template inline auto xscalar::crend() const noexcept -> const_reverse_iterator { return const_reverse_iterator(cbegin()); } /***************************** * Broadcasting iterator api * *****************************/ template template inline auto xscalar::begin(const S& shape) noexcept -> broadcast_iterator { return iterable_base::template begin(shape); } template template inline auto xscalar::end(const S& shape) noexcept -> broadcast_iterator { return iterable_base::template end(shape); } template template inline auto xscalar::begin(const S& shape) const noexcept -> const_broadcast_iterator { return iterable_base::template begin(shape); } template template inline auto xscalar::end(const S& shape) const noexcept -> const_broadcast_iterator { return iterable_base::template end(shape); } template template inline auto xscalar::cbegin(const S& shape) const noexcept -> const_broadcast_iterator { return iterable_base::template cbegin(shape); } template template inline auto xscalar::cend(const S& shape) const noexcept -> const_broadcast_iterator { return iterable_base::template cend(shape); } template template inline auto xscalar::rbegin(const S& shape) noexcept -> reverse_broadcast_iterator { return iterable_base::template rbegin(shape); } template template inline auto xscalar::rend(const S& shape) noexcept -> reverse_broadcast_iterator { return iterable_base::template rend(shape); } template template inline auto xscalar::rbegin(const S& shape) const noexcept -> const_reverse_broadcast_iterator { return iterable_base::template rbegin(shape); } template template inline auto xscalar::rend(const S& shape) const noexcept -> const_reverse_broadcast_iterator { return iterable_base::template rend(shape); } template template inline auto xscalar::crbegin(const S& shape) const noexcept -> const_reverse_broadcast_iterator { return iterable_base::template crbegin(shape); } template template inline auto xscalar::crend(const S& shape) const noexcept -> const_reverse_broadcast_iterator { return iterable_base::template crend(shape); } template inline auto xscalar::linear_begin() noexcept -> iterator { return this->template begin(); } template inline auto xscalar::linear_end() noexcept -> iterator { return this->template end(); } template inline auto xscalar::linear_begin() const noexcept -> const_iterator { return this->template begin(); } template inline auto xscalar::linear_end() const noexcept -> const_iterator { return this->template end(); } template inline auto xscalar::linear_cbegin() const noexcept -> const_iterator { return this->template cbegin(); } template inline auto xscalar::linear_cend() const noexcept -> const_iterator { return this->template cend(); } template inline auto xscalar::linear_rbegin() noexcept -> reverse_iterator { return this->template rbegin(); } template inline auto xscalar::linear_rend() noexcept -> reverse_iterator { return this->template rend(); } template inline auto xscalar::linear_rbegin() const noexcept -> const_reverse_iterator { return this->template rbegin(); } template inline auto xscalar::linear_rend() const noexcept -> const_reverse_iterator { return this->template rend(); } template inline auto xscalar::linear_crbegin() const noexcept -> const_reverse_iterator { return this->template crbegin(); } template inline auto xscalar::linear_crend() const noexcept -> const_reverse_iterator { return this->template crend(); } template template inline auto xscalar::stepper_begin(const S&) noexcept -> stepper { return stepper(this, false); } template template inline auto xscalar::stepper_end(const S&, layout_type) noexcept -> stepper { return stepper(this); } template template inline auto xscalar::stepper_begin(const S&) const noexcept -> const_stepper { return const_stepper(this); } template template inline auto xscalar::stepper_end(const S&, layout_type) const noexcept -> const_stepper { return const_stepper(this); } template inline auto xscalar::dummy_begin() noexcept -> dummy_iterator { return dummy_iterator(this); } template inline auto xscalar::dummy_end() noexcept -> dummy_iterator { return dummy_iterator(this); } template inline auto xscalar::dummy_begin() const noexcept -> const_dummy_iterator { return const_dummy_iterator(this); } template inline auto xscalar::dummy_end() const noexcept -> const_dummy_iterator { return const_dummy_iterator(this); } template inline auto xscalar::data_element(size_type) noexcept -> reference { return m_value; } template inline auto xscalar::data_element(size_type) const noexcept -> const_reference { return m_value; } template inline auto xscalar::flat(size_type) noexcept -> reference { return m_value; } template inline auto xscalar::flat(size_type) const noexcept -> const_reference { return m_value; } template template inline void xscalar::store_simd(size_type, const simd& e) { m_value = static_cast(e[0]); } template template inline auto xscalar::load_simd(size_type) const -> xt_simd::simd_return_type { return xt_simd::broadcast_as(m_value); } template inline xscalar xref(T& t) { return xscalar(t); } template inline xscalar xcref(T& t) { return xscalar(t); } /********************************** * xscalar_stepper implementation * **********************************/ template inline xscalar_stepper::xscalar_stepper(storage_type* c) noexcept : p_c(c) { } template inline auto xscalar_stepper::operator*() const noexcept -> reference { return p_c->operator()(); } template inline void xscalar_stepper::step(size_type /*dim*/, size_type /*n*/) noexcept { } template inline void xscalar_stepper::step_back(size_type /*dim*/, size_type /*n*/) noexcept { } template inline void xscalar_stepper::reset(size_type /*dim*/) noexcept { } template inline void xscalar_stepper::reset_back(size_type /*dim*/) noexcept { } template inline void xscalar_stepper::to_begin() noexcept { } template inline void xscalar_stepper::to_end(layout_type /*l*/) noexcept { } template template inline auto xscalar_stepper::step_simd() -> simd_return_type { return simd_return_type(p_c->operator()()); } template inline void xscalar_stepper::step_leading() { } /********************************** * xdummy_iterator implementation * **********************************/ template inline xdummy_iterator::xdummy_iterator(storage_type* c) noexcept : p_c(c) { } template inline auto xdummy_iterator::operator++() noexcept -> self_type& { return *this; } template inline auto xdummy_iterator::operator--() noexcept -> self_type& { return *this; } template inline auto xdummy_iterator::operator+=(difference_type) noexcept -> self_type& { return *this; } template inline auto xdummy_iterator::operator-=(difference_type) noexcept -> self_type& { return *this; } template inline auto xdummy_iterator::operator-(const self_type&) const noexcept -> difference_type { return 0; } template inline auto xdummy_iterator::operator*() const noexcept -> reference { return p_c->operator()(); } template inline bool xdummy_iterator::equal(const self_type& rhs) const noexcept { return p_c == rhs.p_c; } template inline bool xdummy_iterator::less_than(const self_type& rhs) const noexcept { return p_c < rhs.p_c; } template inline bool operator==(const xdummy_iterator& lhs, const xdummy_iterator& rhs) noexcept { return lhs.equal(rhs); } template inline bool operator<(const xdummy_iterator& lhs, const xdummy_iterator& rhs) noexcept { return lhs.less_than(rhs); } } #endif