Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-12-16 10:04:46

0001 /* Copyright 2016-2024 Joaquin M Lopez Munoz.
0002  * Distributed under the Boost Software License, Version 1.0.
0003  * (See accompanying file LICENSE_1_0.txt or copy at
0004  * http://www.boost.org/LICENSE_1_0.txt)
0005  *
0006  * See http://www.boost.org/libs/poly_collection for library home page.
0007  */
0008 
0009 #ifndef BOOST_POLY_COLLECTION_DETAIL_SEGMENT_HPP
0010 #define BOOST_POLY_COLLECTION_DETAIL_SEGMENT_HPP
0011 
0012 #if defined(_MSC_VER)
0013 #pragma once
0014 #endif
0015 
0016 #include <iterator>
0017 #include <memory>
0018 #include <type_traits>
0019 #include <utility>
0020 
0021 namespace boost{
0022 
0023 namespace poly_collection{
0024 
0025 namespace detail{
0026 
0027 /* segment<Model,Allocator> encapsulates implementations of
0028  * Model::segment_backend virtual interface under a value-semantics type for
0029  * use by poly_collection. The techique is described by Sean Parent at slides
0030  * 157-205 of
0031  * https://github.com/sean-parent/sean-parent.github.com/wiki/
0032  *   presentations/2013-09-11-cpp-seasoning/cpp-seasoning.pdf
0033  * with one twist: when the type of the implementation can be known at compile
0034  * time, a downcast is done and non-virtual member functions (named with a nv_
0035  * prefix) are used: this increases the performance of some operations.
0036  */
0037 
0038 template<typename Model,typename Allocator>
0039 class segment
0040 {
0041 public:
0042   using value_type=typename Model::value_type;
0043   using allocator_type=Allocator; /* needed for uses-allocator construction */
0044   using base_iterator=typename Model::base_iterator;
0045   using const_base_iterator=typename Model::const_base_iterator;
0046   using base_sentinel=typename Model::base_sentinel;
0047   using const_base_sentinel=typename Model::const_base_sentinel;
0048   template<typename T>
0049   using iterator=typename Model::template iterator<T>;
0050   template<typename T>
0051   using const_iterator=typename Model::template const_iterator<T>;
0052 
0053   template<typename T>
0054   static segment make(const allocator_type& al)
0055   {
0056     return segment_backend_implementation<T>::make(al);
0057   }
0058 
0059   /* clones the implementation of x with no elements */
0060 
0061   static segment make_from_prototype(const segment& x,const allocator_type& al)
0062   {
0063     return {from_prototype{},x,al};
0064   }
0065 
0066   segment(const segment& x):
0067     pimpl{x.impl().copy()}{set_sentinel();}
0068   segment(segment&& x)=default;
0069   segment(const segment& x,const allocator_type& al):
0070     pimpl{x.impl().copy(al)}{set_sentinel();}
0071 
0072   /* TODO: try ptr-level move before impl().move() */
0073   segment(segment&& x,const allocator_type& al):
0074     pimpl{x.impl().move(al)}{set_sentinel();}
0075 
0076   segment& operator=(const segment& x)
0077   {
0078     pimpl=allocator_traits::propagate_on_container_copy_assignment::value?
0079       x.impl().copy():x.impl().copy(impl().get_allocator());
0080     set_sentinel();
0081     return *this;
0082   }
0083   
0084   segment& operator=(segment&& x)
0085   {
0086     pimpl=x.impl().move(
0087       allocator_traits::propagate_on_container_move_assignment::value?
0088       x.impl().get_allocator():impl().get_allocator());
0089     set_sentinel();
0090     return *this;
0091   }
0092 
0093   friend bool operator==(const segment& x,const segment& y)
0094   {
0095     if(typeid(*(x.pimpl))!=typeid(*(y.pimpl)))return false;
0096     else return x.impl().equal(y.impl());
0097   }
0098 
0099   friend bool operator!=(const segment& x,const segment& y){return !(x==y);}
0100 
0101   base_iterator        begin()const noexcept{return impl().begin();}
0102   template<typename U>
0103   base_iterator        begin()const noexcept{return impl<U>().nv_begin();}
0104   base_iterator        end()const noexcept{return impl().end();}
0105   template<typename U>
0106   base_iterator        end()const noexcept{return impl<U>().nv_end();}
0107   base_sentinel        sentinel()const noexcept{return snt;}
0108   bool                 empty()const noexcept{return impl().empty();}
0109   template<typename U>
0110   bool                 empty()const noexcept{return impl<U>().nv_empty();}
0111   std::size_t          size()const noexcept{return impl().size();}
0112   template<typename U>
0113   std::size_t          size()const noexcept{return impl<U>().nv_size();}
0114   std::size_t          max_size()const noexcept{return impl().max_size();}
0115   template<typename U>
0116   std::size_t          max_size()const noexcept
0117                          {return impl<U>().nv_max_size();}
0118   void                 reserve(std::size_t n){filter(impl().reserve(n));}
0119   template<typename U>
0120   void                 reserve(std::size_t n){filter(impl<U>().nv_reserve(n));}
0121   std::size_t          capacity()const noexcept{return impl().capacity();}
0122   template<typename U>
0123   std::size_t          capacity()const noexcept
0124                          {return impl<U>().nv_capacity();}
0125   void                 shrink_to_fit(){filter(impl().shrink_to_fit());}
0126   template<typename U>
0127   void                 shrink_to_fit(){filter(impl<U>().nv_shrink_to_fit());}
0128 
0129   template<typename U,typename Iterator,typename... Args>
0130   base_iterator emplace(Iterator it,Args&&... args)
0131   {
0132     return filter(impl<U>().nv_emplace(it,std::forward<Args>(args)...));
0133   }
0134 
0135   template<typename U,typename... Args>
0136   base_iterator emplace_back(Args&&... args)
0137   {
0138     return filter(impl<U>().nv_emplace_back(std::forward<Args>(args)...));
0139   }
0140 
0141   template<typename T>
0142   base_iterator push_back(const T& x)
0143   {
0144     return filter(impl().push_back(subaddress(x)));
0145   }
0146 
0147   template<
0148     typename T,
0149     typename std::enable_if<
0150       !std::is_lvalue_reference<T>::value&&!std::is_const<T>::value
0151     >::type* =nullptr
0152   >
0153   base_iterator push_back(T&& x)
0154   {
0155     return filter(impl().push_back_move(subaddress(x)));
0156   }
0157 
0158   template<typename U>
0159   base_iterator push_back_terminal(U&& x)
0160   {
0161     return filter(
0162       impl<typename std::decay<U>::type>().nv_push_back(std::forward<U>(x)));
0163   }
0164 
0165   template<typename T>
0166   base_iterator insert(const_base_iterator it,const T& x)
0167   {
0168     return filter(impl().insert(it,subaddress(x)));
0169   }
0170 
0171   template<typename U,typename T>
0172   base_iterator insert(const_iterator<U> it,const T& x)
0173   {
0174     return filter(
0175       impl<U>().nv_insert(it,*static_cast<const U*>(subaddress(x))));
0176   }
0177 
0178   template<typename U,typename T>
0179   base_iterator insert(iterator<U> it,const T& x)
0180   {
0181     return insert(const_iterator<U>{it},x);
0182   }
0183 
0184   template<
0185     typename T,
0186     typename std::enable_if<
0187       !std::is_lvalue_reference<T>::value&&!std::is_const<T>::value
0188     >::type* =nullptr
0189   >
0190   base_iterator insert(const_base_iterator it,T&& x)
0191   {
0192     return filter(impl().insert_move(it,subaddress(x)));
0193   }
0194 
0195   template<
0196     typename U,typename T,
0197     typename std::enable_if<
0198       !std::is_lvalue_reference<T>::value&&!std::is_const<T>::value
0199     >::type* =nullptr
0200   >
0201   base_iterator insert(const_iterator<U> it,T&& x)
0202   {
0203     return filter(
0204       impl<U>().nv_insert(it,std::move(*static_cast<U*>(subaddress(x)))));
0205   }
0206 
0207   template<
0208     typename U,typename T,
0209     typename std::enable_if<
0210       !std::is_lvalue_reference<T>::value&&!std::is_const<T>::value
0211     >::type* =nullptr
0212   >
0213   base_iterator insert(iterator<U> it,T&& x)
0214   {
0215     return insert(const_iterator<U>{it},std::move(x));
0216   }
0217 
0218   template<typename InputIterator>
0219   base_iterator insert(InputIterator first,InputIterator last)
0220   {
0221     return filter(
0222       impl<typename std::iterator_traits<InputIterator>::value_type>().
0223         nv_insert(first,last));
0224   }
0225 
0226   template<typename InputIterator>
0227   base_iterator insert(
0228     const_base_iterator it,InputIterator first,InputIterator last)
0229   {
0230     return insert(
0231       const_iterator<
0232         typename std::iterator_traits<InputIterator>::value_type>(it),
0233       first,last);
0234   }
0235 
0236   template<typename U,typename InputIterator>
0237   base_iterator insert(
0238     const_iterator<U> it,InputIterator first,InputIterator last)
0239   {
0240     return filter(impl<U>().nv_insert(it,first,last));
0241   }
0242 
0243   base_iterator erase(const_base_iterator it)
0244   {
0245     return filter(impl().erase(it));
0246   }
0247 
0248   template<typename U>
0249   base_iterator erase(const_iterator<U> it)
0250   {
0251     return filter(impl<U>().nv_erase(it));
0252   }
0253 
0254   base_iterator erase(const_base_iterator f,const_base_iterator l)
0255   {
0256     return filter(impl().erase(f,l));
0257   }
0258 
0259   template<typename U>
0260   base_iterator erase(const_iterator<U> f,const_iterator<U> l)
0261   {
0262     return filter(impl<U>().nv_erase(f,l));
0263   }
0264 
0265   template<typename Iterator>
0266   base_iterator erase_till_end(Iterator f)
0267   {
0268     return filter(impl().erase_till_end(f));
0269   }
0270 
0271   template<typename Iterator>
0272   base_iterator erase_from_begin(Iterator l)
0273   {
0274     return filter(impl().erase_from_begin(l));
0275   }
0276   
0277   void                 clear()noexcept{filter(impl().clear());}
0278   template<typename U>
0279   void                 clear()noexcept{filter(impl<U>().nv_clear());}
0280 
0281 private:
0282   using allocator_traits=std::allocator_traits<Allocator>;
0283   using segment_backend=typename Model::template segment_backend<Allocator>;
0284   template<typename Concrete>
0285   using segment_backend_implementation=typename Model::
0286     template segment_backend_implementation<Concrete,Allocator>;
0287   using segment_backend_unique_ptr=
0288     typename segment_backend::segment_backend_unique_ptr;
0289   using range=typename segment_backend::range;
0290 
0291   struct from_prototype{};
0292 
0293   segment(segment_backend_unique_ptr&& pimpl):
0294     pimpl{std::move(pimpl)}{set_sentinel();}
0295   segment(from_prototype,const segment& x,const allocator_type& al):
0296     pimpl{x.impl().empty_copy(al)}{set_sentinel();}
0297 
0298   segment_backend&       impl()noexcept{return *pimpl;}
0299   const segment_backend& impl()const noexcept{return *pimpl;}
0300 
0301   template<typename Concrete>
0302   segment_backend_implementation<Concrete>& impl()noexcept
0303   {
0304     return static_cast<segment_backend_implementation<Concrete>&>(impl());
0305   }
0306 
0307   template<typename Concrete>
0308   const segment_backend_implementation<Concrete>& impl()const noexcept
0309   {
0310     return
0311       static_cast<const segment_backend_implementation<Concrete>&>(impl());
0312   }
0313 
0314   template<typename T>
0315   static void*         subaddress(T& x){return Model::subaddress(x);}
0316   template<typename T>
0317   static const void*   subaddress(const T& x){return Model::subaddress(x);}
0318 
0319   void          set_sentinel(){filter(impl().end());}
0320   void          filter(base_sentinel x){snt=x;}
0321   base_iterator filter(const range& x){snt=x.second;return x.first;}
0322 
0323   segment_backend_unique_ptr pimpl;
0324   base_sentinel              snt;
0325 };
0326 
0327 } /* namespace poly_collection::detail */
0328 
0329 } /* namespace poly_collection */
0330 
0331 } /* namespace boost */
0332 
0333 #endif