packed_segment.hpp 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349
  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_PACKED_SEGMENT_HPP
  9. #define BOOST_POLY_COLLECTION_DETAIL_PACKED_SEGMENT_HPP
  10. #if defined(_MSC_VER)
  11. #pragma once
  12. #endif
  13. #include <boost/detail/workaround.hpp>
  14. #include <boost/poly_collection/detail/segment_backend.hpp>
  15. #include <boost/poly_collection/detail/value_holder.hpp>
  16. #include <memory>
  17. #include <new>
  18. #include <vector>
  19. #include <utility>
  20. namespace boost{
  21. namespace poly_collection{
  22. namespace detail{
  23. /* segment_backend implementation where value_type& and Concrete& actually refer
  24. * to the same stored entity.
  25. *
  26. * Requires:
  27. * - [const_]base_iterator is a stride iterator constructible from
  28. * {value_type*,sizeof(store_value_type)}.
  29. * - Model provides a function value_ptr for
  30. * const Concrete* -> const value_type* conversion.
  31. * - If Model provides a final_type<Concrete> template alias, it is this
  32. * type that is stored in the segment rather than Concrete. In this case,
  33. * final_type<Concrete> must be constructible from Concrete and
  34. * Concrete* must be reinterpret_castable to final_type<Concrete>* and vice
  35. * versa.
  36. */
  37. template<typename Model,typename Concrete,typename Allocator>
  38. class packed_segment:public segment_backend<Model,Allocator>
  39. {
  40. template<typename M>
  41. static typename M::template final_type<Concrete> final_type_helper(M);
  42. static Concrete final_type_helper(...);
  43. using value_type=typename Model::value_type;
  44. using final_type=decltype(final_type_helper(std::declval<Model>()));
  45. using store_value_type=value_holder<final_type,Concrete>;
  46. using store=std::vector<
  47. store_value_type,
  48. typename std::allocator_traits<Allocator>::
  49. template rebind_alloc<store_value_type>
  50. >;
  51. using store_iterator=typename store::iterator;
  52. using const_store_iterator=typename store::const_iterator;
  53. using segment_backend=detail::segment_backend<Model,Allocator>;
  54. using typename segment_backend::segment_backend_unique_ptr;
  55. using typename segment_backend::value_pointer;
  56. using typename segment_backend::const_value_pointer;
  57. using typename segment_backend::base_iterator;
  58. using typename segment_backend::const_base_iterator;
  59. using const_iterator=
  60. typename segment_backend::template const_iterator<Concrete>;
  61. using typename segment_backend::base_sentinel;
  62. using typename segment_backend::range;
  63. using segment_allocator_type=typename std::allocator_traits<Allocator>::
  64. template rebind_alloc<packed_segment>;
  65. public:
  66. virtual ~packed_segment()=default;
  67. static segment_backend_unique_ptr make(const segment_allocator_type& al)
  68. {
  69. return new_(al,al);
  70. }
  71. virtual segment_backend_unique_ptr copy()const
  72. {
  73. return new_(s.get_allocator(),store{s});
  74. }
  75. virtual segment_backend_unique_ptr copy(const Allocator& al)const
  76. {
  77. return new_(al,store{s,al});
  78. }
  79. virtual segment_backend_unique_ptr empty_copy(const Allocator& al)const
  80. {
  81. return new_(al,al);
  82. }
  83. virtual segment_backend_unique_ptr move(const Allocator& al)
  84. {
  85. return new_(al,store{std::move(s),al});
  86. }
  87. virtual bool equal(const segment_backend& x)const
  88. {
  89. return s==static_cast<const packed_segment&>(x).s;
  90. }
  91. virtual Allocator get_allocator()const noexcept{return s.get_allocator();}
  92. virtual base_iterator begin()const noexcept{return nv_begin();}
  93. base_iterator nv_begin()const noexcept
  94. {
  95. return {value_ptr(s.data()),sizeof(store_value_type)};
  96. }
  97. virtual base_iterator end()const noexcept{return nv_end();}
  98. base_iterator nv_end()const noexcept
  99. {
  100. return {value_ptr(s.data()+s.size()),sizeof(store_value_type)};
  101. }
  102. virtual bool empty()const noexcept{return nv_empty();}
  103. bool nv_empty()const noexcept{return s.empty();}
  104. virtual std::size_t size()const noexcept{return nv_size();}
  105. std::size_t nv_size()const noexcept{return s.size();}
  106. virtual std::size_t max_size()const noexcept{return nv_max_size();}
  107. std::size_t nv_max_size()const noexcept{return s.max_size();}
  108. virtual std::size_t capacity()const noexcept{return nv_capacity();}
  109. std::size_t nv_capacity()const noexcept{return s.capacity();}
  110. virtual base_sentinel reserve(std::size_t n){return nv_reserve(n);}
  111. base_sentinel nv_reserve(std::size_t n)
  112. {s.reserve(n);return sentinel();}
  113. virtual base_sentinel shrink_to_fit(){return nv_shrink_to_fit();}
  114. base_sentinel nv_shrink_to_fit()
  115. {s.shrink_to_fit();return sentinel();}
  116. template<typename Iterator,typename... Args>
  117. range nv_emplace(Iterator p,Args&&... args)
  118. {
  119. return range_from(
  120. s.emplace(
  121. iterator_from(p),
  122. value_holder_emplacing_ctor,std::forward<Args>(args)...));
  123. }
  124. template<typename... Args>
  125. range nv_emplace_back(Args&&... args)
  126. {
  127. s.emplace_back(value_holder_emplacing_ctor,std::forward<Args>(args)...);
  128. return range_from(s.size()-1);
  129. }
  130. virtual range push_back(const_value_pointer x)
  131. {return nv_push_back(const_concrete_ref(x));}
  132. range nv_push_back(const Concrete& x)
  133. {
  134. s.emplace_back(x);
  135. return range_from(s.size()-1);
  136. }
  137. virtual range push_back_move(value_pointer x)
  138. {return nv_push_back(std::move(concrete_ref(x)));}
  139. range nv_push_back(Concrete&& x)
  140. {
  141. s.emplace_back(std::move(x));
  142. return range_from(s.size()-1);
  143. }
  144. virtual range insert(const_base_iterator p,const_value_pointer x)
  145. {return nv_insert(const_iterator(p),const_concrete_ref(x));}
  146. range nv_insert(const_iterator p,const Concrete& x)
  147. {
  148. return range_from(s.emplace(iterator_from(p),x));
  149. }
  150. virtual range insert_move(const_base_iterator p,value_pointer x)
  151. {return nv_insert(const_iterator(p),std::move(concrete_ref(x)));}
  152. range nv_insert(const_iterator p,Concrete&& x)
  153. {
  154. return range_from(s.emplace(iterator_from(p),std::move(x)));
  155. }
  156. template<typename InputIterator>
  157. range nv_insert(InputIterator first,InputIterator last)
  158. {
  159. return nv_insert(
  160. const_iterator(concrete_ptr(s.data()+s.size())),first,last);
  161. }
  162. template<typename InputIterator>
  163. range nv_insert(const_iterator p,InputIterator first,InputIterator last)
  164. {
  165. #if BOOST_WORKAROUND(BOOST_LIBSTDCXX_VERSION,<40900)
  166. /* std::vector::insert(pos,first,last) returns void rather than iterator */
  167. auto n=const_store_value_type_ptr(p)-s.data();
  168. s.insert(s.begin()+n,first,last);
  169. return range_from(static_cast<std::size_t>(n));
  170. #else
  171. return range_from(s.insert(iterator_from(p),first,last));
  172. #endif
  173. }
  174. virtual range erase(const_base_iterator p)
  175. {return nv_erase(const_iterator(p));}
  176. range nv_erase(const_iterator p)
  177. {
  178. return range_from(s.erase(iterator_from(p)));
  179. }
  180. virtual range erase(const_base_iterator first,const_base_iterator last)
  181. {return nv_erase(const_iterator(first),const_iterator(last));}
  182. range nv_erase(const_iterator first,const_iterator last)
  183. {
  184. return range_from(s.erase(iterator_from(first),iterator_from(last)));
  185. }
  186. virtual range erase_till_end(const_base_iterator first)
  187. {
  188. return range_from(s.erase(iterator_from(first),s.end()));
  189. }
  190. virtual range erase_from_begin(const_base_iterator last)
  191. {
  192. return range_from(s.erase(s.begin(),iterator_from(last)));
  193. }
  194. virtual base_sentinel clear()noexcept{return nv_clear();}
  195. base_sentinel nv_clear()noexcept{s.clear();return sentinel();}
  196. private:
  197. template<typename... Args>
  198. static segment_backend_unique_ptr new_(
  199. segment_allocator_type al,Args&&... args)
  200. {
  201. auto p=std::allocator_traits<segment_allocator_type>::allocate(al,1);
  202. try{
  203. ::new ((void*)p) packed_segment{std::forward<Args>(args)...};
  204. }
  205. catch(...){
  206. std::allocator_traits<segment_allocator_type>::deallocate(al,p,1);
  207. throw;
  208. }
  209. return {p,&delete_};
  210. }
  211. static void delete_(segment_backend* p)
  212. {
  213. auto q=static_cast<packed_segment*>(p);
  214. auto al=segment_allocator_type{q->s.get_allocator()};
  215. q->~packed_segment();
  216. std::allocator_traits<segment_allocator_type>::deallocate(al,q,1);
  217. }
  218. packed_segment(const Allocator& al):s{typename store::allocator_type{al}}{}
  219. packed_segment(store&& s):s{std::move(s)}{}
  220. static Concrete& concrete_ref(value_pointer p)noexcept
  221. {
  222. return *static_cast<Concrete*>(p);
  223. }
  224. static const Concrete& const_concrete_ref(const_value_pointer p)noexcept
  225. {
  226. return *static_cast<const Concrete*>(p);
  227. }
  228. static Concrete* concrete_ptr(store_value_type* p)noexcept
  229. {
  230. return reinterpret_cast<Concrete*>(
  231. static_cast<value_holder_base<final_type>*>(p));
  232. }
  233. static const Concrete* const_concrete_ptr(const store_value_type* p)noexcept
  234. {
  235. return concrete_ptr(const_cast<store_value_type*>(p));
  236. }
  237. static value_type* value_ptr(const store_value_type* p)noexcept
  238. {
  239. return const_cast<value_type*>(Model::value_ptr(const_concrete_ptr(p)));
  240. }
  241. static const store_value_type* const_store_value_type_ptr(
  242. const Concrete* p)noexcept
  243. {
  244. return static_cast<const store_value_type*>(
  245. reinterpret_cast<const value_holder_base<final_type>*>(p));
  246. }
  247. /* It would have sufficed if iterator_from returned const_store_iterator
  248. * except for the fact that some old versions of libstdc++ claiming to be
  249. * C++11 compliant do not however provide std::vector modifier ops taking
  250. * const_iterator's.
  251. */
  252. store_iterator iterator_from(const_base_iterator p)
  253. {
  254. return iterator_from(static_cast<const_iterator>(p));
  255. }
  256. store_iterator iterator_from(const_iterator p)
  257. {
  258. return s.begin()+(const_store_value_type_ptr(p)-s.data());
  259. }
  260. base_sentinel sentinel()const noexcept
  261. {
  262. return base_iterator{
  263. value_ptr(s.data()+s.size()),
  264. sizeof(store_value_type)
  265. };
  266. }
  267. range range_from(const_store_iterator it)const
  268. {
  269. return {
  270. {value_ptr(s.data()+(it-s.begin())),sizeof(store_value_type)},
  271. sentinel()
  272. };
  273. }
  274. range range_from(std::size_t n)const
  275. {
  276. return {
  277. {value_ptr(s.data()+n),sizeof(store_value_type)},
  278. sentinel()
  279. };
  280. }
  281. store s;
  282. };
  283. } /* namespace poly_collection::detail */
  284. } /* namespace poly_collection */
  285. } /* namespace boost */
  286. #endif