]> git.proxmox.com Git - ceph.git/blame - ceph/src/boost/boost/poly_collection/detail/poly_collection.hpp
import new upstream nautilus stable release 14.2.8
[ceph.git] / ceph / src / boost / boost / poly_collection / detail / poly_collection.hpp
CommitLineData
92f5a8d4 1/* Copyright 2016-2018 Joaquin M Lopez Munoz.
b32b8144
FG
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>
92f5a8d4 19#include <boost/poly_collection/detail/allocator_adaptor.hpp>
b32b8144
FG
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>
b32b8144
FG
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
32namespace boost{
33
34namespace poly_collection{
35
36namespace common_impl{
37
38/* common implementation for all polymorphic collections */
39
40using namespace detail;
41
42template<typename Model,typename Allocator>
43class poly_collection
44{
45 template<typename T>
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
92f5a8d4
TL
106 using segment_allocator_type=allocator_adaptor<Allocator>;
107 using segment_type=detail::segment<Model,segment_allocator_type>;
b32b8144
FG
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,
92f5a8d4
TL
121 typename std::allocator_traits<segment_allocator_type>::template
122 rebind_alloc<segment_type>
b32b8144
FG
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
128public:
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
140private:
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
151public:
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
168 const_local_base_iterator begin()const noexcept
169 {return {it,it->second.begin()};}
170 const_local_base_iterator end()const noexcept
171 {return {it,it->second.end()};}
172 const_local_base_iterator cbegin()const noexcept{return begin();}
173 const_local_base_iterator cend()const noexcept{return end();}
174
175 template<typename T>
176 const_local_iterator<T> begin()const noexcept
177 {return const_local_iterator<T>{begin()};}
178 template<typename T>
179 const_local_iterator<T> end()const noexcept
180 {return const_local_iterator<T>{end()};}
181 template<typename T>
182 const_local_iterator<T> cbegin()const noexcept{return begin<T>();}
183 template<typename T>
184 const_local_iterator<T> cend()const noexcept{return end<T>();}
185
186 const std::type_info& type_info()const{return *it->first;}
187
188 protected:
189 friend class poly_collection;
190
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
205 local_base_iterator begin()noexcept
206 {return {this->it,this->it->second.begin()};}
207 local_base_iterator end()noexcept
208 {return {this->it,this->it->second.end()};}
209
210 template<typename T>
211 local_iterator<T> begin()noexcept{return local_iterator<T>{begin()};}
212 template<typename T>
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
228 const_local_iterator<T> begin()const noexcept
229 {return {it,it->second.begin()};}
230 const_local_iterator<T> end()const noexcept
231 {return {it,it->second.end()};}
232 const_local_iterator<T> cbegin()const noexcept{return begin();}
233 const_local_iterator<T> cend()const noexcept{return end();}
234
235 protected:
236 friend class poly_collection;
237
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
253 local_iterator<T> begin()noexcept
254 {return {this->it,this->it->second.begin()};}
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
264private:
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 {
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 >
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 >
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
315 SegmentInfo dereference()const noexcept{return this->base();}
316 };
317
318public:
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
324private:
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
337public:
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
345 const_base_segment_info_iterator begin()const noexcept
346 {return pmap->cbegin();}
347 const_base_segment_info_iterator end()const noexcept{return pmap->cend();}
348 const_base_segment_info_iterator cbegin()const noexcept{return begin();}
349 const_base_segment_info_iterator cend()const noexcept{return end();}
350
351 protected:
352 friend class poly_collection;
353
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
369 base_segment_info_iterator begin()noexcept{return this->pmap->cbegin();}
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;
383 explicit poly_collection(const allocator_type& al):
384 map{segment_map_allocator_type{al}}{}
385 poly_collection(const poly_collection& x,const allocator_type& al):
386 map{x.map,segment_map_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>
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
404 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 >
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
424 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>
430 bool is_registered()const
431 {
432 return is_registered(typeid(T));
433 }
434
435 /* iterators */
436
437 iterator begin()noexcept{return {map.begin(),map.end()};}
438 iterator end()noexcept{return {map.end(),map.end()};}
439 const_iterator begin()const noexcept{return {map.begin(),map.end()};}
440 const_iterator end()const noexcept{return {map.end(),map.end()};}
441 const_iterator cbegin()const noexcept{return begin();}
442 const_iterator cend()const noexcept{return end();}
443
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
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
456 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
462 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
468 const_local_base_iterator cbegin(const std::type_info& info)const
469 {return begin(info);}
470 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>
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>
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>
488 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>
495 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>
502 const_local_iterator<T> cbegin()const{return begin<T>();}
503
504 template<typename T,enable_if_acceptable<T> =nullptr>
505 const_local_iterator<T> cend()const{return end<T>();}
506
507 base_segment_info segment(const std::type_info& info)
508 {
509 return get_map_iterator_for(info);
510 }
511
512 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>
518 segment_info<T> segment(){return get_map_iterator_for(typeid(T));}
519
520 template<typename T,enable_if_acceptable<T> =nullptr>
521 const_segment_info<T> segment()const{return get_map_iterator_for(typeid(T));}
522
523 segment_traversal_info segment_traversal()noexcept{return map;}
524 const_segment_traversal_info segment_traversal()const noexcept{return map;}
525
526 /* capacity */
527
528 bool empty()const noexcept
529 {
530 for(const auto& x:map)if(!x.second.empty())return false;
531 return true;
532 }
533
534 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>
540 bool empty()const
541 {
542 return segment(get_map_iterator_for(typeid(T))).template empty<T>();
543 }
544
545 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
552 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>
558 size_type size()const
559 {
560 return segment(get_map_iterator_for(typeid(T))).template size<T>();
561 }
562
563 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>
569 size_type max_size()const
570 {
571 return segment(get_map_iterator_for(typeid(T))).template max_size<T>();
572 }
573
574 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>
580 size_type capacity()const
581 {
582 return segment(get_map_iterator_for(typeid(T))).template capacity<T>();
583 }
584
585 void reserve(size_type n)
586 {
587 for(auto& x:map)x.second.reserve(n);
588 }
589
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>
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
603 void shrink_to_fit()
604 {
605 for(auto& x:map)x.second.shrink_to_fit();
606 }
607
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>
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>
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>
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
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
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>
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>
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>
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 >
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>>
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 >
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 >
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>
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>
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 >
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 >
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>
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>
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 >
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>
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>
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
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>>
886 erase(local_iterator_impl<BaseIterator> pos)
887 {
888 return {pos.mapit,pos.segment().erase(pos.base())};
889 }
890
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>>
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
938 void clear()noexcept
939 {
940 for(auto& x:map)x.second.clear();
941 }
942
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>
949 void clear()
950 {
951 segment(get_map_iterator_for(typeid(T))).template clear<T>();
952 }
953
954 void swap(poly_collection& x){map.swap(x.map);}
955
956private:
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 >
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 >
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 >
994 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 >
1007 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>
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;
92f5a8d4
TL
1022 else return map.insert(
1023 id,segment_type::make_from_prototype(seg,get_allocator())).first;
b32b8144
FG
1024 }
1025
1026 template<typename T>
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
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
1041 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
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 >
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 >
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 >
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 >
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 >
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 >
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 >
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
1137template<typename Model,typename Allocator>
1138bool 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
1153template<typename Model,typename Allocator>
1154bool operator!=(
1155 const poly_collection<Model,Allocator>& x,
1156 const poly_collection<Model,Allocator>& y)
1157{
1158 return !(x==y);
1159}
1160
1161template<typename Model,typename Allocator>
1162void 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