/*************************************************************************** * 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_SEMANTIC_HPP #define XTENSOR_SEMANTIC_HPP #include #include #include "xassign.hpp" #include "xexpression_traits.hpp" namespace xt { namespace detail { template struct is_sharable { static constexpr bool value = true; }; template struct is_sharable> { static constexpr bool value = SH; }; template struct is_sharable> { static constexpr bool value = SH; }; } template using select_expression_base_t = std:: conditional_t::value, xsharable_expression, xexpression>; /** * @class xsemantic_base * @brief Base interface for assignable xexpressions. * * The xsemantic_base class defines the interface for assignable * xexpressions. * * @tparam D The derived type, i.e. the inheriting class for which xsemantic_base * provides the interface. */ template class xsemantic_base : public select_expression_base_t { public: using base_type = select_expression_base_t; using derived_type = typename base_type::derived_type; using temporary_type = typename xcontainer_inner_types::temporary_type; template disable_xexpression operator+=(const E&); template disable_xexpression operator-=(const E&); template disable_xexpression operator*=(const E&); template disable_xexpression operator/=(const E&); template disable_xexpression operator%=(const E&); template disable_xexpression operator&=(const E&); template disable_xexpression operator|=(const E&); template disable_xexpression operator^=(const E&); template derived_type& operator+=(const xexpression&); template derived_type& operator-=(const xexpression&); template derived_type& operator*=(const xexpression&); template derived_type& operator/=(const xexpression&); template derived_type& operator%=(const xexpression&); template derived_type& operator&=(const xexpression&); template derived_type& operator|=(const xexpression&); template derived_type& operator^=(const xexpression&); template derived_type& assign(const xexpression&); template derived_type& plus_assign(const xexpression&); template derived_type& minus_assign(const xexpression&); template derived_type& multiplies_assign(const xexpression&); template derived_type& divides_assign(const xexpression&); template derived_type& modulus_assign(const xexpression&); template derived_type& bit_and_assign(const xexpression&); template derived_type& bit_or_assign(const xexpression&); template derived_type& bit_xor_assign(const xexpression&); protected: xsemantic_base() = default; ~xsemantic_base() = default; xsemantic_base(const xsemantic_base&) = default; xsemantic_base& operator=(const xsemantic_base&) = default; xsemantic_base(xsemantic_base&&) = default; xsemantic_base& operator=(xsemantic_base&&) = default; template derived_type& operator=(const xexpression&); }; template using is_assignable = is_crtp_base_of; template using enable_assignable = typename std::enable_if::value, R>::type; template using disable_assignable = typename std::enable_if::value, R>::type; /** * @class xcontainer_semantic * @brief Implementation of the xsemantic_base interface * for dense multidimensional containers. * * The xcontainer_semantic class is an implementation of the * xsemantic_base interface for dense multidimensional * containers. * * @tparam D the derived type */ template class xcontainer_semantic : public xsemantic_base { public: using base_type = xsemantic_base; using derived_type = D; using temporary_type = typename base_type::temporary_type; derived_type& assign_temporary(temporary_type&&); template derived_type& assign_xexpression(const xexpression& e); template derived_type& computed_assign(const xexpression& e); template derived_type& scalar_computed_assign(const E& e, F&& f); protected: xcontainer_semantic() = default; ~xcontainer_semantic() = default; xcontainer_semantic(const xcontainer_semantic&) = default; xcontainer_semantic& operator=(const xcontainer_semantic&) = default; xcontainer_semantic(xcontainer_semantic&&) = default; xcontainer_semantic& operator=(xcontainer_semantic&&) = default; template derived_type& operator=(const xexpression&); }; template using has_container_semantics = is_crtp_base_of; template using enable_xcontainer_semantics = typename std::enable_if::value, R>::type; template using disable_xcontainer_semantics = typename std::enable_if::value, R>::type; template class xview_semantic; template struct overlapping_memory_checker_traits< E, std::enable_if_t::value && is_crtp_base_of::value>> { static bool check_overlap(const E& expr, const memory_range& dst_range) { if (expr.size() == 0) { return false; } else { using ChildE = std::decay_t; return overlapping_memory_checker_traits::check_overlap(expr.expression(), dst_range); } } }; /** * @class xview_semantic * @brief Implementation of the xsemantic_base interface for * multidimensional views * * The xview_semantic is an implementation of the xsemantic_base * interface for multidimensional views. * * @tparam D the derived type */ template class xview_semantic : public xsemantic_base { public: using base_type = xsemantic_base; using derived_type = D; using temporary_type = typename base_type::temporary_type; derived_type& assign_temporary(temporary_type&&); template derived_type& assign_xexpression(const xexpression& e); template derived_type& computed_assign(const xexpression& e); template derived_type& scalar_computed_assign(const E& e, F&& f); protected: xview_semantic() = default; ~xview_semantic() = default; xview_semantic(const xview_semantic&) = default; xview_semantic& operator=(const xview_semantic&) = default; xview_semantic(xview_semantic&&) = default; xview_semantic& operator=(xview_semantic&&) = default; template derived_type& operator=(const xexpression&); }; template using has_view_semantics = is_crtp_base_of; template using enable_xview_semantics = typename std::enable_if::value, R>::type; template using disable_xview_semantics = typename std::enable_if::value, R>::type; /********************************* * xsemantic_base implementation * *********************************/ /** * @name Computed assignement */ //@{ /** * Adds the scalar \c e to \c *this. * @param e the scalar to add. * @return a reference to \c *this. */ template template inline auto xsemantic_base::operator+=(const E& e) -> disable_xexpression { return this->derived_cast().scalar_computed_assign(e, std::plus<>()); } /** * Subtracts the scalar \c e from \c *this. * @param e the scalar to subtract. * @return a reference to \c *this. */ template template inline auto xsemantic_base::operator-=(const E& e) -> disable_xexpression { return this->derived_cast().scalar_computed_assign(e, std::minus<>()); } /** * Multiplies \c *this with the scalar \c e. * @param e the scalar involved in the operation. * @return a reference to \c *this. */ template template inline auto xsemantic_base::operator*=(const E& e) -> disable_xexpression { return this->derived_cast().scalar_computed_assign(e, std::multiplies<>()); } /** * Divides \c *this by the scalar \c e. * @param e the scalar involved in the operation. * @return a reference to \c *this. */ template template inline auto xsemantic_base::operator/=(const E& e) -> disable_xexpression { return this->derived_cast().scalar_computed_assign(e, std::divides<>()); } /** * Computes the remainder of \c *this after division by the scalar \c e. * @param e the scalar involved in the operation. * @return a reference to \c *this. */ template template inline auto xsemantic_base::operator%=(const E& e) -> disable_xexpression { return this->derived_cast().scalar_computed_assign(e, std::modulus<>()); } /** * Computes the bitwise and of \c *this and the scalar \c e and assigns it to \c *this. * @param e the scalar involved in the operation. * @return a reference to \c *this. */ template template inline auto xsemantic_base::operator&=(const E& e) -> disable_xexpression { return this->derived_cast().scalar_computed_assign(e, std::bit_and<>()); } /** * Computes the bitwise or of \c *this and the scalar \c e and assigns it to \c *this. * @param e the scalar involved in the operation. * @return a reference to \c *this. */ template template inline auto xsemantic_base::operator|=(const E& e) -> disable_xexpression { return this->derived_cast().scalar_computed_assign(e, std::bit_or<>()); } /** * Computes the bitwise xor of \c *this and the scalar \c e and assigns it to \c *this. * @param e the scalar involved in the operation. * @return a reference to \c *this. */ template template inline auto xsemantic_base::operator^=(const E& e) -> disable_xexpression { return this->derived_cast().scalar_computed_assign(e, std::bit_xor<>()); } /** * Adds the xexpression \c e to \c *this. * @param e the xexpression to add. * @return a reference to \c *this. */ template template inline auto xsemantic_base::operator+=(const xexpression& e) -> derived_type& { return this->derived_cast() = this->derived_cast() + e.derived_cast(); } /** * Subtracts the xexpression \c e from \c *this. * @param e the xexpression to subtract. * @return a reference to \c *this. */ template template inline auto xsemantic_base::operator-=(const xexpression& e) -> derived_type& { return this->derived_cast() = this->derived_cast() - e.derived_cast(); } /** * Multiplies \c *this with the xexpression \c e. * @param e the xexpression involved in the operation. * @return a reference to \c *this. */ template template inline auto xsemantic_base::operator*=(const xexpression& e) -> derived_type& { return this->derived_cast() = this->derived_cast() * e.derived_cast(); } /** * Divides \c *this by the xexpression \c e. * @param e the xexpression involved in the operation. * @return a reference to \c *this. */ template template inline auto xsemantic_base::operator/=(const xexpression& e) -> derived_type& { return this->derived_cast() = this->derived_cast() / e.derived_cast(); } /** * Computes the remainder of \c *this after division by the xexpression \c e. * @param e the xexpression involved in the operation. * @return a reference to \c *this. */ template template inline auto xsemantic_base::operator%=(const xexpression& e) -> derived_type& { return this->derived_cast() = this->derived_cast() % e.derived_cast(); } /** * Computes the bitwise and of \c *this and the xexpression \c e and assigns it to \c *this. * @param e the xexpression involved in the operation. * @return a reference to \c *this. */ template template inline auto xsemantic_base::operator&=(const xexpression& e) -> derived_type& { return this->derived_cast() = this->derived_cast() & e.derived_cast(); } /** * Computes the bitwise or of \c *this and the xexpression \c e and assigns it to \c *this. * @param e the xexpression involved in the operation. * @return a reference to \c *this. */ template template inline auto xsemantic_base::operator|=(const xexpression& e) -> derived_type& { return this->derived_cast() = this->derived_cast() | e.derived_cast(); } /** * Computes the bitwise xor of \c *this and the xexpression \c e and assigns it to \c *this. * @param e the xexpression involved in the operation. * @return a reference to \c *this. */ template template inline auto xsemantic_base::operator^=(const xexpression& e) -> derived_type& { return this->derived_cast() = this->derived_cast() ^ e.derived_cast(); } //@} /** * @name Assign functions */ /** * Assigns the xexpression \c e to \c *this. Ensures no temporary * will be used to perform the assignment. * @param e the xexpression to assign. * @return a reference to \c *this. */ template template inline auto xsemantic_base::assign(const xexpression& e) -> derived_type& { return this->derived_cast().assign_xexpression(e); } /** * Adds the xexpression \c e to \c *this. Ensures no temporary * will be used to perform the assignment. * @param e the xexpression to add. * @return a reference to \c *this. */ template template inline auto xsemantic_base::plus_assign(const xexpression& e) -> derived_type& { return this->derived_cast().computed_assign(this->derived_cast() + e.derived_cast()); } /** * Subtracts the xexpression \c e to \c *this. Ensures no temporary * will be used to perform the assignment. * @param e the xexpression to subtract. * @return a reference to \c *this. */ template template inline auto xsemantic_base::minus_assign(const xexpression& e) -> derived_type& { return this->derived_cast().computed_assign(this->derived_cast() - e.derived_cast()); } /** * Multiplies \c *this with the xexpression \c e. Ensures no temporary * will be used to perform the assignment. * @param e the xexpression involved in the operation. * @return a reference to \c *this. */ template template inline auto xsemantic_base::multiplies_assign(const xexpression& e) -> derived_type& { return this->derived_cast().computed_assign(this->derived_cast() * e.derived_cast()); } /** * Divides \c *this by the xexpression \c e. Ensures no temporary * will be used to perform the assignment. * @param e the xexpression involved in the operation. * @return a reference to \c *this. */ template template inline auto xsemantic_base::divides_assign(const xexpression& e) -> derived_type& { return this->derived_cast().computed_assign(this->derived_cast() / e.derived_cast()); } /** * Computes the remainder of \c *this after division by the xexpression \c e. * Ensures no temporary will be used to perform the assignment. * @param e the xexpression involved in the operation. * @return a reference to \c *this. */ template template inline auto xsemantic_base::modulus_assign(const xexpression& e) -> derived_type& { return this->derived_cast().computed_assign(this->derived_cast() % e.derived_cast()); } /** * Computes the bitwise and of \c e to \c *this. Ensures no temporary * will be used to perform the assignment. * @param e the xexpression to add. * @return a reference to \c *this. */ template template inline auto xsemantic_base::bit_and_assign(const xexpression& e) -> derived_type& { return this->derived_cast().computed_assign(this->derived_cast() & e.derived_cast()); } /** * Computes the bitwise or of \c e to \c *this. Ensures no temporary * will be used to perform the assignment. * @param e the xexpression to add. * @return a reference to \c *this. */ template template inline auto xsemantic_base::bit_or_assign(const xexpression& e) -> derived_type& { return this->derived_cast().computed_assign(this->derived_cast() | e.derived_cast()); } /** * Computes the bitwise xor of \c e to \c *this. Ensures no temporary * will be used to perform the assignment. * @param e the xexpression to add. * @return a reference to \c *this. */ template template inline auto xsemantic_base::bit_xor_assign(const xexpression& e) -> derived_type& { return this->derived_cast().computed_assign(this->derived_cast() ^ e.derived_cast()); } template template inline auto xsemantic_base::operator=(const xexpression& e) -> derived_type& { #ifdef XTENSOR_FORCE_TEMPORARY_MEMORY_IN_ASSIGNMENTS temporary_type tmp(e); return this->derived_cast().assign_temporary(std::move(tmp)); #else auto&& this_derived = this->derived_cast(); auto memory_checker = make_overlapping_memory_checker(this_derived); if (memory_checker.check_overlap(e.derived_cast())) { temporary_type tmp(e); return this_derived.assign_temporary(std::move(tmp)); } else { return this->assign(e); } #endif } /************************************** * xcontainer_semantic implementation * **************************************/ /** * Assigns the temporary \c tmp to \c *this. * @param tmp the temporary to assign. * @return a reference to \c *this. */ template inline auto xcontainer_semantic::assign_temporary(temporary_type&& tmp) -> derived_type& { return (this->derived_cast() = std::move(tmp)); } template template inline auto xcontainer_semantic::assign_xexpression(const xexpression& e) -> derived_type& { xt::assign_xexpression(*this, e); return this->derived_cast(); } template template inline auto xcontainer_semantic::computed_assign(const xexpression& e) -> derived_type& { xt::computed_assign(*this, e); return this->derived_cast(); } template template inline auto xcontainer_semantic::scalar_computed_assign(const E& e, F&& f) -> derived_type& { xt::scalar_computed_assign(*this, e, std::forward(f)); return this->derived_cast(); } template template inline auto xcontainer_semantic::operator=(const xexpression& e) -> derived_type& { return base_type::operator=(e); } /********************************* * xview_semantic implementation * *********************************/ /** * Assigns the temporary \c tmp to \c *this. * @param tmp the temporary to assign. * @return a reference to \c *this. */ template inline auto xview_semantic::assign_temporary(temporary_type&& tmp) -> derived_type& { this->derived_cast().assign_temporary_impl(std::move(tmp)); return this->derived_cast(); } namespace detail { template bool get_rhs_triviality(const F&) { return true; } template bool get_rhs_triviality(const xfunction& rhs) { using index_type = xindex_type_t::shape_type>; using size_type = typename index_type::size_type; size_type size = rhs.dimension(); index_type shape = uninitialized_shape(size); bool trivial_broadcast = rhs.broadcast_shape(shape, true); return trivial_broadcast; } } template template inline auto xview_semantic::assign_xexpression(const xexpression& e) -> derived_type& { xt::assert_compatible_shape(*this, e); xt::assign_data(*this, e, detail::get_rhs_triviality(e.derived_cast())); return this->derived_cast(); } template template inline auto xview_semantic::computed_assign(const xexpression& e) -> derived_type& { xt::assert_compatible_shape(*this, e); xt::assign_data(*this, e, detail::get_rhs_triviality(e.derived_cast())); return this->derived_cast(); } namespace xview_semantic_detail { template auto get_begin(D&& lhs, std::true_type) { return lhs.linear_begin(); } template auto get_begin(D&& lhs, std::false_type) { return lhs.begin(); } } template template inline auto xview_semantic::scalar_computed_assign(const E& e, F&& f) -> derived_type& { D& d = this->derived_cast(); using size_type = typename D::size_type; auto dst = xview_semantic_detail::get_begin(d, std::integral_constant()); for (size_type i = d.size(); i > 0; --i) { *dst = f(*dst, e); ++dst; } return this->derived_cast(); } template template inline auto xview_semantic::operator=(const xexpression& rhs) -> derived_type& { bool cond = (rhs.derived_cast().shape().size() == this->derived_cast().dimension()) && std::equal( this->derived_cast().shape().begin(), this->derived_cast().shape().end(), rhs.derived_cast().shape().begin() ); if (!cond) { base_type::operator=(broadcast(rhs.derived_cast(), this->derived_cast().shape())); } else { base_type::operator=(rhs); } return this->derived_cast(); } } #endif