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