poly_collection.hpp 33 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175
  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_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/iterator_impl.hpp>
  17. #include <boost/poly_collection/detail/is_acceptable.hpp>
  18. #include <boost/poly_collection/detail/is_constructible.hpp>
  19. #include <boost/poly_collection/detail/is_final.hpp>
  20. #include <boost/poly_collection/detail/newdelete_allocator.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_type=detail::segment<Model,Allocator>;
  97. using segment_base_iterator=typename segment_type::base_iterator;
  98. using const_segment_base_iterator=
  99. typename segment_type::const_base_iterator;
  100. using segment_base_sentinel=typename segment_type::base_sentinel;
  101. using const_segment_base_sentinel=
  102. typename segment_type::const_base_sentinel;
  103. template<typename T>
  104. using segment_iterator=typename segment_type::template iterator<T>;
  105. template<typename T>
  106. using const_segment_iterator=
  107. typename segment_type::template const_iterator<T>;
  108. using segment_map=type_info_map<
  109. segment_type,
  110. newdelete_allocator_adaptor<
  111. typename std::allocator_traits<Allocator>::template
  112. rebind_alloc<segment_type>
  113. >
  114. >;
  115. using segment_map_allocator_type=typename segment_map::allocator_type;
  116. using segment_map_iterator=typename segment_map::iterator;
  117. using const_segment_map_iterator=typename segment_map::const_iterator;
  118. public:
  119. /* types */
  120. using value_type=typename segment_type::value_type;
  121. using allocator_type=Allocator;
  122. using size_type=std::size_t;
  123. using difference_type=std::ptrdiff_t;
  124. using reference=value_type&;
  125. using const_reference=const value_type&;
  126. using pointer=typename std::allocator_traits<Allocator>::pointer;
  127. using const_pointer=typename std::allocator_traits<Allocator>::const_pointer;
  128. private:
  129. template<typename,bool>
  130. friend class detail::iterator_impl;
  131. template<typename,typename>
  132. friend class detail::local_iterator_impl;
  133. template<bool Const>
  134. using iterator_impl=detail::iterator_impl<poly_collection,Const>;
  135. template<typename BaseIterator>
  136. using local_iterator_impl=
  137. detail::local_iterator_impl<poly_collection,BaseIterator>;
  138. public:
  139. using iterator=iterator_impl<false>;
  140. using const_iterator=iterator_impl<true>;
  141. using local_base_iterator=local_iterator_impl<segment_base_iterator>;
  142. using const_local_base_iterator=
  143. local_iterator_impl<const_segment_base_iterator>;
  144. template<typename T>
  145. using local_iterator=local_iterator_impl<segment_iterator<T>>;
  146. template<typename T>
  147. using const_local_iterator=local_iterator_impl<const_segment_iterator<T>>;
  148. class const_base_segment_info
  149. {
  150. public:
  151. const_base_segment_info(const const_base_segment_info&)=default;
  152. const_base_segment_info& operator=(const const_base_segment_info&)=default;
  153. const_local_base_iterator begin()const noexcept
  154. {return {it,it->second.begin()};}
  155. const_local_base_iterator end()const noexcept
  156. {return {it,it->second.end()};}
  157. const_local_base_iterator cbegin()const noexcept{return begin();}
  158. const_local_base_iterator cend()const noexcept{return end();}
  159. template<typename T>
  160. const_local_iterator<T> begin()const noexcept
  161. {return const_local_iterator<T>{begin()};}
  162. template<typename T>
  163. const_local_iterator<T> end()const noexcept
  164. {return const_local_iterator<T>{end()};}
  165. template<typename T>
  166. const_local_iterator<T> cbegin()const noexcept{return begin<T>();}
  167. template<typename T>
  168. const_local_iterator<T> cend()const noexcept{return end<T>();}
  169. const std::type_info& type_info()const{return *it->first;}
  170. protected:
  171. friend class poly_collection;
  172. const_base_segment_info(const_segment_map_iterator it)noexcept:it{it}{}
  173. const_segment_map_iterator it;
  174. };
  175. class base_segment_info:public const_base_segment_info
  176. {
  177. public:
  178. base_segment_info(const base_segment_info&)=default;
  179. base_segment_info& operator=(const base_segment_info&)=default;
  180. using const_base_segment_info::begin;
  181. using const_base_segment_info::end;
  182. local_base_iterator begin()noexcept
  183. {return {this->it,this->it->second.begin()};}
  184. local_base_iterator end()noexcept
  185. {return {this->it,this->it->second.end()};}
  186. template<typename T>
  187. local_iterator<T> begin()noexcept{return local_iterator<T>{begin()};}
  188. template<typename T>
  189. local_iterator<T> end()noexcept{return local_iterator<T>{end()};}
  190. private:
  191. friend class poly_collection;
  192. using const_base_segment_info::const_base_segment_info;
  193. };
  194. template<typename T>
  195. class const_segment_info
  196. {
  197. public:
  198. const_segment_info(const const_segment_info&)=default;
  199. const_segment_info& operator=(const const_segment_info&)=default;
  200. const_local_iterator<T> begin()const noexcept
  201. {return {it,it->second.begin()};}
  202. const_local_iterator<T> end()const noexcept
  203. {return {it,it->second.end()};}
  204. const_local_iterator<T> cbegin()const noexcept{return begin();}
  205. const_local_iterator<T> cend()const noexcept{return end();}
  206. protected:
  207. friend class poly_collection;
  208. const_segment_info(const_segment_map_iterator it)noexcept:it{it}{}
  209. const_segment_map_iterator it;
  210. };
  211. template<typename T>
  212. class segment_info:public const_segment_info<T>
  213. {
  214. public:
  215. segment_info(const segment_info&)=default;
  216. segment_info& operator=(const segment_info&)=default;
  217. using const_segment_info<T>::begin;
  218. using const_segment_info<T>::end;
  219. local_iterator<T> begin()noexcept
  220. {return {this->it,this->it->second.begin()};}
  221. local_iterator<T> end()noexcept
  222. {return {this->it,this->it->second.end()};}
  223. private:
  224. friend class poly_collection;
  225. using const_segment_info<T>::const_segment_info;
  226. };
  227. private:
  228. template<typename SegmentInfo>
  229. class segment_info_iterator_impl:
  230. public boost::iterator_adaptor<
  231. segment_info_iterator_impl<SegmentInfo>,
  232. const_segment_map_iterator,
  233. SegmentInfo,
  234. std::input_iterator_tag,
  235. SegmentInfo
  236. >
  237. {
  238. segment_info_iterator_impl(const_segment_map_iterator it):
  239. segment_info_iterator_impl::iterator_adaptor_{it}{}
  240. public:
  241. segment_info_iterator_impl()=default;
  242. segment_info_iterator_impl(const segment_info_iterator_impl&)=default;
  243. segment_info_iterator_impl& operator=(
  244. const segment_info_iterator_impl&)=default;
  245. template<
  246. typename SegmentInfo2,
  247. typename std::enable_if<
  248. std::is_base_of<SegmentInfo,SegmentInfo2>::value
  249. >::type* =nullptr
  250. >
  251. segment_info_iterator_impl(
  252. const segment_info_iterator_impl<SegmentInfo2>& x):
  253. segment_info_iterator_impl::iterator_adaptor_{x.base()}{}
  254. template<
  255. typename SegmentInfo2,
  256. typename std::enable_if<
  257. std::is_base_of<SegmentInfo,SegmentInfo2>::value
  258. >::type* =nullptr
  259. >
  260. segment_info_iterator_impl& operator=(
  261. const segment_info_iterator_impl<SegmentInfo2>& x)
  262. {
  263. this->base_reference()=x.base();
  264. return *this;
  265. }
  266. private:
  267. template<typename>
  268. friend class segment_info_iterator_impl;
  269. friend class poly_collection;
  270. friend class boost::iterator_core_access;
  271. template<typename>
  272. friend struct detail::iterator_traits;
  273. SegmentInfo dereference()const noexcept{return this->base();}
  274. };
  275. public:
  276. using base_segment_info_iterator=
  277. segment_info_iterator_impl<base_segment_info>;
  278. using const_base_segment_info_iterator=
  279. segment_info_iterator_impl<const_base_segment_info>;
  280. private:
  281. template<typename Iterator>
  282. static Iterator nonconst_hlp(Iterator);
  283. static iterator nonconst_hlp(const_iterator);
  284. static local_base_iterator nonconst_hlp(const_local_base_iterator);
  285. template<typename T>
  286. static local_iterator<T> nonconst_hlp(const_local_iterator<T>);
  287. static base_segment_info_iterator nonconst_hlp(
  288. const_base_segment_info_iterator);
  289. template<typename Iterator>
  290. using nonconst_version=decltype(nonconst_hlp(std::declval<Iterator>()));
  291. public:
  292. class const_segment_traversal_info
  293. {
  294. public:
  295. const_segment_traversal_info(const const_segment_traversal_info&)=default;
  296. const_segment_traversal_info& operator=(
  297. const const_segment_traversal_info&)=default;
  298. const_base_segment_info_iterator begin()const noexcept
  299. {return pmap->cbegin();}
  300. const_base_segment_info_iterator end()const noexcept{return pmap->cend();}
  301. const_base_segment_info_iterator cbegin()const noexcept{return begin();}
  302. const_base_segment_info_iterator cend()const noexcept{return end();}
  303. protected:
  304. friend class poly_collection;
  305. const_segment_traversal_info(const segment_map& map)noexcept:
  306. pmap{const_cast<segment_map*>(&map)}{}
  307. segment_map* pmap;
  308. };
  309. class segment_traversal_info:public const_segment_traversal_info
  310. {
  311. public:
  312. segment_traversal_info(const segment_traversal_info&)=default;
  313. segment_traversal_info& operator=(const segment_traversal_info&)=default;
  314. using const_segment_traversal_info::begin;
  315. using const_segment_traversal_info::end;
  316. base_segment_info_iterator begin()noexcept{return this->pmap->cbegin();}
  317. base_segment_info_iterator end()noexcept{return this->pmap->cend();}
  318. private:
  319. friend class poly_collection;
  320. using const_segment_traversal_info::const_segment_traversal_info;
  321. };
  322. /* construct/destroy/copy */
  323. poly_collection()=default;
  324. poly_collection(const poly_collection&)=default;
  325. poly_collection(poly_collection&&)=default;
  326. explicit poly_collection(const allocator_type& al):
  327. map{segment_map_allocator_type{al}}{}
  328. poly_collection(const poly_collection& x,const allocator_type& al):
  329. map{x.map,segment_map_allocator_type{al}}{}
  330. poly_collection(poly_collection&& x,const allocator_type& al):
  331. map{std::move(x.map),segment_map_allocator_type{al}}{}
  332. template<typename InputIterator>
  333. poly_collection(
  334. InputIterator first,InputIterator last,
  335. const allocator_type& al=allocator_type{}):
  336. map{segment_map_allocator_type{al}}
  337. {
  338. this->insert(first,last);
  339. }
  340. // TODO: what to do with initializer_list?
  341. poly_collection& operator=(const poly_collection&)=default;
  342. poly_collection& operator=(poly_collection&&)=default;
  343. allocator_type get_allocator()const noexcept{return map.get_allocator();}
  344. /* type registration */
  345. template<
  346. typename... T,
  347. for_all<enable_if_acceptable<T>...> =nullptr
  348. >
  349. void register_types()
  350. {
  351. /* http://twitter.com/SeanParent/status/558765089294020609 */
  352. using seq=int[1+sizeof...(T)];
  353. (void)seq{
  354. 0,
  355. (map.insert(
  356. typeid(T),segment_type::template make<T>(get_allocator())),0)...
  357. };
  358. }
  359. bool is_registered(const std::type_info& info)const
  360. {
  361. return map.find(info)!=map.end();
  362. }
  363. template<typename T,enable_if_acceptable<T> =nullptr>
  364. bool is_registered()const
  365. {
  366. return is_registered(typeid(T));
  367. }
  368. /* iterators */
  369. iterator begin()noexcept{return {map.begin(),map.end()};}
  370. iterator end()noexcept{return {map.end(),map.end()};}
  371. const_iterator begin()const noexcept{return {map.begin(),map.end()};}
  372. const_iterator end()const noexcept{return {map.end(),map.end()};}
  373. const_iterator cbegin()const noexcept{return begin();}
  374. const_iterator cend()const noexcept{return end();}
  375. local_base_iterator begin(const std::type_info& info)
  376. {
  377. auto it=get_map_iterator_for(info);
  378. return {it,segment(it).begin()};
  379. }
  380. local_base_iterator end(const std::type_info& info)
  381. {
  382. auto it=get_map_iterator_for(info);
  383. return {it,segment(it).end()};
  384. }
  385. const_local_base_iterator begin(const std::type_info& info)const
  386. {
  387. auto it=get_map_iterator_for(info);
  388. return {it,segment(it).begin()};
  389. }
  390. const_local_base_iterator end(const std::type_info& info)const
  391. {
  392. auto it=get_map_iterator_for(info);
  393. return {it,segment(it).end()};
  394. }
  395. const_local_base_iterator cbegin(const std::type_info& info)const
  396. {return begin(info);}
  397. const_local_base_iterator cend(const std::type_info& info)const
  398. {return end(info);}
  399. template<typename T,enable_if_acceptable<T> =nullptr>
  400. local_iterator<T> begin()
  401. {
  402. auto it=get_map_iterator_for(typeid(T));
  403. return {it,segment(it).template begin<T>()};
  404. }
  405. template<typename T,enable_if_acceptable<T> =nullptr>
  406. local_iterator<T> end()
  407. {
  408. auto it=get_map_iterator_for(typeid(T));
  409. return {it,segment(it).template end<T>()};
  410. }
  411. template<typename T,enable_if_acceptable<T> =nullptr>
  412. const_local_iterator<T> begin()const
  413. {
  414. auto it=get_map_iterator_for(typeid(T));
  415. return {it,segment(it).template begin<T>()};
  416. }
  417. template<typename T,enable_if_acceptable<T> =nullptr>
  418. const_local_iterator<T> end()const
  419. {
  420. auto it=get_map_iterator_for(typeid(T));
  421. return {it,segment(it).template end<T>()};
  422. }
  423. template<typename T,enable_if_acceptable<T> =nullptr>
  424. const_local_iterator<T> cbegin()const{return begin<T>();}
  425. template<typename T,enable_if_acceptable<T> =nullptr>
  426. const_local_iterator<T> cend()const{return end<T>();}
  427. base_segment_info segment(const std::type_info& info)
  428. {
  429. return get_map_iterator_for(info);
  430. }
  431. const_base_segment_info segment(const std::type_info& info)const
  432. {
  433. return get_map_iterator_for(info);
  434. }
  435. template<typename T,enable_if_acceptable<T> =nullptr>
  436. segment_info<T> segment(){return get_map_iterator_for(typeid(T));}
  437. template<typename T,enable_if_acceptable<T> =nullptr>
  438. const_segment_info<T> segment()const{return get_map_iterator_for(typeid(T));}
  439. segment_traversal_info segment_traversal()noexcept{return map;}
  440. const_segment_traversal_info segment_traversal()const noexcept{return map;}
  441. /* capacity */
  442. bool empty()const noexcept
  443. {
  444. for(const auto& x:map)if(!x.second.empty())return false;
  445. return true;
  446. }
  447. bool empty(const std::type_info& info)const
  448. {
  449. return segment(get_map_iterator_for(info)).empty();
  450. }
  451. template<typename T,enable_if_acceptable<T> =nullptr>
  452. bool empty()const
  453. {
  454. return segment(get_map_iterator_for(typeid(T))).template empty<T>();
  455. }
  456. size_type size()const noexcept
  457. {
  458. size_type res=0;
  459. for(const auto& x:map)res+=x.second.size();
  460. return res;
  461. }
  462. size_type size(const std::type_info& info)const
  463. {
  464. return segment(get_map_iterator_for(info)).size();
  465. }
  466. template<typename T,enable_if_acceptable<T> =nullptr>
  467. size_type size()const
  468. {
  469. return segment(get_map_iterator_for(typeid(T))).template size<T>();
  470. }
  471. size_type max_size(const std::type_info& info)const
  472. {
  473. return segment(get_map_iterator_for(info)).max_size();
  474. }
  475. template<typename T,enable_if_acceptable<T> =nullptr>
  476. size_type max_size()const
  477. {
  478. return segment(get_map_iterator_for(typeid(T))).template max_size<T>();
  479. }
  480. size_type capacity(const std::type_info& info)const
  481. {
  482. return segment(get_map_iterator_for(info)).capacity();
  483. }
  484. template<typename T,enable_if_acceptable<T> =nullptr>
  485. size_type capacity()const
  486. {
  487. return segment(get_map_iterator_for(typeid(T))).template capacity<T>();
  488. }
  489. void reserve(size_type n)
  490. {
  491. for(auto& x:map)x.second.reserve(n);
  492. }
  493. void reserve(const std::type_info& info,size_type n)
  494. {
  495. segment(get_map_iterator_for(info)).reserve(n);
  496. }
  497. template<typename T,enable_if_acceptable<T> =nullptr>
  498. void reserve(size_type n)
  499. {
  500. /* note this creates the segment if it didn't previously exist */
  501. segment(get_map_iterator_for<T>()).template reserve<T>(n);
  502. }
  503. void shrink_to_fit()
  504. {
  505. for(auto& x:map)x.second.shrink_to_fit();
  506. }
  507. void shrink_to_fit(const std::type_info& info)
  508. {
  509. segment(get_map_iterator_for(info)).shrink_to_fit();
  510. }
  511. template<typename T,enable_if_acceptable<T> =nullptr>
  512. void shrink_to_fit()
  513. {
  514. segment(get_map_iterator_for(typeid(T))).template shrink_to_fit<T>();
  515. }
  516. /* modifiers */
  517. template<typename T,typename... Args,enable_if_acceptable<T> =nullptr>
  518. iterator emplace(Args&&... args)
  519. {
  520. auto it=get_map_iterator_for<T>();
  521. return {
  522. it,map.end(),
  523. segment(it).template emplace_back<T>(std::forward<Args>(args)...)
  524. };
  525. }
  526. template<typename T,typename... Args,enable_if_acceptable<T> =nullptr>
  527. iterator emplace_hint(const_iterator hint,Args&&... args)
  528. {
  529. auto it=get_map_iterator_for<T>();
  530. return {
  531. it,map.end(),
  532. hint.mapit==it? /* hint in segment */
  533. segment(it).template emplace<T>(
  534. hint.segpos,std::forward<Args>(args)...):
  535. segment(it).template emplace_back<T>(std::forward<Args>(args)...)
  536. };
  537. }
  538. template<typename T,typename... Args,enable_if_acceptable<T> =nullptr>
  539. local_base_iterator
  540. emplace_pos(local_base_iterator pos,Args&&... args)
  541. {
  542. return emplace_pos<T>(
  543. const_local_base_iterator{pos},std::forward<Args>(args)...);
  544. }
  545. template<typename T,typename... Args,enable_if_acceptable<T> =nullptr>
  546. local_base_iterator
  547. emplace_pos(const_local_base_iterator pos,Args&&... args)
  548. {
  549. BOOST_ASSERT(pos.type_info()==typeid(T));
  550. return {
  551. pos.mapit,
  552. pos.segment().template emplace<T>(pos.base(),std::forward<Args>(args)...)
  553. };
  554. }
  555. template<typename T,typename... Args>
  556. local_iterator<T>
  557. emplace_pos(local_iterator<T> pos,Args&&... args)
  558. {
  559. return emplace_pos(
  560. const_local_iterator<T>{pos},std::forward<Args>(args)...);
  561. }
  562. template<typename T,typename... Args>
  563. local_iterator<T>
  564. emplace_pos(const_local_iterator<T> pos,Args&&... args)
  565. {
  566. return {
  567. pos.mapit,
  568. pos.segment().template emplace<T>(pos.base(),std::forward<Args>(args)...)
  569. };
  570. }
  571. template<typename T,enable_if_implementation<T> =nullptr>
  572. iterator insert(T&& x)
  573. {
  574. auto it=get_map_iterator_for(x);
  575. return {it,map.end(),push_back(segment(it),std::forward<T>(x))};
  576. }
  577. template<
  578. typename T,
  579. enable_if_not_same<const_iterator,T> =nullptr,
  580. enable_if_implementation<T> =nullptr
  581. >
  582. iterator insert(const_iterator hint,T&& x)
  583. {
  584. auto it=get_map_iterator_for(x);
  585. return {
  586. it,map.end(),
  587. hint.mapit==it? /* hint in segment */
  588. segment(it).insert(hint.segpos,std::forward<T>(x)):
  589. push_back(segment(it),std::forward<T>(x))
  590. };
  591. }
  592. template<
  593. typename BaseIterator,typename T,
  594. enable_if_not_same<local_iterator_impl<BaseIterator>,T> =nullptr,
  595. enable_if_implementation<T> =nullptr
  596. >
  597. nonconst_version<local_iterator_impl<BaseIterator>>
  598. insert(local_iterator_impl<BaseIterator> pos,T&& x)
  599. {
  600. BOOST_ASSERT(pos.type_info()==subtypeid(x));
  601. return {
  602. pos.mapit,
  603. pos.segment().insert(pos.base(),std::forward<T>(x))
  604. };
  605. }
  606. template<
  607. typename InputIterator,
  608. enable_if_derefs_to_implementation<InputIterator> =nullptr,
  609. enable_if_derefs_to_not_terminal<InputIterator> =nullptr
  610. >
  611. void insert(InputIterator first,InputIterator last)
  612. {
  613. for(;first!=last;++first)insert(*first);
  614. }
  615. template<
  616. typename InputIterator,
  617. enable_if_derefs_to_implementation<InputIterator> =nullptr,
  618. enable_if_derefs_to_terminal<InputIterator> =nullptr
  619. >
  620. void insert(InputIterator first,InputIterator last)
  621. {
  622. if(first==last)return;
  623. /* same segment for all (type is terminal) */
  624. auto& seg=segment(get_map_iterator_for(*first));
  625. seg.insert(first,last);
  626. }
  627. template<bool Const>
  628. void insert(iterator_impl<Const> first,iterator_impl<Const> last)
  629. {
  630. for(;first!=last;++first){
  631. auto& seg=segment(get_map_iterator_for(*first,first.segment()));
  632. push_back(seg,*first);
  633. }
  634. }
  635. template<typename BaseIterator>
  636. void insert(
  637. local_iterator_impl<BaseIterator> first,
  638. local_iterator_impl<BaseIterator> last)
  639. {
  640. if(first==last)return;
  641. /* same segment for all (iterator is local) */
  642. auto& seg=segment(get_map_iterator_for(*first,first.segment()));
  643. do seg.push_back(*first); while(++first!=last);
  644. }
  645. template<
  646. typename InputIterator,
  647. enable_if_derefs_to_implementation<InputIterator> =nullptr,
  648. enable_if_derefs_to_not_terminal<InputIterator> =nullptr
  649. >
  650. void insert(const_iterator hint,InputIterator first,InputIterator last)
  651. {
  652. for(;first!=last;++first){
  653. auto it=get_map_iterator_for(*first);
  654. if(hint.mapit==it){ /* hint in segment */
  655. hint={it,map.end(),segment(it).insert(hint.segpos,*first)};
  656. ++hint;
  657. }
  658. else push_back(segment(it),*first);
  659. }
  660. }
  661. template<
  662. typename InputIterator,
  663. enable_if_derefs_to_implementation<InputIterator> =nullptr,
  664. enable_if_derefs_to_terminal<InputIterator> =nullptr
  665. >
  666. void insert(const_iterator hint,InputIterator first,InputIterator last)
  667. {
  668. if(first==last)return;
  669. /* same segment for all (type is terminal) */
  670. auto it=get_map_iterator_for(*first);
  671. auto& seg=segment(it);
  672. if(hint.mapit==it)seg.insert(hint.segpos,first,last); /* hint in segment */
  673. else seg.insert(first,last);
  674. }
  675. template<bool Const>
  676. void insert(
  677. const_iterator hint,iterator_impl<Const> first,iterator_impl<Const> last)
  678. {
  679. for(;first!=last;++first){
  680. auto it=get_map_iterator_for(*first,first.segment());
  681. if(hint.mapit==it){ /* hint in segment */
  682. hint={it,map.end(),segment(it).insert(hint.segpos,*first)};
  683. ++hint;
  684. }
  685. else push_back(segment(it),*first);
  686. }
  687. }
  688. template<typename BaseIterator>
  689. void insert(
  690. const_iterator hint,
  691. local_iterator_impl<BaseIterator> first,
  692. local_iterator_impl<BaseIterator> last)
  693. {
  694. if(first==last)return;
  695. /* same segment for all (iterator is local) */
  696. auto it=get_map_iterator_for(*first,first.segment());
  697. auto& seg=segment(it);
  698. if(hint.mapit==it){ /* hint in segment */
  699. do{
  700. hint={it,map.end(),seg.insert(hint.segpos,*first)};
  701. ++hint;
  702. }while(++first!=last);
  703. }
  704. else{
  705. do push_back(seg,*first); while(++first!=last);
  706. }
  707. }
  708. template<
  709. typename InputIterator,
  710. enable_if_derefs_to_implementation<InputIterator> =nullptr
  711. >
  712. local_base_iterator insert(
  713. const_local_base_iterator pos,InputIterator first,InputIterator last)
  714. {
  715. auto& seg=pos.segment();
  716. auto it=Model::nonconst_iterator(pos.base());
  717. size_type n=0;
  718. for(;first!=last;++first){
  719. BOOST_ASSERT(pos.type_info()==subtypeid(*first));
  720. it=std::next(seg.insert(it,*first));
  721. ++n;
  722. }
  723. return {pos.mapit,it-n};
  724. }
  725. template<typename T,typename InputIterator>
  726. local_iterator<T> insert(
  727. const_local_iterator<T> pos,InputIterator first,InputIterator last)
  728. {
  729. auto& seg=pos.segment();
  730. segment_iterator<T> it=Model::nonconst_iterator(pos.base());
  731. size_type n=0;
  732. for(;first!=last;++first){
  733. it=std::next(
  734. static_cast<segment_iterator<T>>(local_insert<T>(seg,it,*first)));
  735. ++n;
  736. }
  737. return {pos.mapit,it-n};
  738. }
  739. template<typename T,typename InputIterator>
  740. local_iterator<T> insert(
  741. local_iterator<T> pos,InputIterator first,InputIterator last)
  742. {
  743. return insert(const_local_iterator<T>{pos},first,last);
  744. }
  745. iterator erase(const_iterator pos)
  746. {
  747. return {pos.mapit,pos.mapend,pos.segment().erase(pos.segpos)};
  748. }
  749. template<typename BaseIterator>
  750. nonconst_version<local_iterator_impl<BaseIterator>>
  751. erase(local_iterator_impl<BaseIterator> pos)
  752. {
  753. return {pos.mapit,pos.segment().erase(pos.base())};
  754. }
  755. iterator erase(const_iterator first, const_iterator last)
  756. {
  757. const_segment_map_iterator fseg=first.mapit,
  758. lseg=last.mapit,
  759. end=first.mapend;
  760. if(fseg!=lseg){ /* [first,last] spans over more than one segment */
  761. /* from 1st elem to end of 1st segment */
  762. segment(fseg).erase_till_end(first.segpos);
  763. /* entire segments till last one */
  764. while(++fseg!=lseg)segment(fseg).clear();
  765. /* remaining elements of last segment */
  766. if(fseg==end){ /* except if at end of container */
  767. return {end,end};
  768. }
  769. else{
  770. return {fseg,end,segment(fseg).erase_from_begin(last.segpos)};
  771. }
  772. }
  773. else{ /* range is included in one segment only */
  774. if(first==last){ /* to avoid segment(fseg) when fseg==end */
  775. return {fseg,end,first.segpos};
  776. }
  777. else{
  778. return {fseg,end,segment(fseg).erase(first.segpos,last.segpos)};
  779. }
  780. }
  781. }
  782. template<typename BaseIterator>
  783. nonconst_version<local_iterator_impl<BaseIterator>>
  784. erase(
  785. local_iterator_impl<BaseIterator> first,
  786. local_iterator_impl<BaseIterator> last)
  787. {
  788. BOOST_ASSERT(first.mapit==last.mapit);
  789. return{
  790. first.mapit,
  791. first.segment().erase(first.base(),last.base())
  792. };
  793. }
  794. void clear()noexcept
  795. {
  796. for(auto& x:map)x.second.clear();
  797. }
  798. void clear(const std::type_info& info)
  799. {
  800. segment(get_map_iterator_for(info)).clear();
  801. }
  802. template<typename T,enable_if_acceptable<T> =nullptr>
  803. void clear()
  804. {
  805. segment(get_map_iterator_for(typeid(T))).template clear<T>();
  806. }
  807. void swap(poly_collection& x){map.swap(x.map);}
  808. private:
  809. template<typename M,typename A>
  810. friend bool operator==(
  811. const poly_collection<M,A>&,const poly_collection<M,A>&);
  812. template<
  813. typename T,
  814. enable_if_acceptable<T> =nullptr,
  815. enable_if_not_terminal<T> =nullptr
  816. >
  817. const_segment_map_iterator get_map_iterator_for(const T& x)
  818. {
  819. const auto& id=subtypeid(x);
  820. auto it=map.find(id);
  821. if(it!=map.end())return it;
  822. else if(id!=typeid(T))throw unregistered_type{id};
  823. else return map.insert(
  824. typeid(T),segment_type::template make<T>(get_allocator())).first;
  825. }
  826. template<
  827. typename T,
  828. enable_if_acceptable<T> =nullptr,
  829. enable_if_terminal<T> =nullptr
  830. >
  831. const_segment_map_iterator get_map_iterator_for(const T&)
  832. {
  833. auto it=map.find(typeid(T));
  834. if(it!=map.end())return it;
  835. else return map.insert(
  836. typeid(T),segment_type::template make<T>(get_allocator())).first;
  837. }
  838. template<
  839. typename T,
  840. enable_if_not_acceptable<T> =nullptr,
  841. enable_if_not_terminal<T> =nullptr
  842. >
  843. const_segment_map_iterator get_map_iterator_for(const T& x)const
  844. {
  845. const auto& id=subtypeid(x);
  846. auto it=map.find(id);
  847. if(it!=map.end())return it;
  848. else throw unregistered_type{id};
  849. }
  850. template<
  851. typename T,
  852. enable_if_not_acceptable<T> =nullptr,
  853. enable_if_terminal<T> =nullptr
  854. >
  855. const_segment_map_iterator get_map_iterator_for(const T&)const
  856. {
  857. static_assert(
  858. is_acceptable<T>::value,
  859. "type must be move constructible and move assignable");
  860. return {}; /* never executed */
  861. }
  862. template<typename T>
  863. const_segment_map_iterator get_map_iterator_for(
  864. const T& x,const segment_type& seg)
  865. {
  866. const auto& id=subtypeid(x);
  867. auto it=map.find(id);
  868. if(it!=map.end())return it;
  869. else return map.insert(id,segment_type::make_from_prototype(seg)).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