/*************************************************************************** * 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_BUFFER_ADAPTOR_HPP #define XTENSOR_BUFFER_ADAPTOR_HPP #include #include #include #include #include #include #include "xstorage.hpp" #include "xtensor_config.hpp" namespace xt { struct no_ownership { }; using smart_ownership = no_ownership; struct acquire_ownership { }; template >>> class xbuffer_adaptor; /******************** * buffer_storage_t * ********************/ namespace detail { template class xbuffer_storage { public: using self_type = xbuffer_storage; using allocator_type = A; using destructor_type = allocator_type; using allocator_traits = std::allocator_traits; using value_type = typename allocator_traits::value_type; using reference = std::conditional_t< std::is_const>>::value, const value_type&, value_type&>; using const_reference = const value_type&; using pointer = std::conditional_t< std::is_const>>::value, typename allocator_traits::const_pointer, typename allocator_traits::pointer>; using const_pointer = typename allocator_traits::const_pointer; using size_type = typename allocator_traits::size_type; using difference_type = typename allocator_traits::difference_type; xbuffer_storage(); template xbuffer_storage(P&& data, size_type size, const allocator_type& alloc = allocator_type()); size_type size() const noexcept; void resize(size_type size); pointer data() noexcept; const_pointer data() const noexcept; void swap(self_type& rhs) noexcept; template void reset_data(P&& data, size_type size) noexcept; private: pointer p_data; size_type m_size; }; template class xbuffer_smart_pointer { public: using self_type = xbuffer_storage; using destructor_type = D; using value_type = std::remove_const_t>>; using allocator_type = std::allocator; using allocator_traits = std::allocator_traits; using reference = std::conditional_t< std::is_const>>::value, const value_type&, value_type&>; using const_reference = const value_type&; using pointer = std::conditional_t< std::is_const>>::value, typename allocator_traits::const_pointer, typename allocator_traits::pointer>; using const_pointer = typename allocator_traits::const_pointer; using size_type = typename allocator_traits::size_type; using difference_type = typename allocator_traits::difference_type; xbuffer_smart_pointer(); template xbuffer_smart_pointer(P&& data_ptr, size_type size, DT&& destruct); size_type size() const noexcept; void resize(size_type size); pointer data() noexcept; const_pointer data() const noexcept; void swap(self_type& rhs) noexcept; template void reset_data(P&& data, size_type size, DT&& destruct) noexcept; private: pointer p_data; size_type m_size; destructor_type m_destruct; }; template class xbuffer_owner_storage { public: using self_type = xbuffer_owner_storage; using allocator_type = A; using destructor_type = allocator_type; using allocator_traits = std::allocator_traits; using value_type = typename allocator_traits::value_type; using reference = std::conditional_t< std::is_const>>::value, const value_type&, value_type&>; using const_reference = const value_type&; using pointer = std::conditional_t< std::is_const>>::value, typename allocator_traits::const_pointer, typename allocator_traits::pointer>; using const_pointer = typename allocator_traits::const_pointer; using size_type = typename allocator_traits::size_type; using difference_type = typename allocator_traits::difference_type; xbuffer_owner_storage() = default; template xbuffer_owner_storage(P&& data, size_type size, const allocator_type& alloc = allocator_type()); ~xbuffer_owner_storage(); xbuffer_owner_storage(const self_type&) = delete; self_type& operator=(const self_type&); xbuffer_owner_storage(self_type&&); self_type& operator=(self_type&&); size_type size() const noexcept; void resize(size_type size); pointer data() noexcept; const_pointer data() const noexcept; allocator_type get_allocator() const noexcept; void swap(self_type& rhs) noexcept; template void reset_data(P&& data, size_type size, const allocator_type& alloc = allocator_type()) noexcept; private: xtl::xclosure_wrapper m_data; size_type m_size; bool m_moved_from; allocator_type m_allocator; }; // Workaround for MSVC2015: using void_t results in some // template instantiation caching that leads to wrong // type deduction later in xfunction. template struct msvc2015_void { using type = void; }; template using msvc2015_void_t = typename msvc2015_void::type; template struct is_lambda_type : std::false_type { }; // check if operator() is available template struct is_lambda_type> : std::true_type { }; template struct self_type { using type = T; }; template struct get_buffer_storage { using type = xtl::mpl::eval_if_t< is_lambda_type, self_type>, self_type>>; }; template struct get_buffer_storage { using type = xbuffer_owner_storage; }; template struct get_buffer_storage, no_ownership> { using type = xbuffer_smart_pointer>; }; template struct get_buffer_storage, no_ownership> { using type = xbuffer_smart_pointer>; }; template using buffer_storage_t = typename get_buffer_storage::type; } /************************ * xbuffer_adaptor_base * ************************/ template struct buffer_inner_types; template class xbuffer_adaptor_base { public: using self_type = xbuffer_adaptor_base; using derived_type = D; using inner_types = buffer_inner_types; using value_type = typename inner_types::value_type; using reference = typename inner_types::reference; using const_reference = typename inner_types::const_reference; using pointer = typename inner_types::pointer; using const_pointer = typename inner_types::const_pointer; using size_type = typename inner_types::size_type; using difference_type = typename inner_types::difference_type; using iterator = typename inner_types::iterator; using const_iterator = typename inner_types::const_iterator; using reverse_iterator = typename inner_types::reverse_iterator; using const_reverse_iterator = typename inner_types::const_reverse_iterator; using index_type = typename inner_types::index_type; bool empty() const noexcept; reference operator[](size_type i); const_reference operator[](size_type i) const; reference front(); const_reference front() const; reference back(); const_reference back() const; iterator begin() noexcept; iterator end() noexcept; const_iterator begin() const noexcept; const_iterator end() const noexcept; const_iterator cbegin() const noexcept; const_iterator cend() const noexcept; reverse_iterator rbegin() noexcept; reverse_iterator rend() noexcept; const_reverse_iterator rbegin() const noexcept; const_reverse_iterator rend() const noexcept; const_reverse_iterator crbegin() const noexcept; const_reverse_iterator crend() const noexcept; derived_type& derived_cast() noexcept; const derived_type& derived_cast() const noexcept; protected: xbuffer_adaptor_base() = default; ~xbuffer_adaptor_base() = default; xbuffer_adaptor_base(const self_type&) = default; self_type& operator=(const self_type&) = default; xbuffer_adaptor_base(self_type&&) = default; self_type& operator=(self_type&&) = default; }; template bool operator==(const xbuffer_adaptor_base& lhs, const xbuffer_adaptor_base& rhs); template bool operator!=(const xbuffer_adaptor_base& lhs, const xbuffer_adaptor_base& rhs); template bool operator<(const xbuffer_adaptor_base& lhs, const xbuffer_adaptor_base& rhs); template bool operator<=(const xbuffer_adaptor_base& lhs, const xbuffer_adaptor_base& rhs); template bool operator>(const xbuffer_adaptor_base& lhs, const xbuffer_adaptor_base& rhs); template bool operator>=(const xbuffer_adaptor_base& lhs, const xbuffer_adaptor_base& rhs); /******************* * xbuffer_adaptor * *******************/ template struct buffer_inner_types> { using base_type = detail::buffer_storage_t; 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 size_type = typename base_type::size_type; using difference_type = typename base_type::difference_type; using iterator = pointer; using const_iterator = const_pointer; using reverse_iterator = std::reverse_iterator; using const_reverse_iterator = std::reverse_iterator; using index_type = size_type; }; template class xbuffer_adaptor : private detail::buffer_storage_t, public xbuffer_adaptor_base> { public: using self_type = xbuffer_adaptor; using base_type = detail::buffer_storage_t; using buffer_base_type = xbuffer_adaptor_base; using allocator_type = typename base_type::allocator_type; using destructor_type = typename base_type::destructor_type; using value_type = typename buffer_base_type::value_type; using reference = typename buffer_base_type::reference; using const_reference = typename buffer_base_type::const_reference; using pointer = typename buffer_base_type::pointer; using const_pointer = typename buffer_base_type::const_pointer; using size_type = typename buffer_base_type::size_type; using difference_type = typename buffer_base_type::difference_type; using iterator = typename buffer_base_type::iterator; using const_iterator = typename buffer_base_type::const_iterator; using reverse_iterator = typename buffer_base_type::reverse_iterator; using const_reverse_iterator = typename buffer_base_type::const_reverse_iterator; using temporary_type = uvector; xbuffer_adaptor() = default; using base_type::base_type; ~xbuffer_adaptor() = default; xbuffer_adaptor(const self_type&) = default; self_type& operator=(const self_type&) = default; xbuffer_adaptor(self_type&&) = default; xbuffer_adaptor& operator=(self_type&&) = default; self_type& operator=(temporary_type&&); using base_type::data; using base_type::reset_data; using base_type::resize; using base_type::size; using base_type::swap; }; template void swap(xbuffer_adaptor& lhs, xbuffer_adaptor& rhs) noexcept; /********************* * xiterator_adaptor * *********************/ template class xiterator_adaptor; template struct buffer_inner_types> { using traits = std::iterator_traits; using const_traits = std::iterator_traits; using value_type = std::common_type_t; using reference = typename traits::reference; using const_reference = typename const_traits::reference; using pointer = typename traits::pointer; using const_pointer = typename const_traits::pointer; using difference_type = std::common_type_t; using size_type = std::make_unsigned_t; using iterator = I; using const_iterator = CI; using reverse_iterator = std::reverse_iterator; using const_reverse_iterator = std::reverse_iterator; using index_type = difference_type; }; template class xiterator_adaptor : public xbuffer_adaptor_base> { public: using self_type = xiterator_adaptor; using base_type = xbuffer_adaptor_base; using value_type = typename base_type::value_type; using allocator_type = std::allocator; using size_type = typename base_type::size_type; using iterator = typename base_type::iterator; using const_iterator = typename base_type::const_iterator; using temporary_type = uvector; xiterator_adaptor() = default; xiterator_adaptor(I it, CI cit, size_type size); ~xiterator_adaptor() = default; xiterator_adaptor(const self_type&) = default; xiterator_adaptor& operator=(const self_type&) = default; xiterator_adaptor(self_type&&) = default; xiterator_adaptor& operator=(self_type&&) = default; xiterator_adaptor& operator=(const temporary_type& rhs); xiterator_adaptor& operator=(temporary_type&& rhs); size_type size() const noexcept; void resize(size_type size); iterator data() noexcept; const_iterator data() const noexcept; void swap(self_type& rhs) noexcept; private: I m_it; CI m_cit; size_type m_size; }; template void swap(xiterator_adaptor& lhs, xiterator_adaptor& rhs) noexcept; template struct is_contiguous_container> : is_contiguous_container { }; /*************************** * xiterator_owner_adaptor * ***************************/ template class xiterator_owner_adaptor; template struct buffer_inner_types> { using iterator = typename IG::iterator; using const_iterator = typename IG::const_iterator; using reverse_iterator = std::reverse_iterator; using const_reverse_iterator = std::reverse_iterator; using traits = std::iterator_traits; using const_traits = std::iterator_traits; using value_type = std::common_type_t; using reference = typename traits::reference; using const_reference = typename const_traits::reference; using pointer = typename traits::pointer; using const_pointer = typename const_traits::pointer; using difference_type = std::common_type_t; using size_type = std::make_unsigned_t; using index_type = difference_type; }; template class xiterator_owner_adaptor : public xbuffer_adaptor_base> { public: using self_type = xiterator_owner_adaptor; using base_type = xbuffer_adaptor_base; using value_type = typename base_type::value_type; using allocator_type = std::allocator; using size_type = typename base_type::size_type; using iterator = typename base_type::iterator; using const_iterator = typename base_type::const_iterator; using temporary_type = uvector; xiterator_owner_adaptor(C&& c); ~xiterator_owner_adaptor() = default; xiterator_owner_adaptor(const self_type&); xiterator_owner_adaptor& operator=(const self_type&); xiterator_owner_adaptor(self_type&&); xiterator_owner_adaptor& operator=(self_type&&); xiterator_owner_adaptor& operator=(const temporary_type& rhs); xiterator_owner_adaptor& operator=(temporary_type&& rhs); size_type size() const noexcept; void resize(size_type size); iterator data() noexcept; const_iterator data() const noexcept; void swap(self_type& rhs) noexcept; private: void init_iterators(); C m_container; iterator m_it; const_iterator m_cit; size_type m_size; }; template void swap(xiterator_owner_adaptor& lhs, xiterator_owner_adaptor& rhs) noexcept; template struct is_contiguous_container> : is_contiguous_container { }; /************************** * make_xiterator_adaptor * **************************/ template auto make_xiterator_adaptor(C&& container, IG iterator_getter); /************************************ * temporary_container metafunction * ************************************/ template struct temporary_container { using type = C; }; template struct temporary_container> { using type = typename xbuffer_adaptor::temporary_type; }; template struct temporary_container> { using type = typename xiterator_adaptor::temporary_type; }; template struct temporary_container> { using type = typename xiterator_owner_adaptor::temporary_type; }; template using temporary_container_t = typename temporary_container::type; /********************************** * xbuffer_storage implementation * **********************************/ namespace detail { template inline xbuffer_storage::xbuffer_storage() : p_data(nullptr) , m_size(0) { } template template inline xbuffer_storage::xbuffer_storage(P&& data, size_type size, const allocator_type&) : p_data(std::forward

(data)) , m_size(size) { } template inline auto xbuffer_storage::size() const noexcept -> size_type { return m_size; } template inline void xbuffer_storage::resize(size_type size) { if (size != m_size) { XTENSOR_THROW(std::runtime_error, "xbuffer_storage not resizable"); } } template inline auto xbuffer_storage::data() noexcept -> pointer { return p_data; } template inline auto xbuffer_storage::data() const noexcept -> const_pointer { return p_data; } template inline void xbuffer_storage::swap(self_type& rhs) noexcept { using std::swap; swap(p_data, rhs.p_data); swap(m_size, rhs.m_size); } template template inline void xbuffer_storage::reset_data(P&& data, size_type size) noexcept { p_data = std::forward

(data); m_size = size; } } /**************************************** * xbuffer_owner_storage implementation * ****************************************/ namespace detail { template template inline xbuffer_owner_storage::xbuffer_owner_storage(P&& data, size_type size, const allocator_type& alloc) : m_data(std::forward

(data)) , m_size(size) , m_moved_from(false) , m_allocator(alloc) { } template inline xbuffer_owner_storage::~xbuffer_owner_storage() { if (!m_moved_from) { safe_destroy_deallocate(m_allocator, m_data.get(), m_size); m_size = 0; } } template inline auto xbuffer_owner_storage::operator=(const self_type& rhs) -> self_type& { using std::swap; if (this != &rhs) { allocator_type al = std::allocator_traits::select_on_container_copy_construction( rhs.get_allocator() ); pointer tmp = safe_init_allocate(al, rhs.m_size); if (xtrivially_default_constructible::value) { std::uninitialized_copy(rhs.m_data.get(), rhs.m_data.get() + rhs.m_size, tmp); } else { std::copy(rhs.m_data.get(), rhs.m_data.get() + rhs.m_size, tmp); } swap(m_data.get(), tmp); swap(m_allocator, al); safe_destroy_deallocate(al, tmp, m_size); m_size = rhs.m_size; } return *this; } template inline xbuffer_owner_storage::xbuffer_owner_storage(self_type&& rhs) : m_data(std::move(rhs.m_data)) , m_size(std::move(rhs.m_size)) , m_moved_from(std::move(rhs.m_moved_from)) , m_allocator(std::move(rhs.m_allocator)) { rhs.m_moved_from = true; rhs.m_size = 0; } template inline auto xbuffer_owner_storage::operator=(self_type&& rhs) -> self_type& { swap(rhs); return *this; } template inline auto xbuffer_owner_storage::size() const noexcept -> size_type { return m_size; } template void xbuffer_owner_storage::resize(size_type size) { using std::swap; if (size != m_size) { pointer tmp = safe_init_allocate(m_allocator, size); swap(m_data.get(), tmp); swap(m_size, size); safe_destroy_deallocate(m_allocator, tmp, size); } } template inline auto xbuffer_owner_storage::data() noexcept -> pointer { return m_data.get(); } template inline auto xbuffer_owner_storage::data() const noexcept -> const_pointer { return m_data.get(); } template inline auto xbuffer_owner_storage::get_allocator() const noexcept -> allocator_type { return allocator_type(m_allocator); } template inline void xbuffer_owner_storage::swap(self_type& rhs) noexcept { using std::swap; swap(m_data, rhs.m_data); swap(m_size, rhs.m_size); swap(m_allocator, rhs.m_allocator); } template template inline void xbuffer_owner_storage::reset_data(P&& data, size_type size, const allocator_type& alloc) noexcept { xbuffer_owner_storage tmp(std::forward

(data), size, alloc); this->swap(tmp); } } /**************************************** * xbuffer_smart_pointer implementation * ****************************************/ namespace detail { template template xbuffer_smart_pointer::xbuffer_smart_pointer(P&& data_ptr, size_type size, DT&& destruct) : p_data(data_ptr) , m_size(size) , m_destruct(std::forward

(destruct)) { } template auto xbuffer_smart_pointer::size() const noexcept -> size_type { return m_size; } template void xbuffer_smart_pointer::resize(size_type size) { if (m_size != size) { XTENSOR_THROW(std::runtime_error, "xbuffer_storage not resizeable"); } } template auto xbuffer_smart_pointer::data() noexcept -> pointer { return p_data; } template auto xbuffer_smart_pointer::data() const noexcept -> const_pointer { return p_data; } template void xbuffer_smart_pointer::swap(self_type& rhs) noexcept { using std::swap; swap(p_data, rhs.p_data); swap(m_size, rhs.m_size); swap(m_destruct, rhs.m_destruct); } template template void xbuffer_smart_pointer::reset_data(P&& data, size_type size, DT&& destruct) noexcept { p_data = std::forward

(data); m_size = size; m_destruct = destruct; } } /*************************************** * xbuffer_adaptor_base implementation * ***************************************/ template inline bool xbuffer_adaptor_base::empty() const noexcept { return derived_cast().size() == size_type(0); } template inline auto xbuffer_adaptor_base::operator[](size_type i) -> reference { return derived_cast().data()[static_cast(i)]; } template inline auto xbuffer_adaptor_base::operator[](size_type i) const -> const_reference { return derived_cast().data()[static_cast(i)]; } template inline auto xbuffer_adaptor_base::front() -> reference { return this->operator[](0); } template inline auto xbuffer_adaptor_base::front() const -> const_reference { return this->operator[](0); } template inline auto xbuffer_adaptor_base::back() -> reference { return this->operator[](derived_cast().size() - 1); } template inline auto xbuffer_adaptor_base::back() const -> const_reference { return this->operator[](derived_cast().size() - 1); } template inline auto xbuffer_adaptor_base::begin() noexcept -> iterator { return derived_cast().data(); } template inline auto xbuffer_adaptor_base::end() noexcept -> iterator { return derived_cast().data() + static_cast(derived_cast().size()); } template inline auto xbuffer_adaptor_base::begin() const noexcept -> const_iterator { return derived_cast().data(); } template inline auto xbuffer_adaptor_base::end() const noexcept -> const_iterator { return derived_cast().data() + static_cast(derived_cast().size()); } template inline auto xbuffer_adaptor_base::cbegin() const noexcept -> const_iterator { return begin(); } template inline auto xbuffer_adaptor_base::cend() const noexcept -> const_iterator { return end(); } template inline auto xbuffer_adaptor_base::rbegin() noexcept -> reverse_iterator { return reverse_iterator(end()); } template inline auto xbuffer_adaptor_base::rend() noexcept -> reverse_iterator { return reverse_iterator(begin()); } template inline auto xbuffer_adaptor_base::rbegin() const noexcept -> const_reverse_iterator { return const_reverse_iterator(end()); } template inline auto xbuffer_adaptor_base::rend() const noexcept -> const_reverse_iterator { return const_reverse_iterator(begin()); } template inline auto xbuffer_adaptor_base::crbegin() const noexcept -> const_reverse_iterator { return rbegin(); } template inline auto xbuffer_adaptor_base::crend() const noexcept -> const_reverse_iterator { return rend(); } template inline auto xbuffer_adaptor_base::derived_cast() noexcept -> derived_type& { return *static_cast(this); } template inline auto xbuffer_adaptor_base::derived_cast() const noexcept -> const derived_type& { return *static_cast(this); } template inline bool operator==(const xbuffer_adaptor_base& lhs, const xbuffer_adaptor_base& rhs) { return lhs.derived_cast().size() == rhs.derived_cast().size() && std::equal(lhs.begin(), lhs.end(), rhs.begin()); } template inline bool operator!=(const xbuffer_adaptor_base& lhs, const xbuffer_adaptor_base& rhs) { return !(lhs == rhs); } template inline bool operator<(const xbuffer_adaptor_base& lhs, const xbuffer_adaptor_base& rhs) { return std::lexicographical_compare( lhs.begin(), lhs.end(), rhs.begin(), rhs.end(), std::less() ); } template inline bool operator<=(const xbuffer_adaptor_base& lhs, const xbuffer_adaptor_base& rhs) { return std::lexicographical_compare( lhs.begin(), lhs.end(), rhs.begin(), rhs.end(), std::less_equal() ); } template inline bool operator>(const xbuffer_adaptor_base& lhs, const xbuffer_adaptor_base& rhs) { return std::lexicographical_compare( lhs.begin(), lhs.end(), rhs.begin(), rhs.end(), std::greater() ); } template inline bool operator>=(const xbuffer_adaptor_base& lhs, const xbuffer_adaptor_base& rhs) { return std::lexicographical_compare( lhs.begin(), lhs.end(), rhs.begin(), rhs.end(), std::greater_equal() ); } /********************************** * xbuffer_adaptor implementation * **********************************/ template inline auto xbuffer_adaptor::operator=(temporary_type&& tmp) -> self_type& { base_type::resize(tmp.size()); std::copy(tmp.cbegin(), tmp.cend(), this->begin()); return *this; } template inline void swap(xbuffer_adaptor& lhs, xbuffer_adaptor& rhs) noexcept { lhs.swap(rhs); } /************************************ * xiterator_adaptor implementation * ************************************/ template inline xiterator_adaptor::xiterator_adaptor(I it, CI cit, size_type size) : m_it(it) , m_cit(cit) , m_size(size) { } template inline auto xiterator_adaptor::operator=(const temporary_type& rhs) -> self_type& { resize(rhs.size()); std::copy(rhs.cbegin(), rhs.cend(), m_it); return *this; } template inline auto xiterator_adaptor::operator=(temporary_type&& rhs) -> self_type& { return (*this = rhs); } template inline auto xiterator_adaptor::size() const noexcept -> size_type { return m_size; } template inline void xiterator_adaptor::resize(size_type size) { if (m_size != size) { XTENSOR_THROW(std::runtime_error, "xiterator_adaptor not resizeable"); } } template inline auto xiterator_adaptor::data() noexcept -> iterator { return m_it; } template inline auto xiterator_adaptor::data() const noexcept -> const_iterator { return m_cit; } template inline void xiterator_adaptor::swap(self_type& rhs) noexcept { using std::swap; swap(m_it, rhs.m_it); swap(m_cit, rhs.m_cit); swap(m_size, rhs.m_size); } template inline void swap(xiterator_adaptor& lhs, xiterator_adaptor& rhs) noexcept { lhs.swap(rhs); } /****************************************** * xiterator_owner_adaptor implementation * ******************************************/ template inline xiterator_owner_adaptor::xiterator_owner_adaptor(C&& c) : m_container(std::move(c)) { init_iterators(); } template inline xiterator_owner_adaptor::xiterator_owner_adaptor(const self_type& rhs) : m_container(rhs.m_container) { init_iterators(); } template inline xiterator_owner_adaptor& xiterator_owner_adaptor::operator=(const self_type& rhs) { m_container = rhs.m_container; init_iterators(); } template inline xiterator_owner_adaptor::xiterator_owner_adaptor(self_type&& rhs) : m_container(std::move(rhs.m_container)) { init_iterators(); } template inline xiterator_owner_adaptor& xiterator_owner_adaptor::operator=(self_type&& rhs) { m_container = std::move(rhs.m_container); init_iterators(); } template inline xiterator_owner_adaptor& xiterator_owner_adaptor::operator=(const temporary_type& rhs) { resize(rhs.size()); std::copy(rhs.cbegin(), rhs.cend(), m_it); return *this; } template inline xiterator_owner_adaptor& xiterator_owner_adaptor::operator=(temporary_type&& rhs) { return (*this = rhs); } template inline auto xiterator_owner_adaptor::size() const noexcept -> size_type { return m_size; } template inline void xiterator_owner_adaptor::resize(size_type size) { if (m_size != size) { XTENSOR_THROW(std::runtime_error, "xiterator_owner_adaptor not resizeable"); } } template inline auto xiterator_owner_adaptor::data() noexcept -> iterator { return m_it; } template inline auto xiterator_owner_adaptor::data() const noexcept -> const_iterator { return m_cit; } template inline void xiterator_owner_adaptor::swap(self_type& rhs) noexcept { using std::swap; swap(m_container, rhs.m_container); init_iterators(); rhs.init_iterators(); } template inline void xiterator_owner_adaptor::init_iterators() { m_it = IG::begin(m_container); m_cit = IG::cbegin(m_container); m_size = IG::size(m_container); } template inline void swap(xiterator_owner_adaptor& lhs, xiterator_owner_adaptor& rhs) noexcept { lhs.swap(rhs); } /***************************************** * make_xiterator_adaptor implementation * *****************************************/ namespace detail { template ::value> struct xiterator_adaptor_builder { using iterator = decltype(IG::begin(std::declval())); using const_iterator = decltype(IG::cbegin(std::declval())); using type = xiterator_adaptor; inline static type build(C& c) { return type(IG::begin(c), IG::cbegin(c), IG::size(c)); } }; template struct xiterator_adaptor_builder { using type = xiterator_owner_adaptor; inline static type build(C&& c) { return type(std::move(c)); } }; } template inline auto make_xiterator_adaptor(C&& container, IG) { using builder_type = detail::xiterator_adaptor_builder; return builder_type::build(std::forward(container)); } } #endif