poly_collection.hpp 33 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175
  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