/* 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