/usr/include/boost/poly_collection/detail
Edit: /usr/include/boost/poly_collection/detail/poly_collection.hpp (34291B)
/* 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
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
namespace boost{
namespace poly_collection{
namespace common_impl{
/* common implementation for all polymorphic collections */
using namespace detail;
template
class poly_collection
{
template
static const std::type_info& subtypeid(const T& x)
{return Model::subtypeid(x);}
template
struct for_all_types{using type=void*;};
template
using for_all=typename for_all_types::type;
template
struct is_implementation: /* using makes VS2015 choke, hence we derive */
Model::template is_implementation::type>{};
template
using enable_if_implementation=
typename std::enable_if::value>::type*;
template
using enable_if_not_implementation=
typename std::enable_if::value>::type*;
template
using is_acceptable=
detail::is_acceptable::type,Model>;
template
using enable_if_acceptable=
typename std::enable_if::value>::type*;
template
using enable_if_not_acceptable=
typename std::enable_if::value>::type*;
template
using enable_if_derefs_to_implementation=enable_if_implementation<
typename std::iterator_traits::value_type
>;
template
using is_terminal=
typename Model::template is_terminal::type>;
template
using enable_if_terminal=
typename std::enable_if::value>::type*;
template
using enable_if_not_terminal=
typename std::enable_if::value>::type*;
template
using derefs_to_terminal=is_terminal<
typename std::iterator_traits::value_type
>;
template
using enable_if_derefs_to_terminal=
typename std::enable_if::value>::type*;
template
using enable_if_derefs_to_not_terminal=
typename std::enable_if::value>::type*;
template
using enable_if_not_same=typename std::enable_if<
!std::is_same<
typename std::decay::type,typename std::decay::type
>::value
>::type*;
template
using enable_if_constructible=
typename std::enable_if::value>::type*;
template
using enable_if_not_constructible=
typename std::enable_if::value>::type*;
using segment_allocator_type=allocator_adaptor;
using segment_type=detail::segment;
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
using segment_iterator=typename segment_type::template iterator;
template
using const_segment_iterator=
typename segment_type::template const_iterator;
using segment_map=type_info_map<
segment_type,
typename std::allocator_traits::template
rebind_alloc
>;
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::pointer;
using const_pointer=typename std::allocator_traits::const_pointer;
private:
template
friend class detail::iterator_impl;
template
friend class detail::local_iterator_impl;
template
using iterator_impl=detail::iterator_impl;
template
using local_iterator_impl=
detail::local_iterator_impl;
public:
using iterator=iterator_impl;
using const_iterator=iterator_impl;
using local_base_iterator=local_iterator_impl;
using const_local_base_iterator=
local_iterator_impl;
template
using local_iterator=local_iterator_impl>;
template
using const_local_iterator=local_iterator_impl>;
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
const_local_iterator begin()const noexcept
{return const_local_iterator{begin()};}
template
const_local_iterator end()const noexcept
{return const_local_iterator{end()};}
template
const_local_iterator cbegin()const noexcept{return begin();}
template
const_local_iterator cend()const noexcept{return end();}
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
local_iterator begin()noexcept{return local_iterator{begin()};}
template
local_iterator end()noexcept{return local_iterator{end()};}
private:
friend class poly_collection;
using const_base_segment_info::const_base_segment_info;
};
template
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 begin()const noexcept
{return {it,it->second.begin()};}
const_local_iterator end()const noexcept
{return {it,it->second.end()};}
const_local_iterator cbegin()const noexcept{return begin();}
const_local_iterator 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
class segment_info:public const_segment_info
{
public:
segment_info(const segment_info&)=default;
segment_info& operator=(const segment_info&)=default;
using const_segment_info::begin;
using const_segment_info::end;
local_iterator begin()noexcept
{return {this->it,this->it->second.begin()};}
local_iterator end()noexcept
{return {this->it,this->it->second.end()};}
private:
friend class poly_collection;
using const_segment_info::const_segment_info;
};
private:
template
class segment_info_iterator_impl:
public boost::iterator_adaptor<
segment_info_iterator_impl,
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::value
>::type* =nullptr
>
segment_info_iterator_impl(
const segment_info_iterator_impl& x):
segment_info_iterator_impl::iterator_adaptor_{x.base()}{}
template<
typename SegmentInfo2,
typename std::enable_if<
std::is_base_of::value
>::type* =nullptr
>
segment_info_iterator_impl& operator=(
const segment_info_iterator_impl& x)
{
this->base_reference()=x.base();
return *this;
}
private:
template
friend class segment_info_iterator_impl;
friend class poly_collection;
friend class boost::iterator_core_access;
template
friend struct detail::iterator_traits;
SegmentInfo dereference()const noexcept{return this->base();}
};
public:
using base_segment_info_iterator=
segment_info_iterator_impl;
using const_base_segment_info_iterator=
segment_info_iterator_impl;
private:
template
static Iterator nonconst_hlp(Iterator);
static iterator nonconst_hlp(const_iterator);
static local_base_iterator nonconst_hlp(const_local_base_iterator);
template
static local_iterator nonconst_hlp(const_local_iterator);
static base_segment_info_iterator nonconst_hlp(
const_base_segment_info_iterator);
template
using nonconst_version=decltype(nonconst_hlp(std::declval()));
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(&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
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...> =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(get_allocator())),0)...
};
}
bool is_registered(const std::type_info& info)const
{
return map.find(info)!=map.end();
}
template =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 =nullptr>
local_iterator begin()
{
auto it=get_map_iterator_for(typeid(T));
return {it,segment(it).template begin()};
}
template =nullptr>
local_iterator end()
{
auto it=get_map_iterator_for(typeid(T));
return {it,segment(it).template end()};
}
template =nullptr>
const_local_iterator begin()const
{
auto it=get_map_iterator_for(typeid(T));
return {it,segment(it).template begin()};
}
template =nullptr>
const_local_iterator end()const
{
auto it=get_map_iterator_for(typeid(T));
return {it,segment(it).template end()};
}
template =nullptr>
const_local_iterator cbegin()const{return begin();}
template =nullptr>
const_local_iterator cend()const{return end();}
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 =nullptr>
segment_info segment(){return get_map_iterator_for(typeid(T));}
template =nullptr>
const_segment_info 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 =nullptr>
bool empty()const
{
return segment(get_map_iterator_for(typeid(T))).template empty();
}
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 =nullptr>
size_type size()const
{
return segment(get_map_iterator_for(typeid(T))).template size();
}
size_type max_size(const std::type_info& info)const
{
return segment(get_map_iterator_for(info)).max_size();
}
template =nullptr>
size_type max_size()const
{
return segment(get_map_iterator_for(typeid(T))).template max_size();
}
size_type capacity(const std::type_info& info)const
{
return segment(get_map_iterator_for(info)).capacity();
}
template =nullptr>
size_type capacity()const
{
return segment(get_map_iterator_for(typeid(T))).template capacity();
}
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 =nullptr>
void reserve(size_type n)
{
/* note this creates the segment if it didn't previously exist */
segment(get_map_iterator_for()).template reserve(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 =nullptr>
void shrink_to_fit()
{
segment(get_map_iterator_for(typeid(T))).template shrink_to_fit();
}
/* modifiers */
template =nullptr>
iterator emplace(Args&&... args)
{
auto it=get_map_iterator_for();
return {
it,map.end(),
segment(it).template emplace_back(std::forward(args)...)
};
}
template =nullptr>
iterator emplace_hint(const_iterator hint,Args&&... args)
{
auto it=get_map_iterator_for();
return {
it,map.end(),
hint.mapit==it? /* hint in segment */
segment(it).template emplace(
hint.segpos,std::forward(args)...):
segment(it).template emplace_back(std::forward(args)...)
};
}
template =nullptr>
local_base_iterator
emplace_pos(local_base_iterator pos,Args&&... args)
{
return emplace_pos(
const_local_base_iterator{pos},std::forward(args)...);
}
template =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(pos.base(),std::forward(args)...)
};
}
template
local_iterator
emplace_pos(local_iterator pos,Args&&... args)
{
return emplace_pos(
const_local_iterator{pos},std::forward(args)...);
}
template
local_iterator
emplace_pos(const_local_iterator pos,Args&&... args)
{
return {
pos.mapit,
pos.segment().template emplace(pos.base(),std::forward(args)...)
};
}
template =nullptr>
iterator insert(T&& x)
{
auto it=get_map_iterator_for(x);
return {it,map.end(),push_back(segment(it),std::forward(x))};
}
template<
typename T,
enable_if_not_same =nullptr,
enable_if_implementation =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(x)):
push_back(segment(it),std::forward(x))
};
}
template<
typename BaseIterator,typename T,
enable_if_not_same,T> =nullptr,
enable_if_implementation =nullptr
>
nonconst_version>
insert(local_iterator_impl pos,T&& x)
{
BOOST_ASSERT(pos.type_info()==subtypeid(x));
return {
pos.mapit,
pos.segment().insert(pos.base(),std::forward(x))
};
}
template<
typename InputIterator,
enable_if_derefs_to_implementation =nullptr,
enable_if_derefs_to_not_terminal =nullptr
>
void insert(InputIterator first,InputIterator last)
{
for(;first!=last;++first)insert(*first);
}
template<
typename InputIterator,
enable_if_derefs_to_implementation =nullptr,
enable_if_derefs_to_terminal =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
void insert(iterator_impl first,iterator_impl last)
{
for(;first!=last;++first){
auto& seg=segment(get_map_iterator_for(*first,first.segment()));
push_back(seg,*first);
}
}
template
void insert(
local_iterator_impl first,
local_iterator_impl 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 =nullptr,
enable_if_derefs_to_not_terminal =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 =nullptr,
enable_if_derefs_to_terminal =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
void insert(
const_iterator hint,iterator_impl first,iterator_impl 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
void insert(
const_iterator hint,
local_iterator_impl first,
local_iterator_impl 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 =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
local_iterator insert(
const_local_iterator pos,InputIterator first,InputIterator last)
{
auto& seg=pos.segment();
segment_iterator it=Model::nonconst_iterator(pos.base());
size_type n=0;
for(;first!=last;++first){
it=std::next(
static_cast>(local_insert(seg,it,*first)));
++n;
}
return {pos.mapit,it-n};
}
template
local_iterator insert(
local_iterator pos,InputIterator first,InputIterator last)
{
return insert(const_local_iterator{pos},first,last);
}
iterator erase(const_iterator pos)
{
return {pos.mapit,pos.mapend,pos.segment().erase(pos.segpos)};
}
template
nonconst_version>
erase(local_iterator_impl 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
nonconst_version>
erase(
local_iterator_impl first,
local_iterator_impl 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 =nullptr>
void clear()
{
segment(get_map_iterator_for(typeid(T))).template clear();
}
void swap(poly_collection& x){map.swap(x.map);}
private:
template
friend bool operator==(
const poly_collection&,const poly_collection&);
template<
typename T,
enable_if_acceptable =nullptr,
enable_if_not_terminal =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(get_allocator())).first;
}
template<
typename T,
enable_if_acceptable =nullptr,
enable_if_terminal =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(get_allocator())).first;
}
template<
typename T,
enable_if_not_acceptable =nullptr,
enable_if_not_terminal =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 =nullptr,
enable_if_terminal =nullptr
>
const_segment_map_iterator get_map_iterator_for(const T&)const
{
static_assert(
is_acceptable::value,
"type must be move constructible and move assignable");
return {}; /* never executed */
}
template
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
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(get_allocator())).first;
}
const_segment_map_iterator get_map_iterator_for(const std::type_info& info)
{
return const_cast(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