| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316 | /* Copyright 2016-2018 Joaquin M Lopez Munoz. * 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) * * See http://www.boost.org/libs/poly_collection for library home page. */#ifndef BOOST_POLY_COLLECTION_DETAIL_SEGMENT_HPP#define BOOST_POLY_COLLECTION_DETAIL_SEGMENT_HPP#if defined(_MSC_VER)#pragma once#endif#include <iterator>#include <memory>#include <type_traits>#include <utility>namespace boost{namespace poly_collection{namespace detail{/* segment<Model,Allocator> encapsulates implementations of * Model::segment_backend virtual interface under a value-semantics type for * use by poly_collection. The techique is described by Sean Parent at slides * 157-205 of * https://github.com/sean-parent/sean-parent.github.com/wiki/ *   presentations/2013-09-11-cpp-seasoning/cpp-seasoning.pdf * with one twist: when the type of the implementation can be known at compile * time, a downcast is done and non-virtual member functions (named with a nv_ * prefix) are used: this increases the performance of some operations. */template<typename Model,typename Allocator>class segment{public:  using value_type=typename Model::value_type;  using allocator_type=Allocator; /* needed for uses-allocator construction */  using base_iterator=typename Model::base_iterator;  using const_base_iterator=typename Model::const_base_iterator;  using base_sentinel=typename Model::base_sentinel;  using const_base_sentinel=typename Model::const_base_sentinel;  template<typename T>  using iterator=typename Model::template iterator<T>;  template<typename T>  using const_iterator=typename Model::template const_iterator<T>;  template<typename T>  static segment make(const allocator_type& al)  {    return segment_backend_implementation<T>::make(al);  }  /* clones the implementation of x with no elements */  static segment make_from_prototype(const segment& x,const allocator_type& al)  {    return {from_prototype{},x,al};  }  segment(const segment& x):    pimpl{x.impl().copy()}{set_sentinel();}  segment(segment&& x)=default;  segment(const segment& x,const allocator_type& al):    pimpl{x.impl().copy(al)}{set_sentinel();}  /* TODO: try ptr-level move before impl().move() */  segment(segment&& x,const allocator_type& al):    pimpl{x.impl().move(al)}{set_sentinel();}  segment& operator=(const segment& x)  {    pimpl=allocator_traits::propagate_on_container_copy_assignment::value?      x.impl().copy():x.impl().copy(impl().get_allocator());    set_sentinel();    return *this;  }    segment& operator=(segment&& x)  {    pimpl=x.impl().move(      allocator_traits::propagate_on_container_move_assignment::value?      x.impl().get_allocator():impl().get_allocator());    set_sentinel();    return *this;  }  friend bool operator==(const segment& x,const segment& y)  {    if(typeid(*(x.pimpl))!=typeid(*(y.pimpl)))return false;    else return x.impl().equal(y.impl());  }  friend bool operator!=(const segment& x,const segment& y){return !(x==y);}  base_iterator        begin()const noexcept{return impl().begin();}  template<typename U>  base_iterator        begin()const noexcept{return impl<U>().nv_begin();}  base_iterator        end()const noexcept{return impl().end();}  template<typename U>  base_iterator        end()const noexcept{return impl<U>().nv_end();}  base_sentinel        sentinel()const noexcept{return snt;}  bool                 empty()const noexcept{return impl().empty();}  template<typename U>  bool                 empty()const noexcept{return impl<U>().nv_empty();}  std::size_t          size()const noexcept{return impl().size();}  template<typename U>  std::size_t          size()const noexcept{return impl<U>().nv_size();}  std::size_t          max_size()const noexcept{return impl().max_size();}  template<typename U>  std::size_t          max_size()const noexcept                         {return impl<U>().nv_max_size();}  void                 reserve(std::size_t n){filter(impl().reserve(n));}  template<typename U>  void                 reserve(std::size_t n){filter(impl<U>().nv_reserve(n));}  std::size_t          capacity()const noexcept{return impl().capacity();}  template<typename U>  std::size_t          capacity()const noexcept                         {return impl<U>().nv_capacity();}  void                 shrink_to_fit(){filter(impl().shrink_to_fit());}  template<typename U>  void                 shrink_to_fit(){filter(impl<U>().nv_shrink_to_fit());}  template<typename U,typename Iterator,typename... Args>  base_iterator emplace(Iterator it,Args&&... args)  {    return filter(impl<U>().nv_emplace(it,std::forward<Args>(args)...));  }  template<typename U,typename... Args>  base_iterator emplace_back(Args&&... args)  {    return filter(impl<U>().nv_emplace_back(std::forward<Args>(args)...));  }  template<typename T>  base_iterator push_back(const T& x)  {    return filter(impl().push_back(subaddress(x)));  }  template<    typename T,    typename std::enable_if<      !std::is_lvalue_reference<T>::value&&!std::is_const<T>::value    >::type* =nullptr  >  base_iterator push_back(T&& x)  {    return filter(impl().push_back_move(subaddress(x)));  }  template<typename U>  base_iterator push_back_terminal(U&& x)  {    return filter(      impl<typename std::decay<U>::type>().nv_push_back(std::forward<U>(x)));  }  template<typename T>  base_iterator insert(const_base_iterator it,const T& x)  {    return filter(impl().insert(it,subaddress(x)));  }  template<typename U,typename T>  base_iterator insert(const_iterator<U> it,const T& x)  {    return filter(      impl<U>().nv_insert(it,*static_cast<const U*>(subaddress(x))));  }  template<    typename T,    typename std::enable_if<      !std::is_lvalue_reference<T>::value&&!std::is_const<T>::value    >::type* =nullptr  >  base_iterator insert(const_base_iterator it,T&& x)  {    return filter(impl().insert_move(it,subaddress(x)));  }  template<    typename U,typename T,    typename std::enable_if<      !std::is_lvalue_reference<T>::value&&!std::is_const<T>::value    >::type* =nullptr  >  base_iterator insert(const_iterator<U> it,T&& x)  {    return filter(      impl<U>().nv_insert(it,std::move(*static_cast<U*>(subaddress(x)))));  }  template<typename InputIterator>  base_iterator insert(InputIterator first,InputIterator last)  {    return filter(      impl<typename std::iterator_traits<InputIterator>::value_type>().        nv_insert(first,last));  }  template<typename InputIterator>  base_iterator insert(    const_base_iterator it,InputIterator first,InputIterator last)  {    return insert(      const_iterator<        typename std::iterator_traits<InputIterator>::value_type>(it),      first,last);  }  template<typename U,typename InputIterator>  base_iterator insert(    const_iterator<U> it,InputIterator first,InputIterator last)  {    return filter(impl<U>().nv_insert(it,first,last));  }  base_iterator erase(const_base_iterator it)  {    return filter(impl().erase(it));  }  template<typename U>  base_iterator erase(const_iterator<U> it)  {    return filter(impl<U>().nv_erase(it));  }  base_iterator erase(const_base_iterator f,const_base_iterator l)  {    return filter(impl().erase(f,l));  }  template<typename U>  base_iterator erase(const_iterator<U> f,const_iterator<U> l)  {    return filter(impl<U>().nv_erase(f,l));  }  template<typename Iterator>  base_iterator erase_till_end(Iterator f)  {    return filter(impl().erase_till_end(f));  }  template<typename Iterator>  base_iterator erase_from_begin(Iterator l)  {    return filter(impl().erase_from_begin(l));  }    void                 clear()noexcept{filter(impl().clear());}  template<typename U>  void                 clear()noexcept{filter(impl<U>().nv_clear());}private:  using allocator_traits=std::allocator_traits<Allocator>;  using segment_backend=typename Model::template segment_backend<Allocator>;  template<typename Concrete>  using segment_backend_implementation=typename Model::    template segment_backend_implementation<Concrete,Allocator>;  using segment_backend_unique_ptr=    typename segment_backend::segment_backend_unique_ptr;  using range=typename segment_backend::range;  struct from_prototype{};  segment(segment_backend_unique_ptr&& pimpl):    pimpl{std::move(pimpl)}{set_sentinel();}  segment(from_prototype,const segment& x,const allocator_type& al):    pimpl{x.impl().empty_copy(al)}{set_sentinel();}  segment_backend&       impl()noexcept{return *pimpl;}  const segment_backend& impl()const noexcept{return *pimpl;}  template<typename Concrete>  segment_backend_implementation<Concrete>& impl()noexcept  {    return static_cast<segment_backend_implementation<Concrete>&>(impl());  }  template<typename Concrete>  const segment_backend_implementation<Concrete>& impl()const noexcept  {    return      static_cast<const segment_backend_implementation<Concrete>&>(impl());  }  template<typename T>  static void*         subaddress(T& x){return Model::subaddress(x);}  template<typename T>  static const void*   subaddress(const T& x){return Model::subaddress(x);}  void          set_sentinel(){filter(impl().end());}  void          filter(base_sentinel x){snt=x;}  base_iterator filter(const range& x){snt=x.second;return x.first;}  segment_backend_unique_ptr pimpl;  base_sentinel              snt;};} /* namespace poly_collection::detail */} /* namespace poly_collection */} /* namespace boost */#endif
 |