/*************************************************************************** * 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_XMASKED_VIEW_HPP #define XTENSOR_XMASKED_VIEW_HPP #include "xaccessible.hpp" #include "xexpression.hpp" #include "xiterable.hpp" #include "xsemantic.hpp" #include "xshape.hpp" #include "xtensor_forward.hpp" #include "xtl/xmasked_value.hpp" #include "xutils.hpp" namespace xt { /**************************** * xmasked_view declaration * *****************************/ template class xmasked_view; template class xmasked_view_stepper; template struct xcontainer_inner_types; template struct xcontainer_inner_types> { using data_type = std::decay_t; using mask_type = std::decay_t; using base_value_type = typename data_type::value_type; using flag_type = typename mask_type::value_type; using val_reference = inner_reference_t; using mask_reference = inner_reference_t; using value_type = xtl::xmasked_value; using reference = xtl::xmasked_value; using const_reference = xtl::xmasked_value; using size_type = typename data_type::size_type; using temporary_type = xarray>; }; template struct xiterable_inner_types> { using masked_view_type = xmasked_view; using inner_shape_type = typename std::decay_t::inner_shape_type; using stepper = xmasked_view_stepper; using const_stepper = xmasked_view_stepper; }; /** * @class xmasked_view * @brief View on an xoptional_assembly or xoptional_assembly_adaptor * hiding values depending on a given mask. * * The xmasked_view class implements a view on an xoptional_assembly or * xoptional_assembly_adaptor, it takes this xoptional_assembly and a * mask as input. The mask is an xexpression containing boolean values, * whenever the value of the mask is false, the optional value of * xmasked_view is considered missing, otherwise it depends on the * underlying xoptional_assembly. * * @tparam CTD The type of expression holding the values. * @tparam CTM The type of expression holding the mask. */ template class xmasked_view : public xview_semantic>, private xaccessible>, private xiterable> { public: using self_type = xmasked_view; using semantic_base = xview_semantic>; using accessible_base = xaccessible; using inner_types = xcontainer_inner_types; using temporary_type = typename inner_types::temporary_type; using data_type = typename inner_types::data_type; using mask_type = typename inner_types::mask_type; using value_expression = CTD; using mask_expression = CTM; static constexpr bool is_data_const = std::is_const>::value; using base_value_type = typename inner_types::base_value_type; using base_reference = typename data_type::reference; using base_const_reference = typename data_type::const_reference; using flag_type = typename inner_types::flag_type; using flag_reference = typename mask_type::reference; using flag_const_reference = typename mask_type::const_reference; using val_reference = typename inner_types::val_reference; using mask_reference = typename inner_types::mask_reference; using value_type = typename inner_types::value_type; using reference = typename inner_types::reference; using const_reference = typename inner_types::const_reference; using pointer = xtl::xclosure_pointer; using const_pointer = xtl::xclosure_pointer; using size_type = typename inner_types::size_type; using difference_type = typename data_type::difference_type; using bool_load_type = xtl::xmasked_value; using shape_type = typename data_type::shape_type; using strides_type = typename data_type::strides_type; static constexpr layout_type static_layout = data_type::static_layout; static constexpr bool contiguous_layout = false; using inner_shape_type = typename data_type::inner_shape_type; using inner_strides_type = typename data_type::inner_strides_type; using inner_backstrides_type = typename data_type::inner_backstrides_type; using expression_tag = xtensor_expression_tag; using iterable_base = xiterable>; 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 = typename iterable_base::iterator; using const_iterator = typename iterable_base::const_iterator; using reverse_iterator = typename iterable_base::reverse_iterator; using const_reverse_iterator = typename iterable_base::const_reverse_iterator; template xmasked_view(D&& data, M&& mask); xmasked_view(const xmasked_view&) = default; 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 void fill(const T& value); template reference operator()(Args... args); template const_reference operator()(Args... args) const; template reference unchecked(Args... args); template const_reference unchecked(Args... args) const; 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 first, It last); template const_reference element(It first, It last) const; template bool has_linear_assign(const S& strides) const noexcept; data_type& value() noexcept; const data_type& value() const noexcept; mask_type& visible() noexcept; const mask_type& visible() const noexcept; using iterable_base::begin; using iterable_base::cbegin; using iterable_base::cend; using iterable_base::crbegin; using iterable_base::crend; using iterable_base::end; using iterable_base::rbegin; using iterable_base::rend; 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; self_type& operator=(const self_type& rhs); template self_type& operator=(const xexpression& e); template disable_xexpression& operator=(const E& e); private: CTD m_data; CTM m_mask; void assign_temporary_impl(temporary_type&& tmp); friend class xiterable; friend class xconst_iterable; friend class xview_semantic; friend class xaccessible; friend class xconst_accessible; }; template class xmasked_view_stepper { public: using self_type = xmasked_view_stepper; using masked_view_type = std::decay_t; using value_type = typename masked_view_type::value_type; using reference = std:: conditional_t; using pointer = std:: conditional_t; using size_type = typename masked_view_type::size_type; using difference_type = typename masked_view_type::difference_type; using data_type = typename masked_view_type::data_type; using mask_type = typename masked_view_type::mask_type; using value_stepper = std::conditional_t; using mask_stepper = std::conditional_t; xmasked_view_stepper(value_stepper vs, mask_stepper fs) noexcept; 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 l); reference operator*() const; private: value_stepper m_vs; mask_stepper m_ms; }; /******************************* * xmasked_view implementation * *******************************/ /** * @name Constructors */ //@{ /** * Creates an xmasked_view, given the xoptional_assembly or * xoptional_assembly_adaptor and the mask * * @param data the underlying xoptional_assembly or xoptional_assembly_adaptor * @param mask the mask. */ template template inline xmasked_view::xmasked_view(D&& data, M&& mask) : m_data(std::forward(data)) , m_mask(std::forward(mask)) { } /** * @name Size and shape */ //@{ /** * Returns the number of elements in the xmasked_view. */ template inline auto xmasked_view::size() const noexcept -> size_type { return m_data.size(); } /** * Returns the shape of the xmasked_view. */ template inline auto xmasked_view::shape() const noexcept -> const inner_shape_type& { return m_data.shape(); } /** * Returns the strides of the xmasked_view. */ template inline auto xmasked_view::strides() const noexcept -> const inner_strides_type& { return m_data.strides(); } /** * Returns the backstrides of the xmasked_view. */ template inline auto xmasked_view::backstrides() const noexcept -> const inner_backstrides_type& { return m_data.backstrides(); } //@} /** * Return the layout_type of the xmasked_view * @return layout_type of the xmasked_view */ template inline layout_type xmasked_view::layout() const noexcept { return m_data.layout(); } template inline bool xmasked_view::is_contiguous() const noexcept { return false; } /** * Fills the data with the given value. * @param value the value to fill the data with. */ template template inline void xmasked_view::fill(const T& value) { std::fill(this->begin(), this->end(), value); } /** * @name Data */ //@{ /** * Returns a reference to the element at the specified position in the xmasked_view. * @param args a list of indices specifying the position in the xmasked_view. Indices * must be unsigned integers, the number of indices should be equal or greater than * the number of dimensions of the xmasked_view. */ template template inline auto xmasked_view::operator()(Args... args) -> reference { return reference(m_data(args...), m_mask(args...)); } /** * Returns a constant reference to the element at the specified position in the xmasked_view. * @param args a list of indices specifying the position in the xmasked_view. Indices * must be unsigned integers, the number of indices should be equal or greater than * the number of dimensions of the xmasked_view. */ template template inline auto xmasked_view::operator()(Args... args) const -> const_reference { return const_reference(m_data(args...), m_mask(args...)); } /** * Returns a reference to the element at the specified position in the xmasked_view. * @param args a list of indices specifying the position in the xmasked_view. Indices * must be unsigned integers, the number of indices must be equal to the number of * dimensions of the xmasked_view, 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 xmasked_view::unchecked(Args... args) -> reference { return reference(m_data.unchecked(args...), m_mask.unchecked(args...)); } /** * Returns a constant reference to the element at the specified position in the xmasked_view. * @param args a list of indices specifying the position in the xmasked_view. Indices * must be unsigned integers, the number of indices must be equal to the number of * dimensions of the xmasked_view, 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 xmasked_view::unchecked(Args... args) const -> const_reference { return const_reference(m_data.unchecked(args...), m_mask.unchecked(args...)); } /** * Returns a reference to the element at the specified position in the xmasked_view. * @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 xmasked_view. */ template template inline auto xmasked_view::element(It first, It last) -> reference { return reference(m_data.element(first, last), m_mask.element(first, last)); } /** * Returns a constant reference to the element at the specified position in the xmasked_view. * @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 xmasked_view. */ template template inline auto xmasked_view::element(It first, It last) const -> const_reference { return const_reference(m_data.element(first, last), m_mask.element(first, last)); } //@} template template inline bool xmasked_view::has_linear_assign(const S& strides) const noexcept { return m_data.has_linear_assign(strides) && m_mask.has_linear_assign(strides); } /** * Return an expression for the values of the xmasked_view. */ template inline auto xmasked_view::value() noexcept -> data_type& { return m_data; } /** * Return a constant expression for the values of the xmasked_view. */ template inline auto xmasked_view::value() const noexcept -> const data_type& { return m_data; } /** * Return an expression for the mask of the xmasked_view. */ template inline auto xmasked_view::visible() noexcept -> mask_type& { return m_mask; } /** * Return a constant expression for the mask of the xmasked_view. */ template inline auto xmasked_view::visible() const noexcept -> const mask_type& { return m_mask; } template template inline auto xmasked_view::stepper_begin(const S& shape) noexcept -> stepper { return stepper(value().stepper_begin(shape), visible().stepper_begin(shape)); } template template inline auto xmasked_view::stepper_end(const S& shape, layout_type l) noexcept -> stepper { return stepper(value().stepper_end(shape, l), visible().stepper_end(shape, l)); } template template inline auto xmasked_view::stepper_begin(const S& shape) const noexcept -> const_stepper { return const_stepper(value().stepper_begin(shape), visible().stepper_begin(shape)); } template template inline auto xmasked_view::stepper_end(const S& shape, layout_type l) const noexcept -> const_stepper { return const_stepper(value().stepper_end(shape, l), visible().stepper_end(shape, l)); } template inline auto xmasked_view::operator=(const self_type& rhs) -> self_type& { temporary_type tmp(rhs); return this->assign_temporary(std::move(tmp)); } template template inline auto xmasked_view::operator=(const xexpression& e) -> self_type& { return semantic_base::operator=(e); } template template inline auto xmasked_view::operator=(const E& e) -> disable_xexpression& { std::fill(this->begin(), this->end(), e); return *this; } template inline void xmasked_view::assign_temporary_impl(temporary_type&& tmp) { std::copy(tmp.cbegin(), tmp.cend(), this->begin()); } template inline xmasked_view masked_view(CTD&& data, CTM&& mask) { return xmasked_view(std::forward(data), std::forward(mask)); } /*************************************** * xmasked_view_stepper implementation * ***************************************/ template inline xmasked_view_stepper::xmasked_view_stepper(value_stepper vs, mask_stepper ms) noexcept : m_vs(vs) , m_ms(ms) { } template inline void xmasked_view_stepper::step(size_type dim) { m_vs.step(dim); m_ms.step(dim); } template inline void xmasked_view_stepper::step_back(size_type dim) { m_vs.step_back(dim); m_ms.step_back(dim); } template inline void xmasked_view_stepper::step(size_type dim, size_type n) { m_vs.step(dim, n); m_ms.step(dim, n); } template inline void xmasked_view_stepper::step_back(size_type dim, size_type n) { m_vs.step_back(dim, n); m_ms.step_back(dim, n); } template inline void xmasked_view_stepper::reset(size_type dim) { m_vs.reset(dim); m_ms.reset(dim); } template inline void xmasked_view_stepper::reset_back(size_type dim) { m_vs.reset_back(dim); m_ms.reset_back(dim); } template inline void xmasked_view_stepper::to_begin() { m_vs.to_begin(); m_ms.to_begin(); } template inline void xmasked_view_stepper::to_end(layout_type l) { m_vs.to_end(l); m_ms.to_end(l); } template inline auto xmasked_view_stepper::operator*() const -> reference { return reference(*m_vs, *m_ms); } } #endif