poly_collection.hpp 33 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174
  1. /* Copyright 2016-2018 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_POLY_COLLECTION_HPP
  9. #define BOOST_POLY_COLLECTION_DETAIL_POLY_COLLECTION_HPP
  10. #if defined(_MSC_VER)
  11. #pragma once
  12. #endif
  13. #include <algorithm>
  14. #include <boost/assert.hpp>
  15. #include <boost/iterator/iterator_adaptor.hpp>
  16. #include <boost/poly_collection/detail/allocator_adaptor.hpp>
  17. #include <boost/poly_collection/detail/iterator_impl.hpp>
  18. #include <boost/poly_collection/detail/is_acceptable.hpp>
  19. #include <boost/poly_collection/detail/is_constructible.hpp>
  20. #include <boost/poly_collection/detail/is_final.hpp>
  21. #include <boost/poly_collection/detail/segment.hpp>
  22. #include <boost/poly_collection/detail/type_info_map.hpp>
  23. #include <boost/poly_collection/exception.hpp>
  24. #include <iterator>
  25. #include <type_traits>
  26. #include <typeinfo>
  27. #include <utility>
  28. namespace boost{
  29. namespace poly_collection{
  30. namespace common_impl{
  31. /* common implementation for all polymorphic collections */
  32. using namespace detail;
  33. template<typename Model,typename Allocator>
  34. class poly_collection
  35. {
  36. template<typename T>
  37. static const std::type_info& subtypeid(const T& x)
  38. {return Model::subtypeid(x);}
  39. template<typename...>
  40. struct for_all_types{using type=void*;};
  41. template<typename... T>
  42. using for_all=typename for_all_types<T...>::type;
  43. template<typename T>
  44. struct is_implementation: /* using makes VS2015 choke, hence we derive */
  45. Model::template is_implementation<typename std::decay<T>::type>{};
  46. template<typename T>
  47. using enable_if_implementation=
  48. typename std::enable_if<is_implementation<T>::value>::type*;
  49. template<typename T>
  50. using enable_if_not_implementation=
  51. typename std::enable_if<!is_implementation<T>::value>::type*;
  52. template<typename T>
  53. using is_acceptable=
  54. detail::is_acceptable<typename std::decay<T>::type,Model>;
  55. template<typename T>
  56. using enable_if_acceptable=
  57. typename std::enable_if<is_acceptable<T>::value>::type*;
  58. template<typename T>
  59. using enable_if_not_acceptable=
  60. typename std::enable_if<!is_acceptable<T>::value>::type*;
  61. template<typename InputIterator>
  62. using enable_if_derefs_to_implementation=enable_if_implementation<
  63. typename std::iterator_traits<InputIterator>::value_type
  64. >;
  65. template<typename T>
  66. using is_terminal=
  67. typename Model::template is_terminal<typename std::decay<T>::type>;
  68. template<typename T>
  69. using enable_if_terminal=
  70. typename std::enable_if<is_terminal<T>::value>::type*;
  71. template<typename T>
  72. using enable_if_not_terminal=
  73. typename std::enable_if<!is_terminal<T>::value>::type*;
  74. template<typename InputIterator>
  75. using derefs_to_terminal=is_terminal<
  76. typename std::iterator_traits<InputIterator>::value_type
  77. >;
  78. template<typename InputIterator>
  79. using enable_if_derefs_to_terminal=
  80. typename std::enable_if<derefs_to_terminal<InputIterator>::value>::type*;
  81. template<typename InputIterator>
  82. using enable_if_derefs_to_not_terminal=
  83. typename std::enable_if<!derefs_to_terminal<InputIterator>::value>::type*;
  84. template<typename T,typename U>
  85. using enable_if_not_same=typename std::enable_if<
  86. !std::is_same<
  87. typename std::decay<T>::type,typename std::decay<U>::type
  88. >::value
  89. >::type*;
  90. template<typename T,typename U>
  91. using enable_if_constructible=
  92. typename std::enable_if<is_constructible<T,U>::value>::type*;
  93. template<typename T,typename U>
  94. using enable_if_not_constructible=
  95. typename std::enable_if<!is_constructible<T,U>::value>::type*;
  96. using segment_allocator_type=allocator_adaptor<Allocator>;
  97. using segment_type=detail::segment<Model,segment_allocator_type>;
  98. using segment_base_iterator=typename segment_type::base_iterator;
  99. using const_segment_base_iterator=
  100. typename segment_type::const_base_iterator;
  101. using segment_base_sentinel=typename segment_type::base_sentinel;
  102. using const_segment_base_sentinel=
  103. typename segment_type::const_base_sentinel;
  104. template<typename T>
  105. using segment_iterator=typename segment_type::template iterator<T>;
  106. template<typename T>
  107. using const_segment_iterator=
  108. typename segment_type::template const_iterator<T>;
  109. using segment_map=type_info_map<
  110. segment_type,
  111. typename std::allocator_traits<segment_allocator_type>::template
  112. rebind_alloc<segment_type>
  113. >;
  114. using segment_map_allocator_type=typename segment_map::allocator_type;
  115. using segment_map_iterator=typename segment_map::iterator;
  116. using const_segment_map_iterator=typename segment_map::const_iterator;
  117. public:
  118. /* types */
  119. using value_type=typename segment_type::value_type;
  120. using allocator_type=Allocator;
  121. using size_type=std::size_t;
  122. using difference_type=std::ptrdiff_t;
  123. using reference=value_type&;
  124. using const_reference=const value_type&;
  125. using pointer=typename std::allocator_traits<Allocator>::pointer;
  126. using const_pointer=typename std::allocator_traits<Allocator>::const_pointer;
  127. private:
  128. template<typename,bool>
  129. friend class detail::iterator_impl;
  130. template<typename,typename>
  131. friend class detail::local_iterator_impl;
  132. template<bool Const>
  133. using iterator_impl=detail::iterator_impl<poly_collection,Const>;
  134. template<typename BaseIterator>
  135. using local_iterator_impl=
  136. detail::local_iterator_impl<poly_collection,BaseIterator>;
  137. public:
  138. using iterator=iterator_impl<false>;
  139. using const_iterator=iterator_impl<true>;
  140. using local_base_iterator=local_iterator_impl<segment_base_iterator>;
  141. using const_local_base_iterator=
  142. local_iterator_impl<const_segment_base_iterator>;
  143. template<typename T>
  144. using local_iterator=local_iterator_impl<segment_iterator<T>>;
  145. template<typename T>
  146. using const_local_iterator=local_iterator_impl<const_segment_iterator<T>>;
  147. class const_base_segment_info
  148. {
  149. public:
  150. const_base_segment_info(const const_base_segment_info&)=default;
  151. const_base_segment_info& operator=(const const_base_segment_info&)=default;
  152. const_local_base_iterator begin()const noexcept
  153. {return {it,it->second.begin()};}
  154. const_local_base_iterator end()const noexcept
  155. {return {it,it->second.end()};}
  156. const_local_base_iterator cbegin()const noexcept{return begin();}
  157. const_local_base_iterator cend()const noexcept{return end();}
  158. template<typename T>
  159. const_local_iterator<T> begin()const noexcept
  160. {return const_local_iterator<T>{begin()};}
  161. template<typename T>
  162. const_local_iterator<T> end()const noexcept
  163. {return const_local_iterator<T>{end()};}
  164. template<typename T>
  165. const_local_iterator<T> cbegin()const noexcept{return begin<T>();}
  166. template<typename T>
  167. const_local_iterator<T> cend()const noexcept{return end<T>();}
  168. const std::type_info& type_info()const{return *it->first;}
  169. protected:
  170. friend class poly_collection;
  171. const_base_segment_info(const_segment_map_iterator it)noexcept:it{it}{}
  172. const_segment_map_iterator it;
  173. };
  174. class base_segment_info:public const_base_segment_info
  175. {
  176. public:
  177. base_segment_info(const base_segment_info&)=default;
  178. base_segment_info& operator=(const base_segment_info&)=default;
  179. using const_base_segment_info::begin;
  180. using const_base_segment_info::end;
  181. local_base_iterator begin()noexcept
  182. {return {this->it,this->it->second.begin()};}
  183. local_base_iterator end()noexcept
  184. {return {this->it,this->it->second.end()};}
  185. template<typename T>
  186. local_iterator<T> begin()noexcept{return local_iterator<T>{begin()};}
  187. template<typename T>
  188. local_iterator<T> end()noexcept{return local_iterator<T>{end()};}
  189. private:
  190. friend class poly_collection;
  191. using const_base_segment_info::const_base_segment_info;
  192. };
  193. template<typename T>
  194. class const_segment_info
  195. {
  196. public:
  197. const_segment_info(const const_segment_info&)=default;
  198. const_segment_info& operator=(const const_segment_info&)=default;
  199. const_local_iterator<T> begin()const noexcept
  200. {return {it,it->second.begin()};}
  201. const_local_iterator<T> end()const noexcept
  202. {return {it,it->second.end()};}
  203. const_local_iterator<T> cbegin()const noexcept{return begin();}
  204. const_local_iterator<T> cend()const noexcept{return end();}
  205. protected:
  206. friend class poly_collection;
  207. const_segment_info(const_segment_map_iterator it)noexcept:it{it}{}
  208. const_segment_map_iterator it;
  209. };
  210. template<typename T>
  211. class segment_info:public const_segment_info<T>
  212. {
  213. public:
  214. segment_info(const segment_info&)=default;
  215. segment_info& operator=(const segment_info&)=default;
  216. using const_segment_info<T>::begin;
  217. using const_segment_info<T>::end;
  218. local_iterator<T> begin()noexcept
  219. {return {this->it,this->it->second.begin()};}
  220. local_iterator<T> end()noexcept
  221. {return {this->it,this->it->second.end()};}
  222. private:
  223. friend class poly_collection;
  224. using const_segment_info<T>::const_segment_info;
  225. };
  226. private:
  227. template<typename SegmentInfo>
  228. class segment_info_iterator_impl:
  229. public boost::iterator_adaptor<
  230. segment_info_iterator_impl<SegmentInfo>,
  231. const_segment_map_iterator,
  232. SegmentInfo,
  233. std::input_iterator_tag,
  234. SegmentInfo
  235. >
  236. {
  237. segment_info_iterator_impl(const_segment_map_iterator it):
  238. segment_info_iterator_impl::iterator_adaptor_{it}{}
  239. public:
  240. segment_info_iterator_impl()=default;
  241. segment_info_iterator_impl(const segment_info_iterator_impl&)=default;
  242. segment_info_iterator_impl& operator=(
  243. const segment_info_iterator_impl&)=default;
  244. template<
  245. typename SegmentInfo2,
  246. typename std::enable_if<
  247. std::is_base_of<SegmentInfo,SegmentInfo2>::value
  248. >::type* =nullptr
  249. >
  250. segment_info_iterator_impl(
  251. const segment_info_iterator_impl<SegmentInfo2>& x):
  252. segment_info_iterator_impl::iterator_adaptor_{x.base()}{}
  253. template<
  254. typename SegmentInfo2,
  255. typename std::enable_if<
  256. std::is_base_of<SegmentInfo,SegmentInfo2>::value
  257. >::type* =nullptr
  258. >
  259. segment_info_iterator_impl& operator=(
  260. const segment_info_iterator_impl<SegmentInfo2>& x)
  261. {
  262. this->base_reference()=x.base();
  263. return *this;
  264. }
  265. private:
  266. template<typename>
  267. friend class segment_info_iterator_impl;
  268. friend class poly_collection;
  269. friend class boost::iterator_core_access;
  270. template<typename>
  271. friend struct detail::iterator_traits;
  272. SegmentInfo dereference()const noexcept{return this->base();}
  273. };
  274. public:
  275. using base_segment_info_iterator=
  276. segment_info_iterator_impl<base_segment_info>;
  277. using const_base_segment_info_iterator=
  278. segment_info_iterator_impl<const_base_segment_info>;
  279. private:
  280. template<typename Iterator>
  281. static Iterator nonconst_hlp(Iterator);
  282. static iterator nonconst_hlp(const_iterator);
  283. static local_base_iterator nonconst_hlp(const_local_base_iterator);
  284. template<typename T>
  285. static local_iterator<T> nonconst_hlp(const_local_iterator<T>);
  286. static base_segment_info_iterator nonconst_hlp(
  287. const_base_segment_info_iterator);
  288. template<typename Iterator>
  289. using nonconst_version=decltype(nonconst_hlp(std::declval<Iterator>()));
  290. public:
  291. class const_segment_traversal_info
  292. {
  293. public:
  294. const_segment_traversal_info(const const_segment_traversal_info&)=default;
  295. const_segment_traversal_info& operator=(
  296. const const_segment_traversal_info&)=default;
  297. const_base_segment_info_iterator begin()const noexcept
  298. {return pmap->cbegin();}
  299. const_base_segment_info_iterator end()const noexcept{return pmap->cend();}
  300. const_base_segment_info_iterator cbegin()const noexcept{return begin();}
  301. const_base_segment_info_iterator cend()const noexcept{return end();}
  302. protected:
  303. friend class poly_collection;
  304. const_segment_traversal_info(const segment_map& map)noexcept:
  305. pmap{const_cast<segment_map*>(&map)}{}
  306. segment_map* pmap;
  307. };
  308. class segment_traversal_info:public const_segment_traversal_info
  309. {
  310. public:
  311. segment_traversal_info(const segment_traversal_info&)=default;
  312. segment_traversal_info& operator=(const segment_traversal_info&)=default;
  313. using const_segment_traversal_info::begin;
  314. using const_segment_traversal_info::end;
  315. base_segment_info_iterator begin()noexcept{return this->pmap->cbegin();}
  316. base_segment_info_iterator end()noexcept{return this->pmap->cend();}
  317. private:
  318. friend class poly_collection;
  319. using const_segment_traversal_info::const_segment_traversal_info;
  320. };
  321. /* construct/destroy/copy */
  322. poly_collection()=default;
  323. poly_collection(const poly_collection&)=default;
  324. poly_collection(poly_collection&&)=default;
  325. explicit poly_collection(const allocator_type& al):
  326. map{segment_map_allocator_type{al}}{}
  327. poly_collection(const poly_collection& x,const allocator_type& al):
  328. map{x.map,segment_map_allocator_type{al}}{}
  329. poly_collection(poly_collection&& x,const allocator_type& al):
  330. map{std::move(x.map),segment_map_allocator_type{al}}{}
  331. template<typename InputIterator>
  332. poly_collection(
  333. InputIterator first,InputIterator last,
  334. const allocator_type& al=allocator_type{}):
  335. map{segment_map_allocator_type{al}}
  336. {
  337. this->insert(first,last);
  338. }
  339. // TODO: what to do with initializer_list?
  340. poly_collection& operator=(const poly_collection&)=default;
  341. poly_collection& operator=(poly_collection&&)=default;
  342. allocator_type get_allocator()const noexcept{return map.get_allocator();}
  343. /* type registration */
  344. template<
  345. typename... T,
  346. for_all<enable_if_acceptable<T>...> =nullptr
  347. >
  348. void register_types()
  349. {
  350. /* http://twitter.com/SeanParent/status/558765089294020609 */
  351. using seq=int[1+sizeof...(T)];
  352. (void)seq{
  353. 0,
  354. (map.insert(
  355. typeid(T),segment_type::template make<T>(get_allocator())),0)...
  356. };
  357. }
  358. bool is_registered(const std::type_info& info)const
  359. {
  360. return map.find(info)!=map.end();
  361. }
  362. template<typename T,enable_if_acceptable<T> =nullptr>
  363. bool is_registered()const
  364. {
  365. return is_registered(typeid(T));
  366. }
  367. /* iterators */
  368. iterator begin()noexcept{return {map.begin(),map.end()};}
  369. iterator end()noexcept{return {map.end(),map.end()};}
  370. const_iterator begin()const noexcept{return {map.begin(),map.end()};}
  371. const_iterator end()const noexcept{return {map.end(),map.end()};}
  372. const_iterator cbegin()const noexcept{return begin();}
  373. const_iterator cend()const noexcept{return end();}
  374. local_base_iterator begin(const std::type_info& info)
  375. {
  376. auto it=get_map_iterator_for(info);
  377. return {it,segment(it).begin()};
  378. }
  379. local_base_iterator end(const std::type_info& info)
  380. {
  381. auto it=get_map_iterator_for(info);
  382. return {it,segment(it).end()};
  383. }
  384. const_local_base_iterator begin(const std::type_info& info)const
  385. {
  386. auto it=get_map_iterator_for(info);
  387. return {it,segment(it).begin()};
  388. }
  389. const_local_base_iterator end(const std::type_info& info)const
  390. {
  391. auto it=get_map_iterator_for(info);
  392. return {it,segment(it).end()};
  393. }
  394. const_local_base_iterator cbegin(const std::type_info& info)const
  395. {return begin(info);}
  396. const_local_base_iterator cend(const std::type_info& info)const
  397. {return end(info);}
  398. template<typename T,enable_if_acceptable<T> =nullptr>
  399. local_iterator<T> begin()
  400. {
  401. auto it=get_map_iterator_for(typeid(T));
  402. return {it,segment(it).template begin<T>()};
  403. }
  404. template<typename T,enable_if_acceptable<T> =nullptr>
  405. local_iterator<T> end()
  406. {
  407. auto it=get_map_iterator_for(typeid(T));
  408. return {it,segment(it).template end<T>()};
  409. }
  410. template<typename T,enable_if_acceptable<T> =nullptr>
  411. const_local_iterator<T> begin()const
  412. {
  413. auto it=get_map_iterator_for(typeid(T));
  414. return {it,segment(it).template begin<T>()};
  415. }
  416. template<typename T,enable_if_acceptable<T> =nullptr>
  417. const_local_iterator<T> end()const
  418. {
  419. auto it=get_map_iterator_for(typeid(T));
  420. return {it,segment(it).template end<T>()};
  421. }
  422. template<typename T,enable_if_acceptable<T> =nullptr>
  423. const_local_iterator<T> cbegin()const{return begin<T>();}
  424. template<typename T,enable_if_acceptable<T> =nullptr>
  425. const_local_iterator<T> cend()const{return end<T>();}
  426. base_segment_info segment(const std::type_info& info)
  427. {
  428. return get_map_iterator_for(info);
  429. }
  430. const_base_segment_info segment(const std::type_info& info)const
  431. {
  432. return get_map_iterator_for(info);
  433. }
  434. template<typename T,enable_if_acceptable<T> =nullptr>
  435. segment_info<T> segment(){return get_map_iterator_for(typeid(T));}
  436. template<typename T,enable_if_acceptable<T> =nullptr>
  437. const_segment_info<T> segment()const{return get_map_iterator_for(typeid(T));}
  438. segment_traversal_info segment_traversal()noexcept{return map;}
  439. const_segment_traversal_info segment_traversal()const noexcept{return map;}
  440. /* capacity */
  441. bool empty()const noexcept
  442. {
  443. for(const auto& x:map)if(!x.second.empty())return false;
  444. return true;
  445. }
  446. bool empty(const std::type_info& info)const
  447. {
  448. return segment(get_map_iterator_for(info)).empty();
  449. }
  450. template<typename T,enable_if_acceptable<T> =nullptr>
  451. bool empty()const
  452. {
  453. return segment(get_map_iterator_for(typeid(T))).template empty<T>();
  454. }
  455. size_type size()const noexcept
  456. {
  457. size_type res=0;
  458. for(const auto& x:map)res+=x.second.size();
  459. return res;
  460. }
  461. size_type size(const std::type_info& info)const
  462. {
  463. return segment(get_map_iterator_for(info)).size();
  464. }
  465. template<typename T,enable_if_acceptable<T> =nullptr>
  466. size_type size()const
  467. {
  468. return segment(get_map_iterator_for(typeid(T))).template size<T>();
  469. }
  470. size_type max_size(const std::type_info& info)const
  471. {
  472. return segment(get_map_iterator_for(info)).max_size();
  473. }
  474. template<typename T,enable_if_acceptable<T> =nullptr>
  475. size_type max_size()const
  476. {
  477. return segment(get_map_iterator_for(typeid(T))).template max_size<T>();
  478. }
  479. size_type capacity(const std::type_info& info)const
  480. {
  481. return segment(get_map_iterator_for(info)).capacity();
  482. }
  483. template<typename T,enable_if_acceptable<T> =nullptr>
  484. size_type capacity()const
  485. {
  486. return segment(get_map_iterator_for(typeid(T))).template capacity<T>();
  487. }
  488. void reserve(size_type n)
  489. {
  490. for(auto& x:map)x.second.reserve(n);
  491. }
  492. void reserve(const std::type_info& info,size_type n)
  493. {
  494. segment(get_map_iterator_for(info)).reserve(n);
  495. }
  496. template<typename T,enable_if_acceptable<T> =nullptr>
  497. void reserve(size_type n)
  498. {
  499. /* note this creates the segment if it didn't previously exist */
  500. segment(get_map_iterator_for<T>()).template reserve<T>(n);
  501. }
  502. void shrink_to_fit()
  503. {
  504. for(auto& x:map)x.second.shrink_to_fit();
  505. }
  506. void shrink_to_fit(const std::type_info& info)
  507. {
  508. segment(get_map_iterator_for(info)).shrink_to_fit();
  509. }
  510. template<typename T,enable_if_acceptable<T> =nullptr>
  511. void shrink_to_fit()
  512. {
  513. segment(get_map_iterator_for(typeid(T))).template shrink_to_fit<T>();
  514. }
  515. /* modifiers */
  516. template<typename T,typename... Args,enable_if_acceptable<T> =nullptr>
  517. iterator emplace(Args&&... args)
  518. {
  519. auto it=get_map_iterator_for<T>();
  520. return {
  521. it,map.end(),
  522. segment(it).template emplace_back<T>(std::forward<Args>(args)...)
  523. };
  524. }
  525. template<typename T,typename... Args,enable_if_acceptable<T> =nullptr>
  526. iterator emplace_hint(const_iterator hint,Args&&... args)
  527. {
  528. auto it=get_map_iterator_for<T>();
  529. return {
  530. it,map.end(),
  531. hint.mapit==it? /* hint in segment */
  532. segment(it).template emplace<T>(
  533. hint.segpos,std::forward<Args>(args)...):
  534. segment(it).template emplace_back<T>(std::forward<Args>(args)...)
  535. };
  536. }
  537. template<typename T,typename... Args,enable_if_acceptable<T> =nullptr>
  538. local_base_iterator
  539. emplace_pos(local_base_iterator pos,Args&&... args)
  540. {
  541. return emplace_pos<T>(
  542. const_local_base_iterator{pos},std::forward<Args>(args)...);
  543. }
  544. template<typename T,typename... Args,enable_if_acceptable<T> =nullptr>
  545. local_base_iterator
  546. emplace_pos(const_local_base_iterator pos,Args&&... args)
  547. {
  548. BOOST_ASSERT(pos.type_info()==typeid(T));
  549. return {
  550. pos.mapit,
  551. pos.segment().template emplace<T>(pos.base(),std::forward<Args>(args)...)
  552. };
  553. }
  554. template<typename T,typename... Args>
  555. local_iterator<T>
  556. emplace_pos(local_iterator<T> pos,Args&&... args)
  557. {
  558. return emplace_pos(
  559. const_local_iterator<T>{pos},std::forward<Args>(args)...);
  560. }
  561. template<typename T,typename... Args>
  562. local_iterator<T>
  563. emplace_pos(const_local_iterator<T> pos,Args&&... args)
  564. {
  565. return {
  566. pos.mapit,
  567. pos.segment().template emplace<T>(pos.base(),std::forward<Args>(args)...)
  568. };
  569. }
  570. template<typename T,enable_if_implementation<T> =nullptr>
  571. iterator insert(T&& x)
  572. {
  573. auto it=get_map_iterator_for(x);
  574. return {it,map.end(),push_back(segment(it),std::forward<T>(x))};
  575. }
  576. template<
  577. typename T,
  578. enable_if_not_same<const_iterator,T> =nullptr,
  579. enable_if_implementation<T> =nullptr
  580. >
  581. iterator insert(const_iterator hint,T&& x)
  582. {
  583. auto it=get_map_iterator_for(x);
  584. return {
  585. it,map.end(),
  586. hint.mapit==it? /* hint in segment */
  587. segment(it).insert(hint.segpos,std::forward<T>(x)):
  588. push_back(segment(it),std::forward<T>(x))
  589. };
  590. }
  591. template<
  592. typename BaseIterator,typename T,
  593. enable_if_not_same<local_iterator_impl<BaseIterator>,T> =nullptr,
  594. enable_if_implementation<T> =nullptr
  595. >
  596. nonconst_version<local_iterator_impl<BaseIterator>>
  597. insert(local_iterator_impl<BaseIterator> pos,T&& x)
  598. {
  599. BOOST_ASSERT(pos.type_info()==subtypeid(x));
  600. return {
  601. pos.mapit,
  602. pos.segment().insert(pos.base(),std::forward<T>(x))
  603. };
  604. }
  605. template<
  606. typename InputIterator,
  607. enable_if_derefs_to_implementation<InputIterator> =nullptr,
  608. enable_if_derefs_to_not_terminal<InputIterator> =nullptr
  609. >
  610. void insert(InputIterator first,InputIterator last)
  611. {
  612. for(;first!=last;++first)insert(*first);
  613. }
  614. template<
  615. typename InputIterator,
  616. enable_if_derefs_to_implementation<InputIterator> =nullptr,
  617. enable_if_derefs_to_terminal<InputIterator> =nullptr
  618. >
  619. void insert(InputIterator first,InputIterator last)
  620. {
  621. if(first==last)return;
  622. /* same segment for all (type is terminal) */
  623. auto& seg=segment(get_map_iterator_for(*first));
  624. seg.insert(first,last);
  625. }
  626. template<bool Const>
  627. void insert(iterator_impl<Const> first,iterator_impl<Const> last)
  628. {
  629. for(;first!=last;++first){
  630. auto& seg=segment(get_map_iterator_for(*first,first.segment()));
  631. push_back(seg,*first);
  632. }
  633. }
  634. template<typename BaseIterator>
  635. void insert(
  636. local_iterator_impl<BaseIterator> first,
  637. local_iterator_impl<BaseIterator> last)
  638. {
  639. if(first==last)return;
  640. /* same segment for all (iterator is local) */
  641. auto& seg=segment(get_map_iterator_for(*first,first.segment()));
  642. do seg.push_back(*first); while(++first!=last);
  643. }
  644. template<
  645. typename InputIterator,
  646. enable_if_derefs_to_implementation<InputIterator> =nullptr,
  647. enable_if_derefs_to_not_terminal<InputIterator> =nullptr
  648. >
  649. void insert(const_iterator hint,InputIterator first,InputIterator last)
  650. {
  651. for(;first!=last;++first){
  652. auto it=get_map_iterator_for(*first);
  653. if(hint.mapit==it){ /* hint in segment */
  654. hint={it,map.end(),segment(it).insert(hint.segpos,*first)};
  655. ++hint;
  656. }
  657. else push_back(segment(it),*first);
  658. }
  659. }
  660. template<
  661. typename InputIterator,
  662. enable_if_derefs_to_implementation<InputIterator> =nullptr,
  663. enable_if_derefs_to_terminal<InputIterator> =nullptr
  664. >
  665. void insert(const_iterator hint,InputIterator first,InputIterator last)
  666. {
  667. if(first==last)return;
  668. /* same segment for all (type is terminal) */
  669. auto it=get_map_iterator_for(*first);
  670. auto& seg=segment(it);
  671. if(hint.mapit==it)seg.insert(hint.segpos,first,last); /* hint in segment */
  672. else seg.insert(first,last);
  673. }
  674. template<bool Const>
  675. void insert(
  676. const_iterator hint,iterator_impl<Const> first,iterator_impl<Const> last)
  677. {
  678. for(;first!=last;++first){
  679. auto it=get_map_iterator_for(*first,first.segment());
  680. if(hint.mapit==it){ /* hint in segment */
  681. hint={it,map.end(),segment(it).insert(hint.segpos,*first)};
  682. ++hint;
  683. }
  684. else push_back(segment(it),*first);
  685. }
  686. }
  687. template<typename BaseIterator>
  688. void insert(
  689. const_iterator hint,
  690. local_iterator_impl<BaseIterator> first,
  691. local_iterator_impl<BaseIterator> last)
  692. {
  693. if(first==last)return;
  694. /* same segment for all (iterator is local) */
  695. auto it=get_map_iterator_for(*first,first.segment());
  696. auto& seg=segment(it);
  697. if(hint.mapit==it){ /* hint in segment */
  698. do{
  699. hint={it,map.end(),seg.insert(hint.segpos,*first)};
  700. ++hint;
  701. }while(++first!=last);
  702. }
  703. else{
  704. do push_back(seg,*first); while(++first!=last);
  705. }
  706. }
  707. template<
  708. typename InputIterator,
  709. enable_if_derefs_to_implementation<InputIterator> =nullptr
  710. >
  711. local_base_iterator insert(
  712. const_local_base_iterator pos,InputIterator first,InputIterator last)
  713. {
  714. auto& seg=pos.segment();
  715. auto it=Model::nonconst_iterator(pos.base());
  716. size_type n=0;
  717. for(;first!=last;++first){
  718. BOOST_ASSERT(pos.type_info()==subtypeid(*first));
  719. it=std::next(seg.insert(it,*first));
  720. ++n;
  721. }
  722. return {pos.mapit,it-n};
  723. }
  724. template<typename T,typename InputIterator>
  725. local_iterator<T> insert(
  726. const_local_iterator<T> pos,InputIterator first,InputIterator last)
  727. {
  728. auto& seg=pos.segment();
  729. segment_iterator<T> it=Model::nonconst_iterator(pos.base());
  730. size_type n=0;
  731. for(;first!=last;++first){
  732. it=std::next(
  733. static_cast<segment_iterator<T>>(local_insert<T>(seg,it,*first)));
  734. ++n;
  735. }
  736. return {pos.mapit,it-n};
  737. }
  738. template<typename T,typename InputIterator>
  739. local_iterator<T> insert(
  740. local_iterator<T> pos,InputIterator first,InputIterator last)
  741. {
  742. return insert(const_local_iterator<T>{pos},first,last);
  743. }
  744. iterator erase(const_iterator pos)
  745. {
  746. return {pos.mapit,pos.mapend,pos.segment().erase(pos.segpos)};
  747. }
  748. template<typename BaseIterator>
  749. nonconst_version<local_iterator_impl<BaseIterator>>
  750. erase(local_iterator_impl<BaseIterator> pos)
  751. {
  752. return {pos.mapit,pos.segment().erase(pos.base())};
  753. }
  754. iterator erase(const_iterator first, const_iterator last)
  755. {
  756. const_segment_map_iterator fseg=first.mapit,
  757. lseg=last.mapit,
  758. end=first.mapend;
  759. if(fseg!=lseg){ /* [first,last] spans over more than one segment */
  760. /* from 1st elem to end of 1st segment */
  761. segment(fseg).erase_till_end(first.segpos);
  762. /* entire segments till last one */
  763. while(++fseg!=lseg)segment(fseg).clear();
  764. /* remaining elements of last segment */
  765. if(fseg==end){ /* except if at end of container */
  766. return {end,end};
  767. }
  768. else{
  769. return {fseg,end,segment(fseg).erase_from_begin(last.segpos)};
  770. }
  771. }
  772. else{ /* range is included in one segment only */
  773. if(first==last){ /* to avoid segment(fseg) when fseg==end */
  774. return {fseg,end,first.segpos};
  775. }
  776. else{
  777. return {fseg,end,segment(fseg).erase(first.segpos,last.segpos)};
  778. }
  779. }
  780. }
  781. template<typename BaseIterator>
  782. nonconst_version<local_iterator_impl<BaseIterator>>
  783. erase(
  784. local_iterator_impl<BaseIterator> first,
  785. local_iterator_impl<BaseIterator> last)
  786. {
  787. BOOST_ASSERT(first.mapit==last.mapit);
  788. return{
  789. first.mapit,
  790. first.segment().erase(first.base(),last.base())
  791. };
  792. }
  793. void clear()noexcept
  794. {
  795. for(auto& x:map)x.second.clear();
  796. }
  797. void clear(const std::type_info& info)
  798. {
  799. segment(get_map_iterator_for(info)).clear();
  800. }
  801. template<typename T,enable_if_acceptable<T> =nullptr>
  802. void clear()
  803. {
  804. segment(get_map_iterator_for(typeid(T))).template clear<T>();
  805. }
  806. void swap(poly_collection& x){map.swap(x.map);}
  807. private:
  808. template<typename M,typename A>
  809. friend bool operator==(
  810. const poly_collection<M,A>&,const poly_collection<M,A>&);
  811. template<
  812. typename T,
  813. enable_if_acceptable<T> =nullptr,
  814. enable_if_not_terminal<T> =nullptr
  815. >
  816. const_segment_map_iterator get_map_iterator_for(const T& x)
  817. {
  818. const auto& id=subtypeid(x);
  819. auto it=map.find(id);
  820. if(it!=map.end())return it;
  821. else if(id!=typeid(T))throw unregistered_type{id};
  822. else return map.insert(
  823. typeid(T),segment_type::template make<T>(get_allocator())).first;
  824. }
  825. template<
  826. typename T,
  827. enable_if_acceptable<T> =nullptr,
  828. enable_if_terminal<T> =nullptr
  829. >
  830. const_segment_map_iterator get_map_iterator_for(const T&)
  831. {
  832. auto it=map.find(typeid(T));
  833. if(it!=map.end())return it;
  834. else return map.insert(
  835. typeid(T),segment_type::template make<T>(get_allocator())).first;
  836. }
  837. template<
  838. typename T,
  839. enable_if_not_acceptable<T> =nullptr,
  840. enable_if_not_terminal<T> =nullptr
  841. >
  842. const_segment_map_iterator get_map_iterator_for(const T& x)const
  843. {
  844. const auto& id=subtypeid(x);
  845. auto it=map.find(id);
  846. if(it!=map.end())return it;
  847. else throw unregistered_type{id};
  848. }
  849. template<
  850. typename T,
  851. enable_if_not_acceptable<T> =nullptr,
  852. enable_if_terminal<T> =nullptr
  853. >
  854. const_segment_map_iterator get_map_iterator_for(const T&)const
  855. {
  856. static_assert(
  857. is_acceptable<T>::value,
  858. "type must be move constructible and move assignable");
  859. return {}; /* never executed */
  860. }
  861. template<typename T>
  862. const_segment_map_iterator get_map_iterator_for(
  863. const T& x,const segment_type& seg)
  864. {
  865. const auto& id=subtypeid(x);
  866. auto it=map.find(id);
  867. if(it!=map.end())return it;
  868. else return map.insert(
  869. id,segment_type::make_from_prototype(seg,get_allocator())).first;
  870. }
  871. template<typename T>
  872. const_segment_map_iterator get_map_iterator_for()
  873. {
  874. auto it=map.find(typeid(T));
  875. if(it!=map.end())return it;
  876. else return map.insert(
  877. typeid(T),segment_type::template make<T>(get_allocator())).first;
  878. }
  879. const_segment_map_iterator get_map_iterator_for(const std::type_info& info)
  880. {
  881. return const_cast<const poly_collection*>(this)->
  882. get_map_iterator_for(info);
  883. }
  884. const_segment_map_iterator get_map_iterator_for(
  885. const std::type_info& info)const
  886. {
  887. auto it=map.find(info);
  888. if(it!=map.end())return it;
  889. else throw unregistered_type{info};
  890. }
  891. static segment_type& segment(const_segment_map_iterator pos)
  892. {
  893. return const_cast<segment_type&>(pos->second);
  894. }
  895. template<
  896. typename T,
  897. enable_if_not_acceptable<T> =nullptr
  898. >
  899. segment_base_iterator push_back(segment_type& seg,T&& x)
  900. {
  901. return seg.push_back(std::forward<T>(x));
  902. }
  903. template<
  904. typename T,
  905. enable_if_acceptable<T> =nullptr,
  906. enable_if_not_terminal<T> =nullptr
  907. >
  908. segment_base_iterator push_back(segment_type& seg,T&& x)
  909. {
  910. return subtypeid(x)==typeid(T)?
  911. seg.push_back_terminal(std::forward<T>(x)):
  912. seg.push_back(std::forward<T>(x));
  913. }
  914. template<
  915. typename T,
  916. enable_if_acceptable<T> =nullptr,
  917. enable_if_terminal<T> =nullptr
  918. >
  919. segment_base_iterator push_back(segment_type& seg,T&& x)
  920. {
  921. return seg.push_back_terminal(std::forward<T>(x));
  922. }
  923. template<
  924. typename T,typename BaseIterator,typename U,
  925. enable_if_implementation<U> =nullptr,
  926. enable_if_not_constructible<T,U&&> =nullptr
  927. >
  928. static segment_base_iterator local_insert(
  929. segment_type& seg,BaseIterator pos,U&& x)
  930. {
  931. BOOST_ASSERT(subtypeid(x)==typeid(T));
  932. return seg.insert(pos,std::forward<U>(x));
  933. }
  934. template<
  935. typename T,typename BaseIterator,typename U,
  936. enable_if_implementation<U> =nullptr,
  937. enable_if_constructible<T,U&&> =nullptr
  938. >
  939. static segment_base_iterator local_insert(
  940. segment_type& seg,BaseIterator pos,U&& x)
  941. {
  942. if(subtypeid(x)==typeid(T))return seg.insert(pos,std::forward<U>(x));
  943. else return seg.template emplace<T>(pos,std::forward<U>(x));
  944. }
  945. template<
  946. typename T,typename BaseIterator,typename U,
  947. enable_if_not_implementation<U> =nullptr,
  948. enable_if_constructible<T,U&&> =nullptr
  949. >
  950. static segment_base_iterator local_insert(
  951. segment_type& seg,BaseIterator pos,U&& x)
  952. {
  953. return seg.template emplace<T>(pos,std::forward<U>(x));
  954. }
  955. template<
  956. typename T,typename BaseIterator,typename U,
  957. enable_if_not_implementation<U> =nullptr,
  958. enable_if_not_constructible<T,U&&> =nullptr
  959. >
  960. static segment_base_iterator local_insert(
  961. segment_type&,BaseIterator,U&&)
  962. {
  963. static_assert(
  964. is_constructible<T,U&&>::value,
  965. "element must be constructible from type");
  966. return {}; /* never executed */
  967. }
  968. segment_map map;
  969. };
  970. template<typename Model,typename Allocator>
  971. bool operator==(
  972. const poly_collection<Model,Allocator>& x,
  973. const poly_collection<Model,Allocator>& y)
  974. {
  975. typename poly_collection<Model,Allocator>::size_type s=0;
  976. const auto &mapx=x.map,&mapy=y.map;
  977. for(const auto& p:mapx){
  978. auto ss=p.second.size();
  979. auto it=mapy.find(*p.first);
  980. if(it==mapy.end()?ss!=0:p.second!=it->second)return false;
  981. s+=ss;
  982. }
  983. return s==y.size();
  984. }
  985. template<typename Model,typename Allocator>
  986. bool operator!=(
  987. const poly_collection<Model,Allocator>& x,
  988. const poly_collection<Model,Allocator>& y)
  989. {
  990. return !(x==y);
  991. }
  992. template<typename Model,typename Allocator>
  993. void swap(
  994. poly_collection<Model,Allocator>& x,poly_collection<Model,Allocator>& y)
  995. {
  996. x.swap(y);
  997. }
  998. } /* namespace poly_collection::common_impl */
  999. } /* namespace poly_collection */
  1000. } /* namespace boost */
  1001. #endif