/*************************************************************************** * 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_FUNCTOR_VIEW_HPP #define XTENSOR_FUNCTOR_VIEW_HPP #include #include #include #include #include #include #include "xaccessible.hpp" #include "xarray.hpp" #include "xexpression.hpp" #include "xiterator.hpp" #include "xsemantic.hpp" #include "xtensor.hpp" #include "xutils.hpp" namespace xt { /** * @defgroup xt_xfunctor_view * * Chunked array container. * Defined in ``xtensor/xfunctor_view.hpp`` */ /************************************************ * xfunctor_view and xfunctor_adaptor extension * ************************************************/ namespace extension { template struct xfunctor_view_base_impl; template struct xfunctor_view_base_impl { using type = xtensor_empty_base; }; template struct xfunctor_view_base : xfunctor_view_base_impl, F, CT> { }; template using xfunctor_view_base_t = typename xfunctor_view_base::type; } /************************************* * xfunctor_applier_base declaration * *************************************/ template class xfunctor_iterator; template class xfunctor_stepper; template class xfunctor_applier_base : private xaccessible { public: using self_type = xfunctor_applier_base; using inner_types = xcontainer_inner_types; using xexpression_type = typename inner_types::xexpression_type; using undecay_expression = typename inner_types::undecay_expression; using functor_type = typename inner_types::functor_type; using accessible_base = xaccessible; using extension_base = extension::xfunctor_view_base_t; using expression_tag = typename extension_base::expression_tag; using value_type = typename functor_type::value_type; using reference = typename inner_types::reference; using const_reference = typename inner_types::const_reference; using pointer = typename functor_type::pointer; using const_pointer = typename functor_type::const_pointer; using size_type = typename inner_types::size_type; using difference_type = typename xexpression_type::difference_type; using shape_type = typename xexpression_type::shape_type; using strides_type = xtl::mpl::eval_if_t< has_strides, detail::expr_strides_type, get_strides_type>; using backstrides_type = xtl::mpl::eval_if_t< has_strides, detail::expr_backstrides_type, get_strides_type>; using inner_shape_type = typename xexpression_type::inner_shape_type; using inner_strides_type = xtl::mpl::eval_if_t< has_strides, detail::expr_inner_strides_type, get_strides_type>; using inner_backstrides_type = xtl::mpl::eval_if_t< has_strides, detail::expr_inner_backstrides_type, get_strides_type>; using bool_load_type = xt::bool_load_type; static constexpr layout_type static_layout = xexpression_type::static_layout; static constexpr bool contiguous_layout = xexpression_type::contiguous_layout; using stepper = xfunctor_stepper; using const_stepper = xfunctor_stepper; template using layout_iterator = xfunctor_iterator>; template using const_layout_iterator = xfunctor_iterator< const functor_type, typename xexpression_type::template const_layout_iterator>; template using reverse_layout_iterator = xfunctor_iterator< functor_type, typename xexpression_type::template reverse_layout_iterator>; template using const_reverse_layout_iterator = xfunctor_iterator< const functor_type, typename xexpression_type::template const_reverse_layout_iterator>; template using broadcast_iterator = xfunctor_iterator>; template using const_broadcast_iterator = xfunctor_iterator< functor_type, xiterator>; template using reverse_broadcast_iterator = xfunctor_iterator< functor_type, typename xexpression_type::template reverse_broadcast_iterator>; template using const_reverse_broadcast_iterator = xfunctor_iterator< functor_type, typename xexpression_type::template const_reverse_broadcast_iterator>; using linear_iterator = xfunctor_iterator; using const_linear_iterator = xfunctor_iterator; using reverse_linear_iterator = xfunctor_iterator; using const_reverse_linear_iterator = xfunctor_iterator< const functor_type, typename xexpression_type::const_reverse_linear_iterator>; using iterator = xfunctor_iterator; using const_iterator = xfunctor_iterator; using reverse_iterator = xfunctor_iterator; using const_reverse_iterator = xfunctor_iterator; explicit xfunctor_applier_base(undecay_expression) noexcept; template xfunctor_applier_base(Func&&, E&&) noexcept; size_type size() const noexcept; const inner_shape_type& shape() const noexcept; const inner_strides_type& strides() const noexcept; const inner_backstrides_type& backstrides() const noexcept; using accessible_base::dimension; using accessible_base::shape; layout_type layout() const noexcept; bool is_contiguous() const noexcept; template reference operator()(Args... args); template reference unchecked(Args... args); template reference element(IT first, IT last); template const_reference operator()(Args... args) const; template const_reference unchecked(Args... args) const; template const_reference element(IT first, IT last) const; using accessible_base::at; using accessible_base::operator[]; using accessible_base::back; using accessible_base::front; using accessible_base::periodic; using accessible_base::in_bounds; xexpression_type& expression() noexcept; const xexpression_type& expression() const noexcept; template bool broadcast_shape(S& shape, bool reuse_cache = false) const; template bool has_linear_assign(const S& strides) const; template auto data_element(size_type i) -> decltype(std::declval()(std::declval().data_element(i))) { return m_functor(m_e.data_element(i)); } template auto data_element(size_type i) const -> decltype(std::declval()(std::declval().data_element(i))) { return m_functor(m_e.data_element(i)); } template auto flat(size_type i) -> decltype(std::declval()(std::declval().flat(i))) { return m_functor(m_e.flat(i)); } template auto flat(size_type i) const -> decltype(std::declval()(std::declval().flat(i))) { return m_functor(m_e.flat(i)); } // The following functions are defined inline because otherwise signatures // don't match on GCC. template < class align, class requested_type = typename xexpression_type::value_type, std::size_t N = xt_simd::simd_traits::size, class FCT = functor_type> auto load_simd(size_type i) const -> decltype(std::declval().template proxy_simd_load( std::declval(), i )) { return m_functor.template proxy_simd_load(m_e, i); } template auto store_simd(size_type i, const simd& e) -> decltype(std::declval() .template proxy_simd_store(std::declval(), i, e)) { return m_functor.template proxy_simd_store(m_e, i, e); } template auto begin() noexcept; template auto end() noexcept; template auto begin() const noexcept; template auto end() const noexcept; template auto cbegin() const noexcept; template auto cend() const noexcept; template auto rbegin() noexcept; template auto rend() noexcept; template auto rbegin() const noexcept; template auto rend() const noexcept; template auto crbegin() const noexcept; template auto 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; linear_iterator linear_begin() noexcept; linear_iterator linear_end() noexcept; const_linear_iterator linear_begin() const noexcept; const_linear_iterator linear_end() const noexcept; const_linear_iterator linear_cbegin() const noexcept; const_linear_iterator linear_cend() const noexcept; reverse_linear_iterator linear_rbegin() noexcept; reverse_linear_iterator linear_rend() noexcept; const_reverse_linear_iterator linear_rbegin() const noexcept; const_reverse_linear_iterator linear_rend() const noexcept; const_reverse_linear_iterator linear_crbegin() const noexcept; const_reverse_linear_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; protected: undecay_expression m_e; functor_type m_functor; private: friend class xaccessible; friend class xconst_accessible; }; template struct has_simd_interface, T> : xtl::conjunction< has_simd_type, has_simd_interface::xexpression_type>, detail::has_simd_interface_impl, T>> { }; /******************************** * xfunctor_view_temporary_type * ********************************/ namespace detail { // TODO replace with xexpression_for_shape ... template struct functorview_temporary_type_impl { using type = xarray; }; template struct functorview_temporary_type_impl, L> { using type = xtensor; }; } template struct xfunctor_view_temporary_type { using type = typename detail::functorview_temporary_type_impl::type; }; /***************************** * xfunctor_view declaration * *****************************/ template class xfunctor_view; template struct xcontainer_inner_types> { using xexpression_type = std::decay_t; using undecay_expression = CT; using functor_type = std::decay_t; using reference = decltype(std::declval()(std::declval()())); using const_reference = decltype(std::declval()(std::declval()())); using size_type = typename xexpression_type::size_type; using temporary_type = typename xfunctor_view_temporary_type::type; }; template struct has_simd_interface, T> : has_simd_interface>, T> { }; /** * View of an xexpression . * * The xt::xfunctor_view class is an expression addressing its elements by applying a functor to the * corresponding element of an underlying expression. * Unlike e.g. xgenerator, an xt::xfunctor_view is an lvalue. * It is used e.g. to access real and imaginary parts of complex expressions. * * xt::xfunctor_view has a view semantics and can be used on any expression. * For a similar feature with a container semantics, one can use xt::xfunctor_adaptor. * * xt::xfunctor_view is not meant to be used directly, but through helper functions such * as xt::real or xt::imag. * * @ingroup xt_xfunctor_view * @tparam F the functor type to be applied to the elements of specified expression. * @tparam CT the closure type of the xt::xexpression type underlying this view * @see xt::real, xt::imag */ template class xfunctor_view : public xfunctor_applier_base>, public xview_semantic>, public extension::xfunctor_view_base_t { public: using self_type = xfunctor_view; using semantic_base = xview_semantic; // constructors using xfunctor_applier_base::xfunctor_applier_base; template self_type& operator=(const xexpression& e); template disable_xexpression& operator=(const E& e); template using rebind_t = xfunctor_view; template rebind_t build_functor_view(E&& e) const; private: using temporary_type = typename xcontainer_inner_types::temporary_type; void assign_temporary_impl(temporary_type&& tmp); friend class xview_semantic; friend class xaccessible; }; /******************************** * xfunctor_adaptor declaration * ********************************/ template class xfunctor_adaptor; template struct xcontainer_inner_types> { using xexpression_type = std::decay_t; using undecay_expression = CT; using functor_type = std::decay_t; using reference = typename functor_type::reference; using const_reference = typename functor_type::const_reference; using size_type = typename xexpression_type::size_type; using temporary_type = typename xfunctor_view_temporary_type::type; }; template struct has_simd_interface, T> : has_simd_interface>, T> { }; /** * Adapt a container with a functor, forwarding methods such as resize / reshape. * * xt::xfunctor_adaptor has a container semantics and can only be used with containers. * For a similar feature with a view semantics, one can use xt::xfunctor_view. * * @ingroup xt_xfunctor_view * @tparam F the functor type to be applied to the elements of specified expression. * @tparam CT the closure type of the xt::xexpression type underlying this view * @see xt::xfunctor_view */ template class xfunctor_adaptor : public xfunctor_applier_base>, public xcontainer_semantic>, public extension::xfunctor_view_base_t { public: using self_type = xfunctor_adaptor; using semantic_base = xcontainer_semantic; using xexpression_type = std::decay_t; using base_type = xfunctor_applier_base; using shape_type = typename base_type::shape_type; using strides_type = typename xexpression_type::strides_type; // constructors using xfunctor_applier_base::xfunctor_applier_base; template self_type& operator=(const xexpression& e); template disable_xexpression& operator=(const E& e); template auto resize(S&& shape, bool force = false); template auto resize(S&& shape, layout_type l); template auto resize(S&& shape, const strides_type& strides); template auto& reshape(S&& shape, layout_type layout = base_type::static_layout) &; private: using temporary_type = typename xcontainer_inner_types::temporary_type; void assign_temporary_impl(temporary_type&& tmp); friend class xcontainer_semantic; friend class xaccessible; }; /********************************* * xfunctor_iterator declaration * *********************************/ template struct xproxy_inner_types { using reference = R; using pointer = std::add_pointer_t>; }; namespace detail { template struct xfunctor_invoker { using type = decltype(std::declval()(*(std::declval()))); }; template using xfunctor_invoker_t = typename xfunctor_invoker::type; } template class xfunctor_iterator : public xtl::xrandom_access_iterator_base< xfunctor_iterator, typename std::decay_t::value_type, typename std::iterator_traits::difference_type, typename xproxy_inner_types>::pointer, typename xproxy_inner_types>::reference> { public: using functor_type = F; using subiterator_traits = std::iterator_traits; using proxy_inner = xproxy_inner_types>; using value_type = typename functor_type::value_type; using reference = typename proxy_inner::reference; using pointer = typename proxy_inner::pointer; using difference_type = typename subiterator_traits::difference_type; using iterator_category = typename subiterator_traits::iterator_category; using self_type = xfunctor_iterator; xfunctor_iterator(const IT&, functor_type*); self_type& operator++(); self_type& operator--(); self_type& operator+=(difference_type n); self_type& operator-=(difference_type n); difference_type operator-(xfunctor_iterator rhs) const; reference operator*() const; pointer operator->() const; bool equal(const xfunctor_iterator& rhs) const; bool less_than(const xfunctor_iterator& rhs) const; private: IT m_it; functor_type* p_functor; }; template bool operator==(const xfunctor_iterator& lhs, const xfunctor_iterator& rhs); template bool operator<(const xfunctor_iterator& lhs, const xfunctor_iterator& rhs); /******************************** * xfunctor_stepper declaration * ********************************/ template class xfunctor_stepper { public: using functor_type = F; using proxy_inner = xproxy_inner_types>; using value_type = typename functor_type::value_type; using reference = typename proxy_inner::reference; using pointer = std::remove_reference_t*; using size_type = typename ST::size_type; using difference_type = typename ST::difference_type; using shape_type = typename ST::shape_type; xfunctor_stepper() = default; xfunctor_stepper(const ST&, functor_type*); reference operator*() const; void step(size_type dim); void step_back(size_type dim); void step(size_type dim, size_type n); void step_back(size_type dim, size_type n); void reset(size_type dim); void reset_back(size_type dim); void to_begin(); void to_end(layout_type); private: ST m_stepper; functor_type* p_functor; }; /**************************************** * xfunctor_applier_base implementation * ****************************************/ /** * @name Constructors */ //@{ /** * Constructs an xfunctor_applier_base expression wrappering the specified xt::xexpression. * * @param e the underlying expression */ template inline xfunctor_applier_base::xfunctor_applier_base(undecay_expression e) noexcept : m_e(e) , m_functor(functor_type()) { } /** * Constructs an xfunctor_applier_base expression wrappering the specified xt::xexpression. * * @param func the functor to be applied to the elements of the underlying expression. * @param e the underlying expression */ template template inline xfunctor_applier_base::xfunctor_applier_base(Func&& func, E&& e) noexcept : m_e(std::forward(e)) , m_functor(std::forward(func)) { } //@} /** * @name Size and shape */ /** * Returns the size of the expression. */ template inline auto xfunctor_applier_base::size() const noexcept -> size_type { return m_e.size(); } /** * Returns the shape of the expression. */ template inline auto xfunctor_applier_base::shape() const noexcept -> const inner_shape_type& { return m_e.shape(); } /** * Returns the strides of the expression. */ template inline auto xfunctor_applier_base::strides() const noexcept -> const inner_strides_type& { return m_e.strides(); } /** * Returns the backstrides of the expression. */ template inline auto xfunctor_applier_base::backstrides() const noexcept -> const inner_backstrides_type& { return m_e.backstrides(); } /** * Returns the layout_type of the expression. */ template inline layout_type xfunctor_applier_base::layout() const noexcept { return m_e.layout(); } template inline bool xfunctor_applier_base::is_contiguous() const noexcept { return m_e.is_contiguous(); } //@} /** * @name Data */ /** * Returns a reference to the element at the specified position in the expression. * @param args a list of indices specifying the position in the function. Indices * must be unsigned integers, the number of indices should be equal or greater than * the number of dimensions of the expression. */ template template inline auto xfunctor_applier_base::operator()(Args... args) -> reference { XTENSOR_TRY(check_index(shape(), args...)); XTENSOR_CHECK_DIMENSION(shape(), args...); return m_functor(m_e(args...)); } /** * Returns a reference to the element at the specified position in the expression. * @param args a list of indices specifying the position in the expression. Indices * must be unsigned integers, the number of indices must be equal to the number of * dimensions of the expression, else the behavior is undefined. * * @warning This method is meant for performance, for expressions with a dynamic * number of dimensions (i.e. not known at compile time). Since it may have * undefined behavior (see parameters), operator() should be preferred whenever * it is possible. * @warning This method is NOT compatible with broadcasting, meaning the following * code has undefined behavior: * @code{.cpp} * xt::xarray a = {{0, 1}, {2, 3}}; * xt::xarray b = {0, 1}; * auto fd = a + b; * double res = fd.unchecked(0, 1); * @endcode */ template template inline auto xfunctor_applier_base::unchecked(Args... args) -> reference { return m_functor(m_e.unchecked(args...)); } /** * Returns a reference to the element at the specified position in the expression. * @param first iterator starting the sequence of indices * @param last iterator ending the sequence of indices * The number of indices in the sequence should be equal to or greater * than the number of dimensions of the function. */ template template inline auto xfunctor_applier_base::element(IT first, IT last) -> reference { XTENSOR_TRY(check_element_index(shape(), first, last)); return m_functor(m_e.element(first, last)); } /** * Returns a constant reference to the element at the specified position in the expression. * @param args a list of indices specifying the position in the function. Indices * must be unsigned integers, the number of indices should be equal or greater than * the number of dimensions of the expression. */ template template inline auto xfunctor_applier_base::operator()(Args... args) const -> const_reference { XTENSOR_TRY(check_index(shape(), args...)); XTENSOR_CHECK_DIMENSION(shape(), args...); return m_functor(m_e(args...)); } /** * Returns a constant reference to the element at the specified position in the expression. * @param args a list of indices specifying the position in the expression. Indices * must be unsigned integers, the number of indices must be equal to the number of * dimensions of the expression, else the behavior is undefined. * * @warning This method is meant for performance, for expressions with a dynamic * number of dimensions (i.e. not known at compile time). Since it may have * undefined behavior (see parameters), operator() should be preferred whenever * it is possible. * @warning This method is NOT compatible with broadcasting, meaning the following * code has undefined behavior: * @code{.cpp} * xt::xarray a = {{0, 1}, {2, 3}}; * xt::xarray b = {0, 1}; * auto fd = a + b; * double res = fd.uncheked(0, 1); * @endcode */ template template inline auto xfunctor_applier_base::unchecked(Args... args) const -> const_reference { return m_functor(m_e.unchecked(args...)); } /** * Returns a constant reference to the element at the specified position in the expression. * @param first iterator starting the sequence of indices * @param last iterator ending the sequence of indices * The number of indices in the sequence should be equal to or greater * than the number of dimensions of the function. */ template template inline auto xfunctor_applier_base::element(IT first, IT last) const -> const_reference { XTENSOR_TRY(check_element_index(shape(), first, last)); return m_functor(m_e.element(first, last)); } /** * Returns a reference to the underlying expression of the view. */ template inline auto xfunctor_applier_base::expression() noexcept -> xexpression_type& { return m_e; } /** * Returns a consttant reference to the underlying expression of the view. */ template inline auto xfunctor_applier_base::expression() const noexcept -> const xexpression_type& { return m_e; } //@} /** * @name Broadcasting */ //@{ /** * Broadcast the shape of the function to the specified parameter. * @param shape the result shape * @param reuse_cache boolean for reusing a previously computed shape * @return a boolean indicating whether the broadcasting is trivial */ template template inline bool xfunctor_applier_base::broadcast_shape(S& shape, bool reuse_cache) const { return m_e.broadcast_shape(shape, reuse_cache); } /** * Checks whether the xfunctor_applier_base can be linearly assigned to an expression * with the specified strides. * * @return a boolean indicating whether a linear assign is possible */ template template inline bool xfunctor_applier_base::has_linear_assign(const S& strides) const { return m_e.has_linear_assign(strides); } //@} /** * @name Iterators */ //@{ /** * Returns an iterator to the first element of the expression. * @tparam L order used for the traversal. Default value is \c XTENSOR_DEFAULT_TRAVERSAL. */ template template inline auto xfunctor_applier_base::begin() noexcept { return xfunctor_iterator())>( m_e.template begin(), &m_functor ); } /** * Returns an iterator to the element following the last element * of the expression. * @tparam L order used for the traversal. Default value is \c XTENSOR_DEFAULT_TRAVERSAL. */ template template inline auto xfunctor_applier_base::end() noexcept { return xfunctor_iterator())>(m_e.template end(), &m_functor); } /** * Returns a constant iterator to the first element of the expression. * @tparam L order used for the traversal. Default value is \c XTENSOR_DEFAULT_TRAVERSAL. */ template template inline auto xfunctor_applier_base::begin() const noexcept { return this->template cbegin(); } /** * Returns a constant iterator to the element following the last element * of the expression. * @tparam L order used for the traversal. Default value is \c XTENSOR_DEFAULT_TRAVERSAL. */ template template inline auto xfunctor_applier_base::end() const noexcept { return this->template cend(); } /** * Returns a constant iterator to the first element of the expression. * @tparam L order used for the traversal. Default value is \c XTENSOR_DEFAULT_TRAVERSAL. */ template template inline auto xfunctor_applier_base::cbegin() const noexcept { return xfunctor_iterator())>( m_e.template cbegin(), &m_functor ); } /** * Returns a constant iterator to the element following the last element * of the expression. * @tparam L order used for the traversal. Default value is \c XTENSOR_DEFAULT_TRAVERSAL. */ template template inline auto xfunctor_applier_base::cend() const noexcept { return xfunctor_iterator())>( m_e.template cend(), &m_functor ); } //@} /** * @name Broadcast iterators */ //@{ /** * Returns a constant iterator to the first element of the expression. The * iteration is broadcasted to the specified shape. * @param shape the shape used for broadcasting * @tparam S type of the \c shape parameter. * @tparam L order used for the traversal. Default value is \c XTENSOR_DEFAULT_TRAVERSAL. */ template template inline auto xfunctor_applier_base::begin(const S& shape) noexcept -> broadcast_iterator { return broadcast_iterator(m_e.template begin(shape), &m_functor); } /** * Returns a constant iterator to the element following the last element of the * expression. The iteration is broadcasted to the specified shape. * @param shape the shape used for broadcasting * @tparam S type of the \c shape parameter. * @tparam L order used for the traversal. Default value is \c XTENSOR_DEFAULT_TRAVERSAL. */ template template inline auto xfunctor_applier_base::end(const S& shape) noexcept -> broadcast_iterator { return broadcast_iterator(m_e.template end(shape), &m_functor); } /** * Returns a constant iterator to the first element of the expression. The * iteration is broadcasted to the specified shape. * @param shape the shape used for broadcasting * @tparam S type of the \c shape parameter. * @tparam L order used for the traversal. Default value is \c XTENSOR_DEFAULT_TRAVERSAL. */ template template inline auto xfunctor_applier_base::begin(const S& shape) const noexcept -> const_broadcast_iterator { return cbegin(shape); } /** * Returns a constant iterator to the element following the last element of the * expression. The iteration is broadcasted to the specified shape. * @param shape the shape used for broadcasting * @tparam S type of the \c shape parameter. * @tparam L order used for the traversal. Default value is \c XTENSOR_DEFAULT_TRAVERSAL. */ template template inline auto xfunctor_applier_base::end(const S& shape) const noexcept -> const_broadcast_iterator { return cend(shape); } /** * Returns a constant iterator to the first element of the expression. The * iteration is broadcasted to the specified shape. * @param shape the shape used for broadcasting * @tparam S type of the \c shape parameter. * @tparam L order used for the traversal. Default value is \c XTENSOR_DEFAULT_TRAVERSAL. */ template template inline auto xfunctor_applier_base::cbegin(const S& shape) const noexcept -> const_broadcast_iterator { return const_broadcast_iterator(m_e.template cbegin(shape), &m_functor); } /** * Returns a constant iterator to the element following the last element of the * expression. The iteration is broadcasted to the specified shape. * @param shape the shape used for broadcasting * @tparam S type of the \c shape parameter. * @tparam L order used for the traversal. Default value is \c XTENSOR_DEFAULT_TRAVERSAL. */ template template inline auto xfunctor_applier_base::cend(const S& shape) const noexcept -> const_broadcast_iterator { return const_broadcast_iterator(m_e.template cend(shape), &m_functor); } //@} /** * @name Reverse iterators */ //@{ /** * Returns an iterator to the first element of the reversed expression. * @tparam L order used for the traversal. Default value is \c XTENSOR_DEFAULT_TRAVERSAL. */ template template inline auto xfunctor_applier_base::rbegin() noexcept { return xfunctor_iterator())>( m_e.template rbegin(), &m_functor ); } /** * Returns an iterator to the element following the last element * of the reversed expression. * @tparam L order used for the traversal. Default value is \c XTENSOR_DEFAULT_TRAVERSAL. */ template template inline auto xfunctor_applier_base::rend() noexcept { return xfunctor_iterator())>( m_e.template rend(), &m_functor ); } /** * Returns a constant iterator to the first element of the reversed expression. * @tparam L order used for the traversal. Default value is \c XTENSOR_DEFAULT_TRAVERSAL. */ template template inline auto xfunctor_applier_base::rbegin() const noexcept { return this->template crbegin(); } /** * Returns a constant iterator to the element following the last element * of the reversed expression. * @tparam L order used for the traversal. Default value is \c XTENSOR_DEFAULT_TRAVERSAL. */ template template inline auto xfunctor_applier_base::rend() const noexcept { return this->template crend(); } /** * Returns a constant iterator to the first element of the reversed expression. * @tparam L order used for the traversal. Default value is \c XTENSOR_DEFAULT_TRAVERSAL. */ template template inline auto xfunctor_applier_base::crbegin() const noexcept { return xfunctor_iterator())>( m_e.template crbegin(), &m_functor ); } /** * Returns a constant iterator to the element following the last element * of the reversed expression. * @tparam L order used for the traversal. Default value is \c XTENSOR_DEFAULT_TRAVERSAL. */ template template inline auto xfunctor_applier_base::crend() const noexcept { return xfunctor_iterator())>( m_e.template crend(), &m_functor ); } //@} /** * @name Reverse broadcast iterators */ /** * Returns an iterator to the first element of the expression. The * iteration is broadcasted to the specified shape. * @param shape the shape used for broadcasting * @tparam S type of the \c shape parameter. * @tparam L order used for the traversal. Default value is \c XTENSOR_DEFAULT_TRAVERSAL. */ template template inline auto xfunctor_applier_base::rbegin(const S& shape) noexcept -> reverse_broadcast_iterator { return reverse_broadcast_iterator(m_e.template rbegin(shape), &m_functor); } /** * Returns an iterator to the element following the last element of the * reversed expression. The iteration is broadcasted to the specified shape. * @param shape the shape used for broadcasting * @tparam S type of the \c shape parameter. * @tparam L order used for the traversal. Default value is \c XTENSOR_DEFAULT_TRAVERSAL. */ template template inline auto xfunctor_applier_base::rend(const S& shape) noexcept -> reverse_broadcast_iterator { return reverse_broadcast_iterator(m_e.template rend(shape), &m_functor); } /** * Returns a constant iterator to the first element of the reversed expression. * The iteration is broadcasted to the specified shape. * @param shape the shape used for broadcasting * @tparam S type of the \c shape parameter. * @tparam L order used for the traversal. Default value is \c XTENSOR_DEFAULT_TRAVERSAL. */ template template inline auto xfunctor_applier_base::rbegin(const S& shape) const noexcept -> const_reverse_broadcast_iterator { return crbegin(shape); } /** * Returns a constant iterator to the element following the last element * of the reversed expression. * @param shape the shape used for broadcasting * @tparam S type of the \c shape parameter. * @tparam L order used for the traversal. Default value is \c XTENSOR_DEFAULT_TRAVERSAL. */ template template inline auto xfunctor_applier_base::rend(const S& /*shape*/) const noexcept -> const_reverse_broadcast_iterator { return crend(); } /** * Returns a constant iterator to the first element of the reversed expression. * The iteration is broadcasted to the specified shape. * @param shape the shape used for broadcasting * @tparam S type of the \c shape parameter. * @tparam L order used for the traversal. Default value is \c XTENSOR_DEFAULT_TRAVERSAL. */ template template inline auto xfunctor_applier_base::crbegin(const S& /*shape*/) const noexcept -> const_reverse_broadcast_iterator { return const_reverse_broadcast_iterator(m_e.template crbegin(), &m_functor); } /** * Returns a constant iterator to the element following the last element * of the reversed expression. * @param shape the shape used for broadcasting * @tparam S type of the \c shape parameter. * @tparam L order used for the traversal. Default value is \c XTENSOR_DEFAULT_TRAVERSAL. */ template template inline auto xfunctor_applier_base::crend(const S& shape) const noexcept -> const_reverse_broadcast_iterator { return const_reverse_broadcast_iterator(m_e.template crend(shape), &m_functor); } //@} template inline auto xfunctor_applier_base::linear_begin() noexcept -> linear_iterator { return linear_iterator(m_e.linear_begin(), &m_functor); } template inline auto xfunctor_applier_base::linear_end() noexcept -> linear_iterator { return linear_iterator(m_e.linear_end(), &m_functor); } template inline auto xfunctor_applier_base::linear_begin() const noexcept -> const_linear_iterator { return const_linear_iterator(m_e.linear_begin(), &m_functor); } template inline auto xfunctor_applier_base::linear_end() const noexcept -> const_linear_iterator { return const_linear_iterator(m_e.linear_end(), &m_functor); } template inline auto xfunctor_applier_base::linear_cbegin() const noexcept -> const_linear_iterator { return const_linear_iterator(m_e.linear_cbegin(), &m_functor); } template inline auto xfunctor_applier_base::linear_cend() const noexcept -> const_linear_iterator { return const_linear_iterator(m_e.linear_cend(), &m_functor); } template inline auto xfunctor_applier_base::linear_rbegin() noexcept -> reverse_linear_iterator { return reverse_linear_iterator(m_e.linear_rbegin(), &m_functor); } template inline auto xfunctor_applier_base::linear_rend() noexcept -> reverse_linear_iterator { return reverse_linear_iterator(m_e.linear_rend(), &m_functor); } template inline auto xfunctor_applier_base::linear_rbegin() const noexcept -> const_reverse_linear_iterator { return const_reverse_linear_iterator(m_e.linear_rbegin(), &m_functor); } template inline auto xfunctor_applier_base::linear_rend() const noexcept -> const_reverse_linear_iterator { return const_reverse_linear_iterator(m_e.linear_rend(), &m_functor); } template inline auto xfunctor_applier_base::linear_crbegin() const noexcept -> const_reverse_linear_iterator { return const_reverse_linear_iterator(m_e.linear_crbegin(), &m_functor); } template inline auto xfunctor_applier_base::linear_crend() const noexcept -> const_reverse_linear_iterator { return const_reverse_linear_iterator(m_e.linear_crend(), &m_functor); } /*************** * stepper api * ***************/ template template inline auto xfunctor_applier_base::stepper_begin(const S& shape) noexcept -> stepper { return stepper(m_e.stepper_begin(shape), &m_functor); } template template inline auto xfunctor_applier_base::stepper_end(const S& shape, layout_type l) noexcept -> stepper { return stepper(m_e.stepper_end(shape, l), &m_functor); } template template inline auto xfunctor_applier_base::stepper_begin(const S& shape) const noexcept -> const_stepper { const xexpression_type& const_m_e = m_e; return const_stepper(const_m_e.stepper_begin(shape), &m_functor); } template template inline auto xfunctor_applier_base::stepper_end(const S& shape, layout_type l) const noexcept -> const_stepper { const xexpression_type& const_m_e = m_e; return const_stepper(const_m_e.stepper_end(shape, l), &m_functor); } /******************************** * xfunctor_view implementation * ********************************/ /** * @name Extended copy semantic */ //@{ /** * The extended assignment operator. */ template template inline auto xfunctor_view::operator=(const xexpression& e) -> self_type& { bool cond = (e.derived_cast().shape().size() == this->dimension()) && std::equal(this->shape().begin(), this->shape().end(), e.derived_cast().shape().begin()); if (!cond) { semantic_base::operator=(broadcast(e.derived_cast(), this->shape())); } else { semantic_base::operator=(e); } return *this; } //@} template template inline auto xfunctor_view::operator=(const E& e) -> disable_xexpression& { std::fill(this->begin(), this->end(), e); return *this; } template inline void xfunctor_view::assign_temporary_impl(temporary_type&& tmp) { std::copy(tmp.cbegin(), tmp.cend(), this->begin()); } template template inline auto xfunctor_view::build_functor_view(E&& e) const -> rebind_t { return rebind_t((this->m_functor), std::forward(e)); } /*********************************** * xfunctor_adaptor implementation * ***********************************/ /** * @name Extended copy semantic */ //@{ /** * The extended assignment operator. */ template template inline auto xfunctor_adaptor::operator=(const xexpression& e) -> self_type& { const auto& de = e.derived_cast(); this->m_e.resize(de.shape()); if (this->layout() == de.layout()) { std::copy(de.linear_begin(), de.linear_end(), this->linear_begin()); } else { // note: does this even select the current layout of *this* for iteration? std::copy(de.begin(), de.end(), this->begin()); } return *this; } //@} template template auto xfunctor_adaptor::resize(S&& shape, bool force) { this->m_e.resize(std::forward(shape), force); } template template auto xfunctor_adaptor::resize(S&& shape, layout_type l) { this->m_e.resize(std::forward(shape), l); } template template auto xfunctor_adaptor::resize(S&& shape, const strides_type& strides) { this->m_e.resize(std::forward(shape), strides); } template template auto& xfunctor_adaptor::reshape(S&& shape, layout_type layout) & { this->m_e.reshape(std::forward(shape), layout); return *this; } /************************************ * xfunctor_iterator implementation * ************************************/ template xfunctor_iterator::xfunctor_iterator(const IT& it, functor_type* pf) : m_it(it) , p_functor(pf) { } template inline auto xfunctor_iterator::operator++() -> self_type& { ++m_it; return *this; } template inline auto xfunctor_iterator::operator--() -> self_type& { --m_it; return *this; } template inline auto xfunctor_iterator::operator+=(difference_type n) -> self_type& { m_it += n; return *this; } template inline auto xfunctor_iterator::operator-=(difference_type n) -> self_type& { m_it -= n; return *this; } template inline auto xfunctor_iterator::operator-(xfunctor_iterator rhs) const -> difference_type { return m_it - rhs.m_it; } template auto xfunctor_iterator::operator*() const -> reference { return (*p_functor)(*m_it); } template auto xfunctor_iterator::operator->() const -> pointer { return &(operator*()); } template auto xfunctor_iterator::equal(const xfunctor_iterator& rhs) const -> bool { return m_it == rhs.m_it; } template auto xfunctor_iterator::less_than(const xfunctor_iterator& rhs) const -> bool { return m_it < rhs.m_it; } template bool operator==(const xfunctor_iterator& lhs, const xfunctor_iterator& rhs) { return lhs.equal(rhs); } template bool operator<(const xfunctor_iterator& lhs, const xfunctor_iterator& rhs) { return !lhs.less_than(rhs); } /*********************************** * xfunctor_stepper implementation * ***********************************/ template xfunctor_stepper::xfunctor_stepper(const ST& stepper, functor_type* pf) : m_stepper(stepper) , p_functor(pf) { } template auto xfunctor_stepper::operator*() const -> reference { return (*p_functor)(*m_stepper); } template void xfunctor_stepper::step(size_type dim) { m_stepper.step(dim); } template void xfunctor_stepper::step_back(size_type dim) { m_stepper.step_back(dim); } template void xfunctor_stepper::step(size_type dim, size_type n) { m_stepper.step(dim, n); } template void xfunctor_stepper::step_back(size_type dim, size_type n) { m_stepper.step_back(dim, n); } template void xfunctor_stepper::reset(size_type dim) { m_stepper.reset(dim); } template void xfunctor_stepper::reset_back(size_type dim) { m_stepper.reset_back(dim); } template void xfunctor_stepper::to_begin() { m_stepper.to_begin(); } template void xfunctor_stepper::to_end(layout_type l) { m_stepper.to_end(l); } } #endif