| 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175 |
- /* Copyright 2016-2018 Joaquin M Lopez Munoz.
- * Distributed under the Boost Software License, Version 1.0.
- * (See accompanying file LICENSE_1_0.txt or copy at
- * http://www.boost.org/LICENSE_1_0.txt)
- *
- * See http://www.boost.org/libs/poly_collection for library home page.
- */
- #ifndef BOOST_POLY_COLLECTION_DETAIL_POLY_COLLECTION_HPP
- #define BOOST_POLY_COLLECTION_DETAIL_POLY_COLLECTION_HPP
- #if defined(_MSC_VER)
- #pragma once
- #endif
- #include <algorithm>
- #include <boost/assert.hpp>
- #include <boost/iterator/iterator_adaptor.hpp>
- #include <boost/poly_collection/detail/allocator_adaptor.hpp>
- #include <boost/poly_collection/detail/iterator_impl.hpp>
- #include <boost/poly_collection/detail/is_acceptable.hpp>
- #include <boost/poly_collection/detail/is_constructible.hpp>
- #include <boost/poly_collection/detail/is_final.hpp>
- #include <boost/poly_collection/detail/segment.hpp>
- #include <boost/poly_collection/detail/type_info_map.hpp>
- #include <boost/poly_collection/exception.hpp>
- #include <iterator>
- #include <type_traits>
- #include <typeinfo>
- #include <utility>
- namespace boost{
- namespace poly_collection{
- namespace common_impl{
- /* common implementation for all polymorphic collections */
- using namespace detail;
- template<typename Model,typename Allocator>
- class poly_collection
- {
- template<typename T>
- static const std::type_info& subtypeid(const T& x)
- {return Model::subtypeid(x);}
- template<typename...>
- struct for_all_types{using type=void*;};
- template<typename... T>
- using for_all=typename for_all_types<T...>::type;
- template<typename T>
- struct is_implementation: /* using makes VS2015 choke, hence we derive */
- Model::template is_implementation<typename std::decay<T>::type>{};
- template<typename T>
- using enable_if_implementation=
- typename std::enable_if<is_implementation<T>::value>::type*;
- template<typename T>
- using enable_if_not_implementation=
- typename std::enable_if<!is_implementation<T>::value>::type*;
- template<typename T>
- using is_acceptable=
- detail::is_acceptable<typename std::decay<T>::type,Model>;
- template<typename T>
- using enable_if_acceptable=
- typename std::enable_if<is_acceptable<T>::value>::type*;
- template<typename T>
- using enable_if_not_acceptable=
- typename std::enable_if<!is_acceptable<T>::value>::type*;
- template<typename InputIterator>
- using enable_if_derefs_to_implementation=enable_if_implementation<
- typename std::iterator_traits<InputIterator>::value_type
- >;
- template<typename T>
- using is_terminal=
- typename Model::template is_terminal<typename std::decay<T>::type>;
- template<typename T>
- using enable_if_terminal=
- typename std::enable_if<is_terminal<T>::value>::type*;
- template<typename T>
- using enable_if_not_terminal=
- typename std::enable_if<!is_terminal<T>::value>::type*;
- template<typename InputIterator>
- using derefs_to_terminal=is_terminal<
- typename std::iterator_traits<InputIterator>::value_type
- >;
- template<typename InputIterator>
- using enable_if_derefs_to_terminal=
- typename std::enable_if<derefs_to_terminal<InputIterator>::value>::type*;
- template<typename InputIterator>
- using enable_if_derefs_to_not_terminal=
- typename std::enable_if<!derefs_to_terminal<InputIterator>::value>::type*;
- template<typename T,typename U>
- using enable_if_not_same=typename std::enable_if<
- !std::is_same<
- typename std::decay<T>::type,typename std::decay<U>::type
- >::value
- >::type*;
- template<typename T,typename U>
- using enable_if_constructible=
- typename std::enable_if<is_constructible<T,U>::value>::type*;
- template<typename T,typename U>
- using enable_if_not_constructible=
- typename std::enable_if<!is_constructible<T,U>::value>::type*;
- using segment_allocator_type=allocator_adaptor<Allocator>;
- using segment_type=detail::segment<Model,segment_allocator_type>;
- using segment_base_iterator=typename segment_type::base_iterator;
- using const_segment_base_iterator=
- typename segment_type::const_base_iterator;
- using segment_base_sentinel=typename segment_type::base_sentinel;
- using const_segment_base_sentinel=
- typename segment_type::const_base_sentinel;
- template<typename T>
- using segment_iterator=typename segment_type::template iterator<T>;
- template<typename T>
- using const_segment_iterator=
- typename segment_type::template const_iterator<T>;
- using segment_map=type_info_map<
- segment_type,
- typename std::allocator_traits<segment_allocator_type>::template
- rebind_alloc<segment_type>
- >;
- using segment_map_allocator_type=typename segment_map::allocator_type;
- using segment_map_iterator=typename segment_map::iterator;
- using const_segment_map_iterator=typename segment_map::const_iterator;
- public:
- /* types */
- using value_type=typename segment_type::value_type;
- using allocator_type=Allocator;
- using size_type=std::size_t;
- using difference_type=std::ptrdiff_t;
- using reference=value_type&;
- using const_reference=const value_type&;
- using pointer=typename std::allocator_traits<Allocator>::pointer;
- using const_pointer=typename std::allocator_traits<Allocator>::const_pointer;
- private:
- template<typename,bool>
- friend class detail::iterator_impl;
- template<typename,typename>
- friend class detail::local_iterator_impl;
- template<bool Const>
- using iterator_impl=detail::iterator_impl<poly_collection,Const>;
- template<typename BaseIterator>
- using local_iterator_impl=
- detail::local_iterator_impl<poly_collection,BaseIterator>;
- public:
- using iterator=iterator_impl<false>;
- using const_iterator=iterator_impl<true>;
- using local_base_iterator=local_iterator_impl<segment_base_iterator>;
- using const_local_base_iterator=
- local_iterator_impl<const_segment_base_iterator>;
- template<typename T>
- using local_iterator=local_iterator_impl<segment_iterator<T>>;
- template<typename T>
- using const_local_iterator=local_iterator_impl<const_segment_iterator<T>>;
- class const_base_segment_info
- {
- public:
- const_base_segment_info(const const_base_segment_info&)=default;
- const_base_segment_info& operator=(const const_base_segment_info&)=default;
-
- const_local_base_iterator begin()const noexcept
- {return {it,it->second.begin()};}
- const_local_base_iterator end()const noexcept
- {return {it,it->second.end()};}
- const_local_base_iterator cbegin()const noexcept{return begin();}
- const_local_base_iterator cend()const noexcept{return end();}
- template<typename T>
- const_local_iterator<T> begin()const noexcept
- {return const_local_iterator<T>{begin()};}
- template<typename T>
- const_local_iterator<T> end()const noexcept
- {return const_local_iterator<T>{end()};}
- template<typename T>
- const_local_iterator<T> cbegin()const noexcept{return begin<T>();}
- template<typename T>
- const_local_iterator<T> cend()const noexcept{return end<T>();}
- const std::type_info& type_info()const{return *it->first;}
- protected:
- friend class poly_collection;
- const_base_segment_info(const_segment_map_iterator it)noexcept:it{it}{}
- const_segment_map_iterator it;
- };
- class base_segment_info:public const_base_segment_info
- {
- public:
- base_segment_info(const base_segment_info&)=default;
- base_segment_info& operator=(const base_segment_info&)=default;
- using const_base_segment_info::begin;
- using const_base_segment_info::end;
- local_base_iterator begin()noexcept
- {return {this->it,this->it->second.begin()};}
- local_base_iterator end()noexcept
- {return {this->it,this->it->second.end()};}
- template<typename T>
- local_iterator<T> begin()noexcept{return local_iterator<T>{begin()};}
- template<typename T>
- local_iterator<T> end()noexcept{return local_iterator<T>{end()};}
- private:
- friend class poly_collection;
- using const_base_segment_info::const_base_segment_info;
- };
- template<typename T>
- class const_segment_info
- {
- public:
- const_segment_info(const const_segment_info&)=default;
- const_segment_info& operator=(const const_segment_info&)=default;
-
- const_local_iterator<T> begin()const noexcept
- {return {it,it->second.begin()};}
- const_local_iterator<T> end()const noexcept
- {return {it,it->second.end()};}
- const_local_iterator<T> cbegin()const noexcept{return begin();}
- const_local_iterator<T> cend()const noexcept{return end();}
- protected:
- friend class poly_collection;
- const_segment_info(const_segment_map_iterator it)noexcept:it{it}{}
- const_segment_map_iterator it;
- };
- template<typename T>
- class segment_info:public const_segment_info<T>
- {
- public:
- segment_info(const segment_info&)=default;
- segment_info& operator=(const segment_info&)=default;
- using const_segment_info<T>::begin;
- using const_segment_info<T>::end;
- local_iterator<T> begin()noexcept
- {return {this->it,this->it->second.begin()};}
- local_iterator<T> end()noexcept
- {return {this->it,this->it->second.end()};}
- private:
- friend class poly_collection;
- using const_segment_info<T>::const_segment_info;
- };
- private:
- template<typename SegmentInfo>
- class segment_info_iterator_impl:
- public boost::iterator_adaptor<
- segment_info_iterator_impl<SegmentInfo>,
- const_segment_map_iterator,
- SegmentInfo,
- std::input_iterator_tag,
- SegmentInfo
- >
- {
- segment_info_iterator_impl(const_segment_map_iterator it):
- segment_info_iterator_impl::iterator_adaptor_{it}{}
- public:
- segment_info_iterator_impl()=default;
- segment_info_iterator_impl(const segment_info_iterator_impl&)=default;
- segment_info_iterator_impl& operator=(
- const segment_info_iterator_impl&)=default;
- template<
- typename SegmentInfo2,
- typename std::enable_if<
- std::is_base_of<SegmentInfo,SegmentInfo2>::value
- >::type* =nullptr
- >
- segment_info_iterator_impl(
- const segment_info_iterator_impl<SegmentInfo2>& x):
- segment_info_iterator_impl::iterator_adaptor_{x.base()}{}
-
- template<
- typename SegmentInfo2,
- typename std::enable_if<
- std::is_base_of<SegmentInfo,SegmentInfo2>::value
- >::type* =nullptr
- >
- segment_info_iterator_impl& operator=(
- const segment_info_iterator_impl<SegmentInfo2>& x)
- {
- this->base_reference()=x.base();
- return *this;
- }
- private:
- template<typename>
- friend class segment_info_iterator_impl;
- friend class poly_collection;
- friend class boost::iterator_core_access;
- template<typename>
- friend struct detail::iterator_traits;
- SegmentInfo dereference()const noexcept{return this->base();}
- };
- public:
- using base_segment_info_iterator=
- segment_info_iterator_impl<base_segment_info>;
- using const_base_segment_info_iterator=
- segment_info_iterator_impl<const_base_segment_info>;
-
- private:
- template<typename Iterator>
- static Iterator nonconst_hlp(Iterator);
- static iterator nonconst_hlp(const_iterator);
- static local_base_iterator nonconst_hlp(const_local_base_iterator);
- template<typename T>
- static local_iterator<T> nonconst_hlp(const_local_iterator<T>);
- static base_segment_info_iterator nonconst_hlp(
- const_base_segment_info_iterator);
- template<typename Iterator>
- using nonconst_version=decltype(nonconst_hlp(std::declval<Iterator>()));
- public:
- class const_segment_traversal_info
- {
- public:
- const_segment_traversal_info(const const_segment_traversal_info&)=default;
- const_segment_traversal_info& operator=(
- const const_segment_traversal_info&)=default;
-
- const_base_segment_info_iterator begin()const noexcept
- {return pmap->cbegin();}
- const_base_segment_info_iterator end()const noexcept{return pmap->cend();}
- const_base_segment_info_iterator cbegin()const noexcept{return begin();}
- const_base_segment_info_iterator cend()const noexcept{return end();}
- protected:
- friend class poly_collection;
- const_segment_traversal_info(const segment_map& map)noexcept:
- pmap{const_cast<segment_map*>(&map)}{}
- segment_map* pmap;
- };
- class segment_traversal_info:public const_segment_traversal_info
- {
- public:
- segment_traversal_info(const segment_traversal_info&)=default;
- segment_traversal_info& operator=(const segment_traversal_info&)=default;
- using const_segment_traversal_info::begin;
- using const_segment_traversal_info::end;
- base_segment_info_iterator begin()noexcept{return this->pmap->cbegin();}
- base_segment_info_iterator end()noexcept{return this->pmap->cend();}
- private:
- friend class poly_collection;
- using const_segment_traversal_info::const_segment_traversal_info;
- };
- /* construct/destroy/copy */
- poly_collection()=default;
- poly_collection(const poly_collection&)=default;
- poly_collection(poly_collection&&)=default;
- explicit poly_collection(const allocator_type& al):
- map{segment_map_allocator_type{al}}{}
- poly_collection(const poly_collection& x,const allocator_type& al):
- map{x.map,segment_map_allocator_type{al}}{}
- poly_collection(poly_collection&& x,const allocator_type& al):
- map{std::move(x.map),segment_map_allocator_type{al}}{}
- template<typename InputIterator>
- poly_collection(
- InputIterator first,InputIterator last,
- const allocator_type& al=allocator_type{}):
- map{segment_map_allocator_type{al}}
- {
- this->insert(first,last);
- }
- // TODO: what to do with initializer_list?
- poly_collection& operator=(const poly_collection&)=default;
- poly_collection& operator=(poly_collection&&)=default;
- allocator_type get_allocator()const noexcept{return map.get_allocator();}
- /* type registration */
- template<
- typename... T,
- for_all<enable_if_acceptable<T>...> =nullptr
- >
- void register_types()
- {
- /* http://twitter.com/SeanParent/status/558765089294020609 */
- using seq=int[1+sizeof...(T)];
- (void)seq{
- 0,
- (map.insert(
- typeid(T),segment_type::template make<T>(get_allocator())),0)...
- };
- }
- bool is_registered(const std::type_info& info)const
- {
- return map.find(info)!=map.end();
- }
- template<typename T,enable_if_acceptable<T> =nullptr>
- bool is_registered()const
- {
- return is_registered(typeid(T));
- }
- /* iterators */
- iterator begin()noexcept{return {map.begin(),map.end()};}
- iterator end()noexcept{return {map.end(),map.end()};}
- const_iterator begin()const noexcept{return {map.begin(),map.end()};}
- const_iterator end()const noexcept{return {map.end(),map.end()};}
- const_iterator cbegin()const noexcept{return begin();}
- const_iterator cend()const noexcept{return end();}
- local_base_iterator begin(const std::type_info& info)
- {
- auto it=get_map_iterator_for(info);
- return {it,segment(it).begin()};
- }
- local_base_iterator end(const std::type_info& info)
- {
- auto it=get_map_iterator_for(info);
- return {it,segment(it).end()};
- }
- const_local_base_iterator begin(const std::type_info& info)const
- {
- auto it=get_map_iterator_for(info);
- return {it,segment(it).begin()};
- }
- const_local_base_iterator end(const std::type_info& info)const
- {
- auto it=get_map_iterator_for(info);
- return {it,segment(it).end()};
- }
- const_local_base_iterator cbegin(const std::type_info& info)const
- {return begin(info);}
- const_local_base_iterator cend(const std::type_info& info)const
- {return end(info);}
- template<typename T,enable_if_acceptable<T> =nullptr>
- local_iterator<T> begin()
- {
- auto it=get_map_iterator_for(typeid(T));
- return {it,segment(it).template begin<T>()};
- }
- template<typename T,enable_if_acceptable<T> =nullptr>
- local_iterator<T> end()
- {
- auto it=get_map_iterator_for(typeid(T));
- return {it,segment(it).template end<T>()};
- }
- template<typename T,enable_if_acceptable<T> =nullptr>
- const_local_iterator<T> begin()const
- {
- auto it=get_map_iterator_for(typeid(T));
- return {it,segment(it).template begin<T>()};
- }
- template<typename T,enable_if_acceptable<T> =nullptr>
- const_local_iterator<T> end()const
- {
- auto it=get_map_iterator_for(typeid(T));
- return {it,segment(it).template end<T>()};
- }
- template<typename T,enable_if_acceptable<T> =nullptr>
- const_local_iterator<T> cbegin()const{return begin<T>();}
- template<typename T,enable_if_acceptable<T> =nullptr>
- const_local_iterator<T> cend()const{return end<T>();}
- base_segment_info segment(const std::type_info& info)
- {
- return get_map_iterator_for(info);
- }
- const_base_segment_info segment(const std::type_info& info)const
- {
- return get_map_iterator_for(info);
- }
- template<typename T,enable_if_acceptable<T> =nullptr>
- segment_info<T> segment(){return get_map_iterator_for(typeid(T));}
- template<typename T,enable_if_acceptable<T> =nullptr>
- const_segment_info<T> segment()const{return get_map_iterator_for(typeid(T));}
- segment_traversal_info segment_traversal()noexcept{return map;}
- const_segment_traversal_info segment_traversal()const noexcept{return map;}
- /* capacity */
- bool empty()const noexcept
- {
- for(const auto& x:map)if(!x.second.empty())return false;
- return true;
- }
- bool empty(const std::type_info& info)const
- {
- return segment(get_map_iterator_for(info)).empty();
- }
- template<typename T,enable_if_acceptable<T> =nullptr>
- bool empty()const
- {
- return segment(get_map_iterator_for(typeid(T))).template empty<T>();
- }
- size_type size()const noexcept
- {
- size_type res=0;
- for(const auto& x:map)res+=x.second.size();
- return res;
- }
- size_type size(const std::type_info& info)const
- {
- return segment(get_map_iterator_for(info)).size();
- }
- template<typename T,enable_if_acceptable<T> =nullptr>
- size_type size()const
- {
- return segment(get_map_iterator_for(typeid(T))).template size<T>();
- }
- size_type max_size(const std::type_info& info)const
- {
- return segment(get_map_iterator_for(info)).max_size();
- }
- template<typename T,enable_if_acceptable<T> =nullptr>
- size_type max_size()const
- {
- return segment(get_map_iterator_for(typeid(T))).template max_size<T>();
- }
- size_type capacity(const std::type_info& info)const
- {
- return segment(get_map_iterator_for(info)).capacity();
- }
- template<typename T,enable_if_acceptable<T> =nullptr>
- size_type capacity()const
- {
- return segment(get_map_iterator_for(typeid(T))).template capacity<T>();
- }
- void reserve(size_type n)
- {
- for(auto& x:map)x.second.reserve(n);
- }
- void reserve(const std::type_info& info,size_type n)
- {
- segment(get_map_iterator_for(info)).reserve(n);
- }
- template<typename T,enable_if_acceptable<T> =nullptr>
- void reserve(size_type n)
- {
- /* note this creates the segment if it didn't previously exist */
- segment(get_map_iterator_for<T>()).template reserve<T>(n);
- }
- void shrink_to_fit()
- {
- for(auto& x:map)x.second.shrink_to_fit();
- }
- void shrink_to_fit(const std::type_info& info)
- {
- segment(get_map_iterator_for(info)).shrink_to_fit();
- }
- template<typename T,enable_if_acceptable<T> =nullptr>
- void shrink_to_fit()
- {
- segment(get_map_iterator_for(typeid(T))).template shrink_to_fit<T>();
- }
- /* modifiers */
- template<typename T,typename... Args,enable_if_acceptable<T> =nullptr>
- iterator emplace(Args&&... args)
- {
- auto it=get_map_iterator_for<T>();
- return {
- it,map.end(),
- segment(it).template emplace_back<T>(std::forward<Args>(args)...)
- };
- }
- template<typename T,typename... Args,enable_if_acceptable<T> =nullptr>
- iterator emplace_hint(const_iterator hint,Args&&... args)
- {
- auto it=get_map_iterator_for<T>();
- return {
- it,map.end(),
- hint.mapit==it? /* hint in segment */
- segment(it).template emplace<T>(
- hint.segpos,std::forward<Args>(args)...):
- segment(it).template emplace_back<T>(std::forward<Args>(args)...)
- };
- }
- template<typename T,typename... Args,enable_if_acceptable<T> =nullptr>
- local_base_iterator
- emplace_pos(local_base_iterator pos,Args&&... args)
- {
- return emplace_pos<T>(
- const_local_base_iterator{pos},std::forward<Args>(args)...);
- }
- template<typename T,typename... Args,enable_if_acceptable<T> =nullptr>
- local_base_iterator
- emplace_pos(const_local_base_iterator pos,Args&&... args)
- {
- BOOST_ASSERT(pos.type_info()==typeid(T));
- return {
- pos.mapit,
- pos.segment().template emplace<T>(pos.base(),std::forward<Args>(args)...)
- };
- }
- template<typename T,typename... Args>
- local_iterator<T>
- emplace_pos(local_iterator<T> pos,Args&&... args)
- {
- return emplace_pos(
- const_local_iterator<T>{pos},std::forward<Args>(args)...);
- }
- template<typename T,typename... Args>
- local_iterator<T>
- emplace_pos(const_local_iterator<T> pos,Args&&... args)
- {
- return {
- pos.mapit,
- pos.segment().template emplace<T>(pos.base(),std::forward<Args>(args)...)
- };
- }
- template<typename T,enable_if_implementation<T> =nullptr>
- iterator insert(T&& x)
- {
- auto it=get_map_iterator_for(x);
- return {it,map.end(),push_back(segment(it),std::forward<T>(x))};
- }
- template<
- typename T,
- enable_if_not_same<const_iterator,T> =nullptr,
- enable_if_implementation<T> =nullptr
- >
- iterator insert(const_iterator hint,T&& x)
- {
- auto it=get_map_iterator_for(x);
- return {
- it,map.end(),
- hint.mapit==it? /* hint in segment */
- segment(it).insert(hint.segpos,std::forward<T>(x)):
- push_back(segment(it),std::forward<T>(x))
- };
- }
- template<
- typename BaseIterator,typename T,
- enable_if_not_same<local_iterator_impl<BaseIterator>,T> =nullptr,
- enable_if_implementation<T> =nullptr
- >
- nonconst_version<local_iterator_impl<BaseIterator>>
- insert(local_iterator_impl<BaseIterator> pos,T&& x)
- {
- BOOST_ASSERT(pos.type_info()==subtypeid(x));
- return {
- pos.mapit,
- pos.segment().insert(pos.base(),std::forward<T>(x))
- };
- }
- template<
- typename InputIterator,
- enable_if_derefs_to_implementation<InputIterator> =nullptr,
- enable_if_derefs_to_not_terminal<InputIterator> =nullptr
- >
- void insert(InputIterator first,InputIterator last)
- {
- for(;first!=last;++first)insert(*first);
- }
- template<
- typename InputIterator,
- enable_if_derefs_to_implementation<InputIterator> =nullptr,
- enable_if_derefs_to_terminal<InputIterator> =nullptr
- >
- void insert(InputIterator first,InputIterator last)
- {
- if(first==last)return;
- /* same segment for all (type is terminal) */
- auto& seg=segment(get_map_iterator_for(*first));
- seg.insert(first,last);
- }
- template<bool Const>
- void insert(iterator_impl<Const> first,iterator_impl<Const> last)
- {
- for(;first!=last;++first){
- auto& seg=segment(get_map_iterator_for(*first,first.segment()));
- push_back(seg,*first);
- }
- }
- template<typename BaseIterator>
- void insert(
- local_iterator_impl<BaseIterator> first,
- local_iterator_impl<BaseIterator> last)
- {
- if(first==last)return;
- /* same segment for all (iterator is local) */
- auto& seg=segment(get_map_iterator_for(*first,first.segment()));
- do seg.push_back(*first); while(++first!=last);
- }
- template<
- typename InputIterator,
- enable_if_derefs_to_implementation<InputIterator> =nullptr,
- enable_if_derefs_to_not_terminal<InputIterator> =nullptr
- >
- void insert(const_iterator hint,InputIterator first,InputIterator last)
- {
- for(;first!=last;++first){
- auto it=get_map_iterator_for(*first);
- if(hint.mapit==it){ /* hint in segment */
- hint={it,map.end(),segment(it).insert(hint.segpos,*first)};
- ++hint;
- }
- else push_back(segment(it),*first);
- }
- }
- template<
- typename InputIterator,
- enable_if_derefs_to_implementation<InputIterator> =nullptr,
- enable_if_derefs_to_terminal<InputIterator> =nullptr
- >
- void insert(const_iterator hint,InputIterator first,InputIterator last)
- {
- if(first==last)return;
- /* same segment for all (type is terminal) */
- auto it=get_map_iterator_for(*first);
- auto& seg=segment(it);
- if(hint.mapit==it)seg.insert(hint.segpos,first,last); /* hint in segment */
- else seg.insert(first,last);
- }
- template<bool Const>
- void insert(
- const_iterator hint,iterator_impl<Const> first,iterator_impl<Const> last)
- {
- for(;first!=last;++first){
- auto it=get_map_iterator_for(*first,first.segment());
- if(hint.mapit==it){ /* hint in segment */
- hint={it,map.end(),segment(it).insert(hint.segpos,*first)};
- ++hint;
- }
- else push_back(segment(it),*first);
- }
- }
- template<typename BaseIterator>
- void insert(
- const_iterator hint,
- local_iterator_impl<BaseIterator> first,
- local_iterator_impl<BaseIterator> last)
- {
- if(first==last)return;
- /* same segment for all (iterator is local) */
- auto it=get_map_iterator_for(*first,first.segment());
- auto& seg=segment(it);
- if(hint.mapit==it){ /* hint in segment */
- do{
- hint={it,map.end(),seg.insert(hint.segpos,*first)};
- ++hint;
- }while(++first!=last);
- }
- else{
- do push_back(seg,*first); while(++first!=last);
- }
- }
- template<
- typename InputIterator,
- enable_if_derefs_to_implementation<InputIterator> =nullptr
- >
- local_base_iterator insert(
- const_local_base_iterator pos,InputIterator first,InputIterator last)
- {
- auto& seg=pos.segment();
- auto it=Model::nonconst_iterator(pos.base());
- size_type n=0;
- for(;first!=last;++first){
- BOOST_ASSERT(pos.type_info()==subtypeid(*first));
- it=std::next(seg.insert(it,*first));
- ++n;
- }
- return {pos.mapit,it-n};
- }
- template<typename T,typename InputIterator>
- local_iterator<T> insert(
- const_local_iterator<T> pos,InputIterator first,InputIterator last)
- {
- auto& seg=pos.segment();
- segment_iterator<T> it=Model::nonconst_iterator(pos.base());
- size_type n=0;
- for(;first!=last;++first){
- it=std::next(
- static_cast<segment_iterator<T>>(local_insert<T>(seg,it,*first)));
- ++n;
- }
- return {pos.mapit,it-n};
- }
- template<typename T,typename InputIterator>
- local_iterator<T> insert(
- local_iterator<T> pos,InputIterator first,InputIterator last)
- {
- return insert(const_local_iterator<T>{pos},first,last);
- }
- iterator erase(const_iterator pos)
- {
- return {pos.mapit,pos.mapend,pos.segment().erase(pos.segpos)};
- }
- template<typename BaseIterator>
- nonconst_version<local_iterator_impl<BaseIterator>>
- erase(local_iterator_impl<BaseIterator> pos)
- {
- return {pos.mapit,pos.segment().erase(pos.base())};
- }
- iterator erase(const_iterator first, const_iterator last)
- {
- const_segment_map_iterator fseg=first.mapit,
- lseg=last.mapit,
- end=first.mapend;
- if(fseg!=lseg){ /* [first,last] spans over more than one segment */
- /* from 1st elem to end of 1st segment */
- segment(fseg).erase_till_end(first.segpos);
- /* entire segments till last one */
- while(++fseg!=lseg)segment(fseg).clear();
- /* remaining elements of last segment */
- if(fseg==end){ /* except if at end of container */
- return {end,end};
- }
- else{
- return {fseg,end,segment(fseg).erase_from_begin(last.segpos)};
- }
- }
- else{ /* range is included in one segment only */
- if(first==last){ /* to avoid segment(fseg) when fseg==end */
- return {fseg,end,first.segpos};
- }
- else{
- return {fseg,end,segment(fseg).erase(first.segpos,last.segpos)};
- }
- }
- }
- template<typename BaseIterator>
- nonconst_version<local_iterator_impl<BaseIterator>>
- erase(
- local_iterator_impl<BaseIterator> first,
- local_iterator_impl<BaseIterator> last)
- {
- BOOST_ASSERT(first.mapit==last.mapit);
- return{
- first.mapit,
- first.segment().erase(first.base(),last.base())
- };
- }
- void clear()noexcept
- {
- for(auto& x:map)x.second.clear();
- }
- void clear(const std::type_info& info)
- {
- segment(get_map_iterator_for(info)).clear();
- }
- template<typename T,enable_if_acceptable<T> =nullptr>
- void clear()
- {
- segment(get_map_iterator_for(typeid(T))).template clear<T>();
- }
- void swap(poly_collection& x){map.swap(x.map);}
- private:
- template<typename M,typename A>
- friend bool operator==(
- const poly_collection<M,A>&,const poly_collection<M,A>&);
- template<
- typename T,
- enable_if_acceptable<T> =nullptr,
- enable_if_not_terminal<T> =nullptr
- >
- const_segment_map_iterator get_map_iterator_for(const T& x)
- {
- const auto& id=subtypeid(x);
- auto it=map.find(id);
- if(it!=map.end())return it;
- else if(id!=typeid(T))throw unregistered_type{id};
- else return map.insert(
- typeid(T),segment_type::template make<T>(get_allocator())).first;
- }
- template<
- typename T,
- enable_if_acceptable<T> =nullptr,
- enable_if_terminal<T> =nullptr
- >
- const_segment_map_iterator get_map_iterator_for(const T&)
- {
- auto it=map.find(typeid(T));
- if(it!=map.end())return it;
- else return map.insert(
- typeid(T),segment_type::template make<T>(get_allocator())).first;
- }
- template<
- typename T,
- enable_if_not_acceptable<T> =nullptr,
- enable_if_not_terminal<T> =nullptr
- >
- const_segment_map_iterator get_map_iterator_for(const T& x)const
- {
- const auto& id=subtypeid(x);
- auto it=map.find(id);
- if(it!=map.end())return it;
- else throw unregistered_type{id};
- }
- template<
- typename T,
- enable_if_not_acceptable<T> =nullptr,
- enable_if_terminal<T> =nullptr
- >
- const_segment_map_iterator get_map_iterator_for(const T&)const
- {
- static_assert(
- is_acceptable<T>::value,
- "type must be move constructible and move assignable");
- return {}; /* never executed */
- }
- template<typename T>
- const_segment_map_iterator get_map_iterator_for(
- const T& x,const segment_type& seg)
- {
- const auto& id=subtypeid(x);
- auto it=map.find(id);
- if(it!=map.end())return it;
- else return map.insert(
- id,segment_type::make_from_prototype(seg,get_allocator())).first;
- }
- template<typename T>
- const_segment_map_iterator get_map_iterator_for()
- {
- auto it=map.find(typeid(T));
- if(it!=map.end())return it;
- else return map.insert(
- typeid(T),segment_type::template make<T>(get_allocator())).first;
- }
- const_segment_map_iterator get_map_iterator_for(const std::type_info& info)
- {
- return const_cast<const poly_collection*>(this)->
- get_map_iterator_for(info);
- }
- const_segment_map_iterator get_map_iterator_for(
- const std::type_info& info)const
- {
- auto it=map.find(info);
- if(it!=map.end())return it;
- else throw unregistered_type{info};
- }
- static segment_type& segment(const_segment_map_iterator pos)
- {
- return const_cast<segment_type&>(pos->second);
- }
- template<
- typename T,
- enable_if_not_acceptable<T> =nullptr
- >
- segment_base_iterator push_back(segment_type& seg,T&& x)
- {
- return seg.push_back(std::forward<T>(x));
- }
- template<
- typename T,
- enable_if_acceptable<T> =nullptr,
- enable_if_not_terminal<T> =nullptr
- >
- segment_base_iterator push_back(segment_type& seg,T&& x)
- {
- return subtypeid(x)==typeid(T)?
- seg.push_back_terminal(std::forward<T>(x)):
- seg.push_back(std::forward<T>(x));
- }
- template<
- typename T,
- enable_if_acceptable<T> =nullptr,
- enable_if_terminal<T> =nullptr
- >
- segment_base_iterator push_back(segment_type& seg,T&& x)
- {
- return seg.push_back_terminal(std::forward<T>(x));
- }
- template<
- typename T,typename BaseIterator,typename U,
- enable_if_implementation<U> =nullptr,
- enable_if_not_constructible<T,U&&> =nullptr
- >
- static segment_base_iterator local_insert(
- segment_type& seg,BaseIterator pos,U&& x)
- {
- BOOST_ASSERT(subtypeid(x)==typeid(T));
- return seg.insert(pos,std::forward<U>(x));
- }
- template<
- typename T,typename BaseIterator,typename U,
- enable_if_implementation<U> =nullptr,
- enable_if_constructible<T,U&&> =nullptr
- >
- static segment_base_iterator local_insert(
- segment_type& seg,BaseIterator pos,U&& x)
- {
- if(subtypeid(x)==typeid(T))return seg.insert(pos,std::forward<U>(x));
- else return seg.template emplace<T>(pos,std::forward<U>(x));
- }
- template<
- typename T,typename BaseIterator,typename U,
- enable_if_not_implementation<U> =nullptr,
- enable_if_constructible<T,U&&> =nullptr
- >
- static segment_base_iterator local_insert(
- segment_type& seg,BaseIterator pos,U&& x)
- {
- return seg.template emplace<T>(pos,std::forward<U>(x));
- }
- template<
- typename T,typename BaseIterator,typename U,
- enable_if_not_implementation<U> =nullptr,
- enable_if_not_constructible<T,U&&> =nullptr
- >
- static segment_base_iterator local_insert(
- segment_type&,BaseIterator,U&&)
- {
- static_assert(
- is_constructible<T,U&&>::value,
- "element must be constructible from type");
- return {}; /* never executed */
- }
- segment_map map;
- };
- template<typename Model,typename Allocator>
- bool operator==(
- const poly_collection<Model,Allocator>& x,
- const poly_collection<Model,Allocator>& y)
- {
- typename poly_collection<Model,Allocator>::size_type s=0;
- const auto &mapx=x.map,&mapy=y.map;
- for(const auto& p:mapx){
- auto ss=p.second.size();
- auto it=mapy.find(*p.first);
- if(it==mapy.end()?ss!=0:p.second!=it->second)return false;
- s+=ss;
- }
- return s==y.size();
- }
- template<typename Model,typename Allocator>
- bool operator!=(
- const poly_collection<Model,Allocator>& x,
- const poly_collection<Model,Allocator>& y)
- {
- return !(x==y);
- }
- template<typename Model,typename Allocator>
- void swap(
- poly_collection<Model,Allocator>& x,poly_collection<Model,Allocator>& y)
- {
- x.swap(y);
- }
- } /* namespace poly_collection::common_impl */
- } /* namespace poly_collection */
- } /* namespace boost */
- #endif
|