split_segment.hpp 13 KB

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