/*************************************************************************** * 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_ARRAY_HPP #define XTENSOR_ARRAY_HPP #include #include #include #include #include "xbuffer_adaptor.hpp" #include "xcontainer.hpp" #include "xsemantic.hpp" namespace xt { /******************************** * xarray_container declaration * ********************************/ namespace extension { template struct xarray_container_base; template struct xarray_container_base { using type = xtensor_empty_base; }; template using xarray_container_base_t = typename xarray_container_base::type; } template struct xcontainer_inner_types> { using storage_type = EC; using reference = inner_reference_t; using const_reference = typename storage_type::const_reference; using size_type = typename storage_type::size_type; using shape_type = SC; using strides_type = get_strides_t; using backstrides_type = get_strides_t; using inner_shape_type = shape_type; using inner_strides_type = strides_type; using inner_backstrides_type = backstrides_type; using temporary_type = xarray_container; static constexpr layout_type layout = L; }; template struct xiterable_inner_types> : xcontainer_iterable_types> { }; /** * @class xarray_container * @brief Dense multidimensional container with tensor semantic. * * The xarray_container class implements a dense multidimensional container * with tensor semantic. * * @tparam EC The type of the container holding the elements. * @tparam L The layout_type of the container. * @tparam SC The type of the containers holding the shape and the strides. * @tparam Tag The expression tag. * @sa xarray, xstrided_container, xcontainer */ template class xarray_container : public xstrided_container>, public xcontainer_semantic>, public extension::xarray_container_base_t { public: using self_type = xarray_container; using base_type = xstrided_container; using semantic_base = xcontainer_semantic; using extension_base = extension::xarray_container_base_t; using storage_type = typename base_type::storage_type; using allocator_type = typename base_type::allocator_type; using value_type = typename base_type::value_type; using reference = typename base_type::reference; using const_reference = typename base_type::const_reference; using pointer = typename base_type::pointer; using const_pointer = typename base_type::const_pointer; using shape_type = typename base_type::shape_type; using inner_shape_type = typename base_type::inner_shape_type; using strides_type = typename base_type::strides_type; using backstrides_type = typename base_type::backstrides_type; using inner_strides_type = typename base_type::inner_strides_type; using inner_backstrides_type = typename base_type::inner_backstrides_type; using temporary_type = typename semantic_base::temporary_type; using expression_tag = Tag; static constexpr std::size_t rank = SIZE_MAX; xarray_container(); explicit xarray_container(const shape_type& shape, layout_type l = L); explicit xarray_container(const shape_type& shape, const_reference value, layout_type l = L); explicit xarray_container(const shape_type& shape, const strides_type& strides); explicit xarray_container(const shape_type& shape, const strides_type& strides, const_reference value); explicit xarray_container(storage_type&& storage, inner_shape_type&& shape, inner_strides_type&& strides); xarray_container(const value_type& t); xarray_container(nested_initializer_list_t t); xarray_container(nested_initializer_list_t t); xarray_container(nested_initializer_list_t t); xarray_container(nested_initializer_list_t t); xarray_container(nested_initializer_list_t t); template static xarray_container from_shape(S&& s); ~xarray_container() = default; xarray_container(const xarray_container&) = default; xarray_container& operator=(const xarray_container&) = default; xarray_container(xarray_container&&) = default; xarray_container& operator=(xarray_container&&) = default; template explicit xarray_container(xtensor_container&& rhs); template xarray_container& operator=(xtensor_container&& rhs); template xarray_container(const xexpression& e); template xarray_container& operator=(const xexpression& e); private: storage_type m_storage; storage_type& storage_impl() noexcept; const storage_type& storage_impl() const noexcept; friend class xcontainer>; }; /****************************** * xarray_adaptor declaration * ******************************/ namespace extension { template struct xarray_adaptor_base; template struct xarray_adaptor_base { using type = xtensor_empty_base; }; template using xarray_adaptor_base_t = typename xarray_adaptor_base::type; } template struct xcontainer_inner_types> { using storage_type = std::remove_reference_t; using reference = inner_reference_t; using const_reference = typename storage_type::const_reference; using size_type = typename storage_type::size_type; using shape_type = SC; using strides_type = get_strides_t; using backstrides_type = get_strides_t; using inner_shape_type = shape_type; using inner_strides_type = strides_type; using inner_backstrides_type = backstrides_type; using temporary_type = xarray_container, L, SC, Tag>; static constexpr layout_type layout = L; }; template struct xiterable_inner_types> : xcontainer_iterable_types> { }; /** * @class xarray_adaptor * @brief Dense multidimensional container adaptor with * tensor semantic. * * The xarray_adaptor class implements a dense multidimensional * container adaptor with tensor semantic. It is used to provide * a multidimensional container semantic and a tensor semantic to * stl-like containers. * * @tparam EC The closure for the container type to adapt. * @tparam L The layout_type of the adaptor. * @tparam SC The type of the containers holding the shape and the strides. * @tparam Tag The expression tag. * @sa xstrided_container, xcontainer */ template class xarray_adaptor : public xstrided_container>, public xcontainer_semantic>, public extension::xarray_adaptor_base_t { public: using container_closure_type = EC; using self_type = xarray_adaptor; using base_type = xstrided_container; using semantic_base = xcontainer_semantic; using extension_base = extension::xarray_adaptor_base_t; using storage_type = typename base_type::storage_type; using allocator_type = typename base_type::allocator_type; using shape_type = typename base_type::shape_type; using strides_type = typename base_type::strides_type; using backstrides_type = typename base_type::backstrides_type; using temporary_type = typename semantic_base::temporary_type; using expression_tag = Tag; static constexpr std::size_t rank = SIZE_MAX; xarray_adaptor(storage_type&& storage); xarray_adaptor(const storage_type& storage); template xarray_adaptor(D&& storage, const shape_type& shape, layout_type l = L); template xarray_adaptor(D&& storage, const shape_type& shape, const strides_type& strides); ~xarray_adaptor() = default; xarray_adaptor(const xarray_adaptor&) = default; xarray_adaptor& operator=(const xarray_adaptor&); xarray_adaptor(xarray_adaptor&&) = default; xarray_adaptor& operator=(xarray_adaptor&&); xarray_adaptor& operator=(temporary_type&&); template xarray_adaptor& operator=(const xexpression& e); template void reset_buffer(P&& pointer, S&& size); private: container_closure_type m_storage; storage_type& storage_impl() noexcept; const storage_type& storage_impl() const noexcept; friend class xcontainer>; }; /*********************************** * xarray_container implementation * ***********************************/ /** * @name Constructors */ //@{ /** * Allocates an uninitialized xarray_container that holds 0 element. */ template inline xarray_container::xarray_container() : base_type() , m_storage(1, value_type()) { } /** * Allocates an uninitialized xarray_container with the specified shape and * layout_type. * @param shape the shape of the xarray_container * @param l the layout_type of the xarray_container */ template inline xarray_container::xarray_container(const shape_type& shape, layout_type l) : base_type() { base_type::resize(shape, l); } /** * Allocates an xarray_container with the specified shape and layout_type. Elements * are initialized to the specified value. * @param shape the shape of the xarray_container * @param value the value of the elements * @param l the layout_type of the xarray_container */ template inline xarray_container::xarray_container( const shape_type& shape, const_reference value, layout_type l ) : base_type() { base_type::resize(shape, l); std::fill(m_storage.begin(), m_storage.end(), value); } /** * Allocates an uninitialized xarray_container with the specified shape and strides. * @param shape the shape of the xarray_container * @param strides the strides of the xarray_container */ template inline xarray_container::xarray_container(const shape_type& shape, const strides_type& strides) : base_type() { base_type::resize(shape, strides); } /** * Allocates an uninitialized xarray_container with the specified shape and strides. * Elements are initialized to the specified value. * @param shape the shape of the xarray_container * @param strides the strides of the xarray_container * @param value the value of the elements */ template inline xarray_container::xarray_container( const shape_type& shape, const strides_type& strides, const_reference value ) : base_type() { base_type::resize(shape, strides); std::fill(m_storage.begin(), m_storage.end(), value); } /** * Allocates an xarray_container that holds a single element initialized to the * specified value. * @param t the value of the element */ template inline xarray_container::xarray_container(const value_type& t) : base_type() { base_type::resize(xt::shape(t), true); nested_copy(m_storage.begin(), t); } /** * Allocates an xarray_container by moving specified data, shape and strides * * @param storage the data for the xarray_container * @param shape the shape of the xarray_container * @param strides the strides of the xarray_container */ template inline xarray_container::xarray_container( storage_type&& storage, inner_shape_type&& shape, inner_strides_type&& strides ) : base_type(std::move(shape), std::move(strides)) , m_storage(std::move(storage)) { } //@} /** * @name Constructors from initializer list */ //@{ /** * Allocates a one-dimensional xarray_container. * @param t the elements of the xarray_container */ template inline xarray_container::xarray_container(nested_initializer_list_t t) : base_type() { base_type::resize(xt::shape(t)); constexpr auto tmp = layout_type::row_major; L == tmp ? nested_copy(m_storage.begin(), t) : nested_copy(this->template begin(), t); } /** * Allocates a two-dimensional xarray_container. * @param t the elements of the xarray_container */ template inline xarray_container::xarray_container(nested_initializer_list_t t) : base_type() { base_type::resize(xt::shape(t)); constexpr auto tmp = layout_type::row_major; L == tmp ? nested_copy(m_storage.begin(), t) : nested_copy(this->template begin(), t); } /** * Allocates a three-dimensional xarray_container. * @param t the elements of the xarray_container */ template inline xarray_container::xarray_container(nested_initializer_list_t t) : base_type() { base_type::resize(xt::shape(t)); constexpr auto tmp = layout_type::row_major; L == tmp ? nested_copy(m_storage.begin(), t) : nested_copy(this->template begin(), t); } /** * Allocates a four-dimensional xarray_container. * @param t the elements of the xarray_container */ template inline xarray_container::xarray_container(nested_initializer_list_t t) : base_type() { base_type::resize(xt::shape(t)); constexpr auto tmp = layout_type::row_major; L == tmp ? nested_copy(m_storage.begin(), t) : nested_copy(this->template begin(), t); } /** * Allocates a five-dimensional xarray_container. * @param t the elements of the xarray_container */ template inline xarray_container::xarray_container(nested_initializer_list_t t) : base_type() { base_type::resize(xt::shape(t)); constexpr auto tmp = layout_type::row_major; L == tmp ? nested_copy(m_storage.begin(), t) : nested_copy(this->template begin(), t); } //@} /** * Allocates and returns an xarray_container with the specified shape. * @param s the shape of the xarray_container */ template template inline xarray_container xarray_container::from_shape(S&& s) { shape_type shape = xtl::forward_sequence(s); return self_type(shape); } template template inline xarray_container::xarray_container(xtensor_container&& rhs) : base_type( inner_shape_type(rhs.shape().cbegin(), rhs.shape().cend()), inner_strides_type(rhs.strides().cbegin(), rhs.strides().cend()), inner_backstrides_type(rhs.backstrides().cbegin(), rhs.backstrides().cend()), std::move(rhs.layout()) ) , m_storage(std::move(rhs.storage())) { } template template inline xarray_container& xarray_container::operator=(xtensor_container&& rhs) { this->shape_impl().assign(rhs.shape().cbegin(), rhs.shape().cend()); this->strides_impl().assign(rhs.strides().cbegin(), rhs.strides().cend()); this->backstrides_impl().assign(rhs.backstrides().cbegin(), rhs.backstrides().cend()); this->mutable_layout() = rhs.layout(); m_storage = std::move(rhs.storage()); return *this; } /** * @name Extended copy semantic */ //@{ /** * The extended copy constructor. */ template template inline xarray_container::xarray_container(const xexpression& e) : base_type() { // Avoids unintialized data because of (m_shape == shape) condition // in resize (called by assign), which is always true when dimension == 0. if (e.derived_cast().dimension() == 0) { detail::resize_data_container(m_storage, std::size_t(1)); } semantic_base::assign(e); } /** * The extended assignment operator. */ template template inline auto xarray_container::operator=(const xexpression& e) -> self_type& { return semantic_base::operator=(e); } //@} template inline auto xarray_container::storage_impl() noexcept -> storage_type& { return m_storage; } template inline auto xarray_container::storage_impl() const noexcept -> const storage_type& { return m_storage; } /****************** * xarray_adaptor * ******************/ /** * @name Constructors */ //@{ /** * Constructs an xarray_adaptor of the given stl-like container. * @param storage the container to adapt */ template inline xarray_adaptor::xarray_adaptor(storage_type&& storage) : base_type() , m_storage(std::move(storage)) { } /** * Constructs an xarray_adaptor of the given stl-like container. * @param storage the container to adapt */ template inline xarray_adaptor::xarray_adaptor(const storage_type& storage) : base_type() , m_storage(storage) { } /** * Constructs an xarray_adaptor of the given stl-like container, * with the specified shape and layout_type. * @param storage the container to adapt * @param shape the shape of the xarray_adaptor * @param l the layout_type of the xarray_adaptor */ template template inline xarray_adaptor::xarray_adaptor(D&& storage, const shape_type& shape, layout_type l) : base_type() , m_storage(std::forward(storage)) { base_type::resize(shape, l); } /** * Constructs an xarray_adaptor of the given stl-like container, * with the specified shape and strides. * @param storage the container to adapt * @param shape the shape of the xarray_adaptor * @param strides the strides of the xarray_adaptor */ template template inline xarray_adaptor::xarray_adaptor( D&& storage, const shape_type& shape, const strides_type& strides ) : base_type() , m_storage(std::forward(storage)) { base_type::resize(shape, strides); } //@} template inline auto xarray_adaptor::operator=(const xarray_adaptor& rhs) -> self_type& { base_type::operator=(rhs); m_storage = rhs.m_storage; return *this; } template inline auto xarray_adaptor::operator=(xarray_adaptor&& rhs) -> self_type& { base_type::operator=(std::move(rhs)); m_storage = rhs.m_storage; return *this; } template inline auto xarray_adaptor::operator=(temporary_type&& rhs) -> self_type& { base_type::shape_impl() = std::move(const_cast(rhs.shape())); base_type::strides_impl() = std::move(const_cast(rhs.strides())); base_type::backstrides_impl() = std::move(const_cast(rhs.backstrides())); m_storage = std::move(rhs.storage()); return *this; } /** * @name Extended copy semantic */ //@{ /** * The extended assignment operator. */ template template inline auto xarray_adaptor::operator=(const xexpression& e) -> self_type& { return semantic_base::operator=(e); } //@} template inline auto xarray_adaptor::storage_impl() noexcept -> storage_type& { return m_storage; } template inline auto xarray_adaptor::storage_impl() const noexcept -> const storage_type& { return m_storage; } template template inline void xarray_adaptor::reset_buffer(P&& pointer, S&& size) { return m_storage.reset_data(std::forward

(pointer), std::forward(size)); } } #endif