/*============================================================================= Copyright (c) 2011-2017 Bolero MURAKAMI https://github.com/bolero-MURAKAMI/Sprout Distributed under the Boost Software License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) =============================================================================*/ #ifndef SPROUT_SUB_ARRAY_SUB_ARRAY_HPP #define SPROUT_SUB_ARRAY_SUB_ARRAY_HPP #include <utility> #include <stdexcept> #include <type_traits> #include <sprout/config.hpp> #include <sprout/index_tuple/metafunction.hpp> #include <sprout/container/traits.hpp> #include <sprout/container/functions.hpp> #include <sprout/iterator/operation.hpp> #include <sprout/algorithm/cxx14/fill_n.hpp> #include <sprout/utility/swap.hpp> #include <sprout/utility/forward.hpp> #include <sprout/utility/move.hpp> namespace sprout { namespace detail { struct is_non_reference_array_tag {}; struct is_not_non_reference_array_tag {}; template<typename Container> class sub_array_impl { public: typedef Container container_type; typedef typename std::remove_reference<container_type>::type internal_type; public: SPROUT_STATIC_CONSTEXPR bool is_reference = std::is_reference<container_type>::value; SPROUT_STATIC_CONSTEXPR bool is_const = std::is_const<internal_type>::value; public: typedef typename sprout::container_traits<internal_type>::const_iterator impl_const_iterator; typedef typename sprout::container_traits<internal_type>::difference_type impl_difference_type; public: typedef typename std::conditional< is_reference, internal_type*, typename std::remove_const<internal_type>::type >::type holder_type; typedef typename std::conditional< is_reference, internal_type&, internal_type const& >::type param_type; typedef internal_type const& const_param_type; public: typedef typename std::conditional< std::is_array<holder_type>::value, sprout::detail::is_non_reference_array_tag, sprout::detail::is_not_non_reference_array_tag >::type array_tag; public: template<typename Arr> static SPROUT_CONSTEXPR typename std::enable_if< std::is_reference<Arr>::value, holder_type >::type to_holder(param_type arr) { return &arr; } template<typename Arr> static SPROUT_CONSTEXPR typename std::enable_if< !std::is_reference<Arr>::value, holder_type const& >::type to_holder(param_type arr) { return arr; } template<typename Arr> static SPROUT_CONSTEXPR typename std::enable_if< std::is_reference<Arr>::value, param_type >::type to_param(holder_type arr) { return *arr; } template<typename Arr> static SPROUT_CONSTEXPR typename std::enable_if< !std::is_reference<Arr>::value, param_type >::type to_param(holder_type& arr) { return arr; } template<typename Arr> static SPROUT_CONSTEXPR typename std::enable_if< !std::is_reference<Arr>::value, param_type >::type to_param(holder_type const& arr) { return arr; } template<typename Arr> static SPROUT_CONSTEXPR typename std::enable_if< std::is_reference<Arr>::value, const_param_type >::type to_const_param(holder_type arr) { return *arr; } template<typename Arr> static SPROUT_CONSTEXPR typename std::enable_if< !std::is_reference<Arr>::value, const_param_type >::type to_const_param(holder_type const& arr) { return arr; } template<typename Arr> static SPROUT_CONSTEXPR typename std::enable_if< std::is_reference<Arr>::value, internal_type& >::type to_held(holder_type arr) { return *arr; } template<typename Arr> static SPROUT_CONSTEXPR typename std::enable_if< !std::is_reference<Arr>::value, internal_type& >::type to_held(holder_type& arr) { return arr; } template<typename Arr> static SPROUT_CONSTEXPR typename std::enable_if< !std::is_reference<Arr>::value, internal_type const& >::type to_held(holder_type const& arr) { return arr; } template<typename Arr> static SPROUT_CONSTEXPR typename std::enable_if< std::is_reference<Arr>::value, internal_type const& >::type to_const_held(holder_type arr) { return *arr; } template<typename Arr> static SPROUT_CONSTEXPR typename std::enable_if< !std::is_reference<Arr>::value, internal_type const& >::type to_const_held(holder_type const& arr) { return arr; } public: holder_type array_; impl_difference_type to_first_; impl_difference_type to_last_; public: SPROUT_CONSTEXPR sub_array_impl() : array_() , to_first_() , to_last_() {} sub_array_impl(sub_array_impl const&) = default; public: template<typename ContainerTag, sprout::index_t... Indexes> SPROUT_CONSTEXPR sub_array_impl( ContainerTag, param_type arr, sprout::index_tuple<Indexes...>, impl_const_iterator first, impl_const_iterator last, typename std::enable_if<std::is_same<ContainerTag, sprout::detail::is_non_reference_array_tag>::value>::type* = 0 ) : array_{to_holder<Container>(arr)[Indexes]...} , to_first_(sprout::distance(sprout::cbegin(arr), first)) , to_last_(sprout::distance(sprout::cbegin(arr), last)) {} template<typename ContainerTag, sprout::index_t... Indexes> SPROUT_CONSTEXPR sub_array_impl( ContainerTag, param_type arr, sprout::index_tuple<Indexes...>, impl_const_iterator first, impl_const_iterator last, typename std::enable_if<!std::is_same<ContainerTag, sprout::detail::is_non_reference_array_tag>::value>::type* = 0 ) : array_(to_holder<Container>(arr)) , to_first_(sprout::distance(sprout::cbegin(arr), first)) , to_last_(sprout::distance(sprout::cbegin(arr), last)) {} template<typename ContainerTag, sprout::index_t... Indexes> SPROUT_CONSTEXPR sub_array_impl( ContainerTag, param_type arr, sprout::index_tuple<Indexes...>, impl_difference_type to_first, impl_difference_type to_last, typename std::enable_if<std::is_same<ContainerTag, sprout::detail::is_non_reference_array_tag>::value>::type* = 0 ) : array_{to_holder<Container>(arr)[Indexes]...} , to_first_(to_first) , to_last_(to_last) {} template<typename ContainerTag, sprout::index_t... Indexes> SPROUT_CONSTEXPR sub_array_impl( ContainerTag, param_type arr, sprout::index_tuple<Indexes...>, impl_difference_type to_first, impl_difference_type to_last, typename std::enable_if<!std::is_same<ContainerTag, sprout::detail::is_non_reference_array_tag>::value>::type* = 0 ) : array_(to_holder<Container>(arr)) , to_first_(to_first) , to_last_(to_last) {} }; } // namespace detail // // sub_array // template<typename Container> class sub_array : public sprout::container_traits_facade<typename std::remove_reference<Container>::type> { private: typedef sprout::detail::sub_array_impl<Container> impl_type; typedef sprout::container_traits_facade<typename std::remove_reference<Container>::type> facade_type; public: typedef typename impl_type::container_type container_type; typedef typename impl_type::internal_type internal_type; public: SPROUT_STATIC_CONSTEXPR bool is_reference = impl_type::is_reference; SPROUT_STATIC_CONSTEXPR bool is_const = impl_type::is_const; public: typedef typename facade_type::value_type value_type; typedef typename facade_type::iterator iterator; typedef typename facade_type::const_iterator const_iterator; typedef typename facade_type::reference reference; typedef typename facade_type::const_reference const_reference; typedef typename facade_type::size_type size_type; typedef typename facade_type::difference_type difference_type; typedef typename facade_type::pointer pointer; typedef typename facade_type::const_pointer const_pointer; public: SPROUT_STATIC_CONSTEXPR size_type enumerable_size = sprout::detail::static_size_or_zero<facade_type>::value; public: typedef typename impl_type::holder_type holder_type; typedef typename impl_type::param_type param_type; typedef typename impl_type::const_param_type const_param_type; private: typedef typename impl_type::array_tag array_tag; private: impl_type impl_; public: // construct/copy/destroy: SPROUT_CONSTEXPR sub_array() SPROUT_DEFAULTED_DEFAULT_CONSTRUCTOR_DECL sub_array(sub_array const&) = default; SPROUT_CONSTEXPR sub_array(param_type arr, const_iterator first, const_iterator last) : impl_( array_tag(), arr, sprout::make_index_tuple<enumerable_size>::make(), first, last ) {} SPROUT_CONSTEXPR sub_array(param_type arr, difference_type to_first, difference_type to_last) : impl_( array_tag(), arr, sprout::make_index_tuple<enumerable_size>::make(), to_first, to_last ) {} SPROUT_CONSTEXPR sub_array(sub_array const& other, const_iterator first, const_iterator last) : impl_( array_tag(), impl_type::template to_param<Container>(other.impl_.array_), sprout::make_index_tuple<enumerable_size>::make(), sprout::distance(sprout::begin(other.get_internal()), first), sprout::distance(sprout::begin(other.get_internal()), last) ) {} SPROUT_CONSTEXPR sub_array(sub_array const& other, difference_type to_first, difference_type to_last) : impl_( array_tag(), impl_type::template to_param<Container>(other.impl_.array_), sprout::make_index_tuple<enumerable_size>::make(), other.impl_.to_first_ + to_first, other.impl_.to_first_ + to_last ) {} template<typename Container2> SPROUT_CXX14_CONSTEXPR sub_array& operator=(sub_array<Container2> const& rhs) { impl_.array_ = rhs.impl_.array_; impl_.to_first_ = rhs.impl_.to_first_; impl_.to_last_ = rhs.impl_.to_last_; return *this; } template<typename Container2> SPROUT_CXX14_CONSTEXPR sub_array& operator=(sub_array<Container2>&& rhs) { impl_.array_ = sprout::move(rhs.impl_.array_); impl_.to_first_ = sprout::move(rhs.impl_.to_first_); impl_.to_last_ = sprout::move(rhs.impl_.to_last_); return *this; } SPROUT_CXX14_CONSTEXPR void fill(const_reference value) { sprout::fill_n(begin(), size(), value); } template<typename Container2> SPROUT_CXX14_CONSTEXPR void swap(sub_array<Container2>& other) SPROUT_NOEXCEPT_IF_EXPR(sprout::swap(other.impl_.array_, impl_.array_)) { sprout::swap(other.impl_.array_, impl_.array_); sprout::swap(other.impl_.to_first_, impl_.to_first_); sprout::swap(other.impl_.to_last_, impl_.to_last_); } // iterators: SPROUT_CXX14_CONSTEXPR iterator begin() { return sprout::next(sprout::begin(get_internal()), impl_.to_first_); } SPROUT_CONSTEXPR const_iterator begin() const { return sprout::next(sprout::begin(get_internal()), impl_.to_first_); } SPROUT_CXX14_CONSTEXPR iterator end() { return sprout::next(sprout::begin(get_internal()), impl_.to_last_); } SPROUT_CONSTEXPR const_iterator end() const { return sprout::next(sprout::begin(get_internal()), impl_.to_last_); } SPROUT_CONSTEXPR const_iterator cbegin() const { return sprout::next(sprout::begin(get_internal()), impl_.to_first_); } SPROUT_CONSTEXPR const_iterator cend() const { return sprout::next(sprout::begin(get_internal()), impl_.to_last_); } // capacity: SPROUT_CONSTEXPR size_type size() const { return impl_.to_last_ - impl_.to_first_; } SPROUT_CONSTEXPR size_type max_size() const { return size(); } SPROUT_CONSTEXPR bool empty() const { return impl_.to_first_ == impl_.to_last_; } // element access: SPROUT_CXX14_CONSTEXPR reference operator[](size_type i) { return *sprout::next(sprout::begin(get_internal()), impl_.to_first_ + i); } SPROUT_CONSTEXPR const_reference operator[](size_type i) const { return *sprout::next(sprout::begin(get_internal()), impl_.to_first_ + i); } SPROUT_CXX14_CONSTEXPR reference at(size_type i) { return i < size() ? *sprout::next(sprout::begin(get_internal()), impl_.to_first_ + i) : (throw std::out_of_range("sub_array<>: index out of range"), *sprout::next(sprout::begin(get_internal()), impl_.to_first_ + i)) ; } SPROUT_CONSTEXPR const_reference at(size_type i) const { return i < size() ? *sprout::next(sprout::begin(get_internal()), impl_.to_first_ + i) : (throw std::out_of_range("sub_array<>: index out of range"), *sprout::next(sprout::begin(get_internal()), impl_.to_first_ + i)) ; } SPROUT_CXX14_CONSTEXPR reference front() { return *sprout::next(sprout::begin(get_internal()), impl_.to_first_); } SPROUT_CONSTEXPR const_reference front() const { return *sprout::next(sprout::begin(get_internal()), impl_.to_first_); } SPROUT_CXX14_CONSTEXPR reference back() { return *sprout::next(sprout::begin(get_internal()), impl_.to_last_ - 1); } SPROUT_CONSTEXPR const_reference back() const { return *sprout::next(sprout::begin(get_internal()), impl_.to_last_ - 1); } SPROUT_CXX14_CONSTEXPR pointer data() { return get_internal().data() + impl_.to_first_; } SPROUT_CONSTEXPR const_pointer data() const { return get_internal().data() + impl_.to_first_; } // others: SPROUT_CXX14_CONSTEXPR pointer c_array() { return data(); } SPROUT_CONSTEXPR const_pointer c_array() const { return data(); } SPROUT_CXX14_CONSTEXPR void assign(const_reference value) { fill(value); } SPROUT_CXX14_CONSTEXPR void rangecheck(size_type i) const { return i >= size() ? throw std::out_of_range("uuid: index out of range") : (void)0 ; } SPROUT_CXX14_CONSTEXPR internal_type& get_internal() { return impl_type::template to_held<Container>(impl_.array_); } SPROUT_CONSTEXPR internal_type const& get_internal() const { return impl_type::template to_const_held<Container>(impl_.array_); } SPROUT_CXX14_CONSTEXPR internal_type& get_array() { return impl_type::template to_held<Container>(impl_.array_); } SPROUT_CONSTEXPR internal_type const& get_array() const { return impl_type::template to_const_held<Container>(impl_.array_); } SPROUT_CONSTEXPR difference_type to_first() const { return impl_.to_first_; } SPROUT_CONSTEXPR difference_type to_last() const { return impl_.to_last_; } SPROUT_CONSTEXPR difference_type from_begin() const { return impl_.to_first_; } SPROUT_CONSTEXPR difference_type from_end() const { return impl_.to_last_ - sprout::size(get_internal()); } SPROUT_CXX14_CONSTEXPR sub_array& window(difference_type to_first = 0) { impl_.to_first_ = to_first; impl_.to_last_ = size(); return *this; } SPROUT_CXX14_CONSTEXPR sub_array& window(difference_type to_first, difference_type to_last) { impl_.to_first_ = to_first; impl_.to_last_ = to_last; return *this; } SPROUT_CONSTEXPR sub_array window(difference_type to_first = 0) const { return sub_array(impl_.array_, to_first, size()); } SPROUT_CONSTEXPR sub_array window(difference_type to_first, difference_type to_last) const { return sub_array(impl_.array_, to_first, to_last); } SPROUT_CONSTEXPR sub_array cwindow(difference_type to_first = 0) const { return window(to_first); } SPROUT_CONSTEXPR sub_array cwindow(difference_type to_first, difference_type to_last) const { return window(to_first, to_last); } SPROUT_CXX14_CONSTEXPR sub_array& offset(difference_type from_begin = 0, difference_type from_end = 0) { impl_.to_first_ += from_begin; impl_.to_last_ += from_end; return *this; } SPROUT_CONSTEXPR sub_array offset(difference_type from_begin = 0, difference_type from_end = 0) const { return sub_array(impl_.array_, impl_.to_first_ + from_begin, impl_.to_last_ + from_end); } SPROUT_CONSTEXPR sub_array coffset(difference_type from_begin = 0, difference_type from_end = 0) const { return offset(from_begin, from_end); } SPROUT_CXX14_CONSTEXPR iterator nth(size_type i) { return i < size() ? sprout::next(begin(), i) : (throw std::out_of_range("sub_array<>: index out of range"), iterator()) ; } SPROUT_CONSTEXPR const_iterator nth(size_type i) const { return i < size() ? sprout::next(begin(), i) : (throw std::out_of_range("array<>: index out of range"), const_iterator()) ; } SPROUT_CXX14_CONSTEXPR size_type index_of(iterator p) { return sprout::distance(begin(), p); } SPROUT_CONSTEXPR size_type index_of(const_iterator p) const { return sprout::distance(begin(), p); } SPROUT_CXX14_CONSTEXPR void push_back(value_type const& x) { impl_.array_[impl_.to_last_] = x; ++impl_.to_last_; } SPROUT_CXX14_CONSTEXPR void push_back(value_type&& x) { impl_.array_[impl_.to_last_] = sprout::move(x); ++impl_.to_last_; } SPROUT_CXX14_CONSTEXPR void pop_back() { impl_.array_[impl_.to_last_ - 1] = value_type(); --impl_.to_last_; } SPROUT_CXX14_CONSTEXPR void drop_back() { --impl_.to_last_; } SPROUT_CXX14_CONSTEXPR void push_front(value_type const& x) { impl_.array_[impl_.to_first_ - 1] = x; --impl_.to_first_; } SPROUT_CXX14_CONSTEXPR void push_front(value_type&& x) { impl_.array_[impl_.to_first_ - 1] = sprout::move(x); --impl_.to_first_; } SPROUT_CXX14_CONSTEXPR void pop_front() { impl_.array_[impl_.to_first_] = value_type(); ++impl_.to_first_; } SPROUT_CXX14_CONSTEXPR void drop_front() { ++impl_.to_first_; } }; template<typename Container> SPROUT_CONSTEXPR_OR_CONST typename sprout::sub_array<Container>::size_type sprout::sub_array<Container>::enumerable_size; // // swap // template<typename Container> inline SPROUT_CXX14_CONSTEXPR void swap(sprout::sub_array<Container>& lhs, sprout::sub_array<Container>& rhs) SPROUT_NOEXCEPT_IF_EXPR(lhs.swap(rhs)) { lhs.swap(rhs); } } // namespace sprout #include <sprout/sub_array/container.hpp> #endif // #ifndef SPROUT_SUB_ARRAY_SUB_ARRAY_HPP