split_segment.hpp 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510
  1. /* Copyright 2016-2020 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_SPLIT_SEGMENT_HPP
  9. #define BOOST_POLY_COLLECTION_DETAIL_SPLIT_SEGMENT_HPP
  10. #if defined(_MSC_VER)
  11. #pragma once
  12. #endif
  13. #include <boost/poly_collection/detail/segment_backend.hpp>
  14. #include <boost/poly_collection/detail/value_holder.hpp>
  15. #include <iterator>
  16. #include <memory>
  17. #include <new>
  18. #include <utility>
  19. #include <vector>
  20. namespace boost{
  21. namespace poly_collection{
  22. namespace detail{
  23. /* segment_backend implementation that maintains two internal vectors, one for
  24. * value_type's (the index) and another for the concrete elements those refer
  25. * to (the store).
  26. *
  27. * Requires:
  28. * - [const_]base_iterator is constructible from value_type*.
  29. * - value_type is copy constructible.
  30. * - Model::make_value_type(x) returns a value_type created from a reference
  31. * to the concrete type.
  32. *
  33. * Conversion from base_iterator to local_iterator<Concrete> requires accesing
  34. * value_type internal info, so the end() base_iterator has to be made to point
  35. * to a valid element of index, which implies size(index)=size(store)+1. This
  36. * slightly complicates the memory management.
  37. */
  38. template<typename Model,typename Concrete,typename Allocator>
  39. class split_segment:public segment_backend<Model,Allocator>
  40. {
  41. using value_type=typename Model::value_type;
  42. using store_value_type=value_holder<Concrete>;
  43. using store=std::vector<
  44. store_value_type,
  45. typename std::allocator_traits<Allocator>::
  46. template rebind_alloc<store_value_type>
  47. >;
  48. using store_iterator=typename store::iterator;
  49. using const_store_iterator=typename store::const_iterator;
  50. using index=std::vector<
  51. value_type,
  52. typename std::allocator_traits<Allocator>::
  53. template rebind_alloc<value_type>
  54. >;
  55. using const_index_iterator=typename index::const_iterator;
  56. using segment_backend=detail::segment_backend<Model,Allocator>;
  57. using typename segment_backend::segment_backend_unique_ptr;
  58. using typename segment_backend::value_pointer;
  59. using typename segment_backend::const_value_pointer;
  60. using typename segment_backend::base_iterator;
  61. using typename segment_backend::const_base_iterator;
  62. using const_iterator=
  63. typename segment_backend::template const_iterator<Concrete>;
  64. using typename segment_backend::base_sentinel;
  65. using typename segment_backend::range;
  66. using segment_allocator_type=typename std::allocator_traits<Allocator>::
  67. template rebind_alloc<split_segment>;
  68. public:
  69. virtual ~split_segment()=default;
  70. static segment_backend_unique_ptr make(const segment_allocator_type& al)
  71. {
  72. return new_(al,al);
  73. }
  74. virtual segment_backend_unique_ptr copy()const
  75. {
  76. return new_(s.get_allocator(),store{s});
  77. }
  78. virtual segment_backend_unique_ptr copy(const Allocator& al)const
  79. {
  80. return new_(al,store{s,al});
  81. }
  82. virtual segment_backend_unique_ptr empty_copy(const Allocator& al)const
  83. {
  84. return new_(al,al);
  85. }
  86. virtual segment_backend_unique_ptr move(const Allocator& al)
  87. {
  88. return new_(al,store{std::move(s),al});
  89. }
  90. virtual bool equal(const segment_backend& x)const
  91. {
  92. return s==static_cast<const split_segment&>(x).s;
  93. }
  94. virtual Allocator get_allocator()const noexcept
  95. {return s.get_allocator();}
  96. virtual base_iterator begin()const noexcept{return nv_begin();}
  97. base_iterator nv_begin()const noexcept
  98. {return base_iterator{value_ptr(i.data())};}
  99. virtual base_iterator end()const noexcept{return nv_end();}
  100. base_iterator nv_end()const noexcept
  101. {return base_iterator{value_ptr(i.data()+s.size())};}
  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()-1;}
  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. {
  113. bool rebuild=n>s.capacity();
  114. i.reserve(n+1);
  115. s.reserve(n);
  116. if(rebuild)rebuild_index();
  117. return sentinel();
  118. };
  119. virtual base_sentinel shrink_to_fit(){return nv_shrink_to_fit();}
  120. base_sentinel nv_shrink_to_fit()
  121. {
  122. try{
  123. auto p=s.data();
  124. if(!s.empty())s.shrink_to_fit();
  125. else{
  126. store ss{s.get_allocator()};
  127. ss.reserve(1); /* --> s.data()!=nullptr */
  128. s.swap(ss);
  129. }
  130. if(p!=s.data()){
  131. index ii{{},i.get_allocator()};
  132. ii.reserve(s.capacity()+1);
  133. i.swap(ii);
  134. build_index();
  135. }
  136. }
  137. catch(...){
  138. rebuild_index();
  139. throw;
  140. }
  141. return sentinel();
  142. }
  143. template<typename Iterator,typename... Args>
  144. range nv_emplace(Iterator p,Args&&... args)
  145. {
  146. auto q=prereserve(p);
  147. auto it=s.emplace(
  148. iterator_from(q),
  149. value_holder_emplacing_ctor,std::forward<Args>(args)...);
  150. push_index_entry();
  151. return range_from(it);
  152. }
  153. template<typename... Args>
  154. range nv_emplace_back(Args&&... args)
  155. {
  156. prereserve();
  157. s.emplace_back(value_holder_emplacing_ctor,std::forward<Args>(args)...);
  158. push_index_entry();
  159. return range_from(s.size()-1);
  160. }
  161. virtual range push_back(const_value_pointer x)
  162. {return nv_push_back(const_concrete_ref(x));}
  163. range nv_push_back(const Concrete& x)
  164. {
  165. prereserve();
  166. s.emplace_back(x);
  167. push_index_entry();
  168. return range_from(s.size()-1);
  169. }
  170. virtual range push_back_move(value_pointer x)
  171. {return nv_push_back(std::move(concrete_ref(x)));}
  172. range nv_push_back(Concrete&& x)
  173. {
  174. prereserve();
  175. s.emplace_back(std::move(x));
  176. push_index_entry();
  177. return range_from(s.size()-1);
  178. }
  179. virtual range insert(const_base_iterator p,const_value_pointer x)
  180. {return nv_insert(const_iterator(p),const_concrete_ref(x));}
  181. range nv_insert(const_iterator p,const Concrete& x)
  182. {
  183. p=prereserve(p);
  184. auto it=s.emplace(iterator_from(p),x);
  185. push_index_entry();
  186. return range_from(it);
  187. }
  188. virtual range insert_move(const_base_iterator p,value_pointer x)
  189. {return nv_insert(const_iterator(p),std::move(concrete_ref(x)));}
  190. range nv_insert(const_iterator p,Concrete&& x)
  191. {
  192. p=prereserve(p);
  193. auto it=s.emplace(iterator_from(p),std::move(x));
  194. push_index_entry();
  195. return range_from(it);
  196. }
  197. template<typename InputIterator>
  198. range nv_insert(InputIterator first,InputIterator last)
  199. {
  200. return nv_insert(
  201. const_iterator(concrete_ptr(s.data()+s.size())),first,last);
  202. }
  203. template<typename InputIterator>
  204. range nv_insert(const_iterator p,InputIterator first,InputIterator last)
  205. {
  206. return insert(
  207. p,first,last,
  208. typename std::iterator_traits<InputIterator>::iterator_category{});
  209. }
  210. virtual range erase(const_base_iterator p)
  211. {return nv_erase(const_iterator(p));}
  212. range nv_erase(const_iterator p)
  213. {
  214. pop_index_entry();
  215. return range_from(s.erase(iterator_from(p)));
  216. }
  217. virtual range erase(const_base_iterator first,const_base_iterator last)
  218. {return nv_erase(const_iterator(first),const_iterator(last));}
  219. range nv_erase(const_iterator first,const_iterator last)
  220. {
  221. std::size_t n=s.size();
  222. auto it=s.erase(iterator_from(first),iterator_from(last));
  223. pop_index_entry(n-s.size());
  224. return range_from(it);
  225. }
  226. virtual range erase_till_end(const_base_iterator first)
  227. {
  228. std::size_t n=s.size();
  229. auto it=s.erase(iterator_from(first),s.end());
  230. pop_index_entry(n-s.size());
  231. return range_from(it);
  232. }
  233. virtual range erase_from_begin(const_base_iterator last)
  234. {
  235. std::size_t n=s.size();
  236. auto it=s.erase(s.begin(),iterator_from(last));
  237. pop_index_entry(n-s.size());
  238. return range_from(it);
  239. }
  240. base_sentinel clear()noexcept{return nv_clear();}
  241. base_sentinel nv_clear()noexcept
  242. {
  243. s.clear();
  244. for(std::size_t n=i.size()-1;n--;)i.pop_back();
  245. return sentinel();
  246. }
  247. private:
  248. template<typename... Args>
  249. static segment_backend_unique_ptr new_(
  250. segment_allocator_type al,Args&&... args)
  251. {
  252. auto p=std::allocator_traits<segment_allocator_type>::allocate(al,1);
  253. try{
  254. ::new ((void*)p) split_segment{std::forward<Args>(args)...};
  255. }
  256. catch(...){
  257. std::allocator_traits<segment_allocator_type>::deallocate(al,p,1);
  258. throw;
  259. }
  260. return {p,&delete_};
  261. }
  262. static void delete_(segment_backend* p)
  263. {
  264. auto q=static_cast<split_segment*>(p);
  265. auto al=segment_allocator_type{q->s.get_allocator()};
  266. q->~split_segment();
  267. std::allocator_traits<segment_allocator_type>::deallocate(al,q,1);
  268. }
  269. split_segment(const Allocator& al):
  270. s{typename store::allocator_type{al}},
  271. i{{},typename index::allocator_type{al}}
  272. {
  273. s.reserve(1); /* --> s.data()!=nullptr */
  274. build_index();
  275. }
  276. split_segment(store&& s_):
  277. s{std::move(s_)},i{{},typename index::allocator_type{s.get_allocator()}}
  278. {
  279. s.reserve(1); /* --> s.data()!=nullptr */
  280. build_index();
  281. }
  282. void prereserve()
  283. {
  284. if(s.size()==s.capacity())expand();
  285. }
  286. const_base_iterator prereserve(const_base_iterator p)
  287. {
  288. if(s.size()==s.capacity()){
  289. auto n=p-i.data();
  290. expand();
  291. return const_base_iterator{i.data()+n};
  292. }
  293. else return p;
  294. }
  295. const_iterator prereserve(const_iterator p)
  296. {
  297. if(s.size()==s.capacity()){
  298. auto n=p-const_concrete_ptr(s.data());
  299. expand();
  300. return const_concrete_ptr(s.data())+n;
  301. }
  302. else return p;
  303. }
  304. const_iterator prereserve(const_iterator p,std::size_t m)
  305. {
  306. if(s.size()+m>s.capacity()){
  307. auto n=p-const_concrete_ptr(s.data());
  308. expand(m);
  309. return const_concrete_ptr(s.data())+n;
  310. }
  311. else return p;
  312. }
  313. void expand()
  314. {
  315. std::size_t c=
  316. s.size()<=1||(s.max_size()-1-s.size())/2<s.size()?
  317. s.size()+1:
  318. s.size()+s.size()/2;
  319. i.reserve(c+1);
  320. s.reserve(c);
  321. rebuild_index();
  322. }
  323. void expand(std::size_t m)
  324. {
  325. i.reserve(s.size()+m+1);
  326. s.reserve(s.size()+m);
  327. rebuild_index();
  328. }
  329. void build_index(std::size_t start=0)
  330. {
  331. for(std::size_t n=start,m=s.size();n<=m;++n){
  332. i.push_back(Model::make_value_type(concrete_ref(s.data()[n])));
  333. };
  334. }
  335. void rebuild_index()
  336. {
  337. i.clear();
  338. build_index();
  339. }
  340. void push_index_entry()
  341. {
  342. build_index(s.size());
  343. }
  344. void pop_index_entry(std::size_t n=1)
  345. {
  346. while(n--)i.pop_back();
  347. }
  348. static Concrete& concrete_ref(value_pointer p)noexcept
  349. {
  350. return *static_cast<Concrete*>(p);
  351. }
  352. static Concrete& concrete_ref(store_value_type& r)noexcept
  353. {
  354. return *concrete_ptr(&r);
  355. }
  356. static const Concrete& const_concrete_ref(const_value_pointer p)noexcept
  357. {
  358. return *static_cast<const Concrete*>(p);
  359. }
  360. static Concrete* concrete_ptr(store_value_type* p)noexcept
  361. {
  362. return reinterpret_cast<Concrete*>(
  363. static_cast<value_holder_base<Concrete>*>(p));
  364. }
  365. static const Concrete* const_concrete_ptr(const store_value_type* p)noexcept
  366. {
  367. return concrete_ptr(const_cast<store_value_type*>(p));
  368. }
  369. static value_type* value_ptr(const value_type* p)noexcept
  370. {
  371. return const_cast<value_type*>(p);
  372. }
  373. /* It would have sufficed if iterator_from returned const_store_iterator
  374. * except for the fact that some old versions of libstdc++ claiming to be
  375. * C++11 compliant do not however provide std::vector modifier ops taking
  376. * const_iterator's.
  377. */
  378. store_iterator iterator_from(const_base_iterator p)
  379. {
  380. return s.begin()+(p-i.data());
  381. }
  382. store_iterator iterator_from(const_iterator p)
  383. {
  384. return s.begin()+(p-const_concrete_ptr(s.data()));
  385. }
  386. base_sentinel sentinel()const noexcept
  387. {
  388. return base_iterator{value_ptr(i.data()+s.size())};
  389. }
  390. range range_from(const_store_iterator it)const
  391. {
  392. return {base_iterator{value_ptr(i.data()+(it-s.begin()))},sentinel()};
  393. }
  394. range range_from(std::size_t n)const
  395. {
  396. return {base_iterator{value_ptr(i.data()+n)},sentinel()};
  397. }
  398. template<typename InputIterator>
  399. range insert(
  400. const_iterator p,InputIterator first,InputIterator last,
  401. std::input_iterator_tag)
  402. {
  403. std::size_t n=0;
  404. for(;first!=last;++first,++n,++p){
  405. p=prereserve(p);
  406. s.emplace(iterator_from(p),*first);
  407. push_index_entry();
  408. }
  409. return range_from(iterator_from(p-n));
  410. }
  411. template<typename InputIterator>
  412. range insert(
  413. const_iterator p,InputIterator first,InputIterator last,
  414. std::forward_iterator_tag)
  415. {
  416. auto n=s.size();
  417. auto m=static_cast<std::size_t>(std::distance(first,last));
  418. if(m){
  419. p=prereserve(p,m);
  420. try{
  421. s.insert(iterator_from(p),first,last);
  422. }
  423. catch(...){
  424. build_index(n+1);
  425. throw;
  426. }
  427. build_index(n+1);
  428. }
  429. return range_from(iterator_from(p));
  430. }
  431. store s;
  432. index i;
  433. };
  434. } /* namespace poly_collection::detail */
  435. } /* namespace poly_collection */
  436. } /* namespace boost */
  437. #endif