segment.hpp 9.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334
  1. /* Copyright 2016-2024 Joaquin M Lopez Munoz.
  2. * Distributed under the Boost Software License, Version 1.0.
  3. * (See accompanying file LICENSE_1_0.txt or copy at
  4. * http://www.boost.org/LICENSE_1_0.txt)
  5. *
  6. * See http://www.boost.org/libs/poly_collection for library home page.
  7. */
  8. #ifndef BOOST_POLY_COLLECTION_DETAIL_SEGMENT_HPP
  9. #define BOOST_POLY_COLLECTION_DETAIL_SEGMENT_HPP
  10. #if defined(_MSC_VER)
  11. #pragma once
  12. #endif
  13. #include <iterator>
  14. #include <memory>
  15. #include <type_traits>
  16. #include <utility>
  17. namespace boost{
  18. namespace poly_collection{
  19. namespace detail{
  20. /* segment<Model,Allocator> encapsulates implementations of
  21. * Model::segment_backend virtual interface under a value-semantics type for
  22. * use by poly_collection. The techique is described by Sean Parent at slides
  23. * 157-205 of
  24. * https://github.com/sean-parent/sean-parent.github.com/wiki/
  25. * presentations/2013-09-11-cpp-seasoning/cpp-seasoning.pdf
  26. * with one twist: when the type of the implementation can be known at compile
  27. * time, a downcast is done and non-virtual member functions (named with a nv_
  28. * prefix) are used: this increases the performance of some operations.
  29. */
  30. template<typename Model,typename Allocator>
  31. class segment
  32. {
  33. public:
  34. using value_type=typename Model::value_type;
  35. using allocator_type=Allocator; /* needed for uses-allocator construction */
  36. using base_iterator=typename Model::base_iterator;
  37. using const_base_iterator=typename Model::const_base_iterator;
  38. using base_sentinel=typename Model::base_sentinel;
  39. using const_base_sentinel=typename Model::const_base_sentinel;
  40. template<typename T>
  41. using iterator=typename Model::template iterator<T>;
  42. template<typename T>
  43. using const_iterator=typename Model::template const_iterator<T>;
  44. template<typename T>
  45. static segment make(const allocator_type& al)
  46. {
  47. return segment_backend_implementation<T>::make(al);
  48. }
  49. /* clones the implementation of x with no elements */
  50. static segment make_from_prototype(const segment& x,const allocator_type& al)
  51. {
  52. return {from_prototype{},x,al};
  53. }
  54. segment(const segment& x):
  55. pimpl{x.impl().copy()}{set_sentinel();}
  56. segment(segment&& x)=default;
  57. segment(const segment& x,const allocator_type& al):
  58. pimpl{x.impl().copy(al)}{set_sentinel();}
  59. /* TODO: try ptr-level move before impl().move() */
  60. segment(segment&& x,const allocator_type& al):
  61. pimpl{x.impl().move(al)}{set_sentinel();}
  62. segment& operator=(const segment& x)
  63. {
  64. pimpl=allocator_traits::propagate_on_container_copy_assignment::value?
  65. x.impl().copy():x.impl().copy(impl().get_allocator());
  66. set_sentinel();
  67. return *this;
  68. }
  69. segment& operator=(segment&& x)
  70. {
  71. pimpl=x.impl().move(
  72. allocator_traits::propagate_on_container_move_assignment::value?
  73. x.impl().get_allocator():impl().get_allocator());
  74. set_sentinel();
  75. return *this;
  76. }
  77. friend bool operator==(const segment& x,const segment& y)
  78. {
  79. if(typeid(*(x.pimpl))!=typeid(*(y.pimpl)))return false;
  80. else return x.impl().equal(y.impl());
  81. }
  82. friend bool operator!=(const segment& x,const segment& y){return !(x==y);}
  83. base_iterator begin()const noexcept{return impl().begin();}
  84. template<typename U>
  85. base_iterator begin()const noexcept{return impl<U>().nv_begin();}
  86. base_iterator end()const noexcept{return impl().end();}
  87. template<typename U>
  88. base_iterator end()const noexcept{return impl<U>().nv_end();}
  89. base_sentinel sentinel()const noexcept{return snt;}
  90. bool empty()const noexcept{return impl().empty();}
  91. template<typename U>
  92. bool empty()const noexcept{return impl<U>().nv_empty();}
  93. std::size_t size()const noexcept{return impl().size();}
  94. template<typename U>
  95. std::size_t size()const noexcept{return impl<U>().nv_size();}
  96. std::size_t max_size()const noexcept{return impl().max_size();}
  97. template<typename U>
  98. std::size_t max_size()const noexcept
  99. {return impl<U>().nv_max_size();}
  100. void reserve(std::size_t n){filter(impl().reserve(n));}
  101. template<typename U>
  102. void reserve(std::size_t n){filter(impl<U>().nv_reserve(n));}
  103. std::size_t capacity()const noexcept{return impl().capacity();}
  104. template<typename U>
  105. std::size_t capacity()const noexcept
  106. {return impl<U>().nv_capacity();}
  107. void shrink_to_fit(){filter(impl().shrink_to_fit());}
  108. template<typename U>
  109. void shrink_to_fit(){filter(impl<U>().nv_shrink_to_fit());}
  110. template<typename U,typename Iterator,typename... Args>
  111. base_iterator emplace(Iterator it,Args&&... args)
  112. {
  113. return filter(impl<U>().nv_emplace(it,std::forward<Args>(args)...));
  114. }
  115. template<typename U,typename... Args>
  116. base_iterator emplace_back(Args&&... args)
  117. {
  118. return filter(impl<U>().nv_emplace_back(std::forward<Args>(args)...));
  119. }
  120. template<typename T>
  121. base_iterator push_back(const T& x)
  122. {
  123. return filter(impl().push_back(subaddress(x)));
  124. }
  125. template<
  126. typename T,
  127. typename std::enable_if<
  128. !std::is_lvalue_reference<T>::value&&!std::is_const<T>::value
  129. >::type* =nullptr
  130. >
  131. base_iterator push_back(T&& x)
  132. {
  133. return filter(impl().push_back_move(subaddress(x)));
  134. }
  135. template<typename U>
  136. base_iterator push_back_terminal(U&& x)
  137. {
  138. return filter(
  139. impl<typename std::decay<U>::type>().nv_push_back(std::forward<U>(x)));
  140. }
  141. template<typename T>
  142. base_iterator insert(const_base_iterator it,const T& x)
  143. {
  144. return filter(impl().insert(it,subaddress(x)));
  145. }
  146. template<typename U,typename T>
  147. base_iterator insert(const_iterator<U> it,const T& x)
  148. {
  149. return filter(
  150. impl<U>().nv_insert(it,*static_cast<const U*>(subaddress(x))));
  151. }
  152. template<typename U,typename T>
  153. base_iterator insert(iterator<U> it,const T& x)
  154. {
  155. return insert(const_iterator<U>{it},x);
  156. }
  157. template<
  158. typename T,
  159. typename std::enable_if<
  160. !std::is_lvalue_reference<T>::value&&!std::is_const<T>::value
  161. >::type* =nullptr
  162. >
  163. base_iterator insert(const_base_iterator it,T&& x)
  164. {
  165. return filter(impl().insert_move(it,subaddress(x)));
  166. }
  167. template<
  168. typename U,typename T,
  169. typename std::enable_if<
  170. !std::is_lvalue_reference<T>::value&&!std::is_const<T>::value
  171. >::type* =nullptr
  172. >
  173. base_iterator insert(const_iterator<U> it,T&& x)
  174. {
  175. return filter(
  176. impl<U>().nv_insert(it,std::move(*static_cast<U*>(subaddress(x)))));
  177. }
  178. template<
  179. typename U,typename T,
  180. typename std::enable_if<
  181. !std::is_lvalue_reference<T>::value&&!std::is_const<T>::value
  182. >::type* =nullptr
  183. >
  184. base_iterator insert(iterator<U> it,T&& x)
  185. {
  186. return insert(const_iterator<U>{it},std::move(x));
  187. }
  188. template<typename InputIterator>
  189. base_iterator insert(InputIterator first,InputIterator last)
  190. {
  191. return filter(
  192. impl<typename std::iterator_traits<InputIterator>::value_type>().
  193. nv_insert(first,last));
  194. }
  195. template<typename InputIterator>
  196. base_iterator insert(
  197. const_base_iterator it,InputIterator first,InputIterator last)
  198. {
  199. return insert(
  200. const_iterator<
  201. typename std::iterator_traits<InputIterator>::value_type>(it),
  202. first,last);
  203. }
  204. template<typename U,typename InputIterator>
  205. base_iterator insert(
  206. const_iterator<U> it,InputIterator first,InputIterator last)
  207. {
  208. return filter(impl<U>().nv_insert(it,first,last));
  209. }
  210. base_iterator erase(const_base_iterator it)
  211. {
  212. return filter(impl().erase(it));
  213. }
  214. template<typename U>
  215. base_iterator erase(const_iterator<U> it)
  216. {
  217. return filter(impl<U>().nv_erase(it));
  218. }
  219. base_iterator erase(const_base_iterator f,const_base_iterator l)
  220. {
  221. return filter(impl().erase(f,l));
  222. }
  223. template<typename U>
  224. base_iterator erase(const_iterator<U> f,const_iterator<U> l)
  225. {
  226. return filter(impl<U>().nv_erase(f,l));
  227. }
  228. template<typename Iterator>
  229. base_iterator erase_till_end(Iterator f)
  230. {
  231. return filter(impl().erase_till_end(f));
  232. }
  233. template<typename Iterator>
  234. base_iterator erase_from_begin(Iterator l)
  235. {
  236. return filter(impl().erase_from_begin(l));
  237. }
  238. void clear()noexcept{filter(impl().clear());}
  239. template<typename U>
  240. void clear()noexcept{filter(impl<U>().nv_clear());}
  241. private:
  242. using allocator_traits=std::allocator_traits<Allocator>;
  243. using segment_backend=typename Model::template segment_backend<Allocator>;
  244. template<typename Concrete>
  245. using segment_backend_implementation=typename Model::
  246. template segment_backend_implementation<Concrete,Allocator>;
  247. using segment_backend_unique_ptr=
  248. typename segment_backend::segment_backend_unique_ptr;
  249. using range=typename segment_backend::range;
  250. struct from_prototype{};
  251. segment(segment_backend_unique_ptr&& pimpl):
  252. pimpl{std::move(pimpl)}{set_sentinel();}
  253. segment(from_prototype,const segment& x,const allocator_type& al):
  254. pimpl{x.impl().empty_copy(al)}{set_sentinel();}
  255. segment_backend& impl()noexcept{return *pimpl;}
  256. const segment_backend& impl()const noexcept{return *pimpl;}
  257. template<typename Concrete>
  258. segment_backend_implementation<Concrete>& impl()noexcept
  259. {
  260. return static_cast<segment_backend_implementation<Concrete>&>(impl());
  261. }
  262. template<typename Concrete>
  263. const segment_backend_implementation<Concrete>& impl()const noexcept
  264. {
  265. return
  266. static_cast<const segment_backend_implementation<Concrete>&>(impl());
  267. }
  268. template<typename T>
  269. static void* subaddress(T& x){return Model::subaddress(x);}
  270. template<typename T>
  271. static const void* subaddress(const T& x){return Model::subaddress(x);}
  272. void set_sentinel(){filter(impl().end());}
  273. void filter(base_sentinel x){snt=x;}
  274. base_iterator filter(const range& x){snt=x.second;return x.first;}
  275. segment_backend_unique_ptr pimpl;
  276. base_sentinel snt;
  277. };
  278. } /* namespace poly_collection::detail */
  279. } /* namespace poly_collection */
  280. } /* namespace boost */
  281. #endif