feat():initial version

This commit is contained in:
2026-06-09 20:16:47 +08:00
commit 85fbb3188c
14809 changed files with 3044607 additions and 0 deletions

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,78 @@
/* Copyright 2016-2017 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_ANY_COLLECTION_HPP
#define BOOST_POLY_COLLECTION_ANY_COLLECTION_HPP
#if defined(_MSC_VER)
#pragma once
#endif
#include <boost/poly_collection/any_collection_fwd.hpp>
#include <boost/poly_collection/detail/any_model.hpp>
#include <boost/poly_collection/detail/poly_collection.hpp>
#include <utility>
namespace boost{
namespace poly_collection{
template<typename Concept,typename Allocator>
class any_collection:
public common_impl::poly_collection<detail::any_model<Concept>,Allocator>
{
using base_type=common_impl::poly_collection<
detail::any_model<Concept>,Allocator>;
base_type& base()noexcept{return *this;}
const base_type& base()const noexcept{return *this;}
public:
using base_type::base_type;
any_collection()=default;
any_collection(const any_collection& x)=default;
any_collection(any_collection&& x)=default;
any_collection& operator=(const any_collection& x)=default;
any_collection& operator=(any_collection&& x)=default;
template<typename C,typename A>
friend bool operator==(
const any_collection<C,A>&,const any_collection<C,A>&);
};
template<typename Concept,typename Allocator>
bool operator==(
const any_collection<Concept,Allocator>& x,
const any_collection<Concept,Allocator>& y)
{
return x.base()==y.base();
}
template<typename Concept,typename Allocator>
bool operator!=(
const any_collection<Concept,Allocator>& x,
const any_collection<Concept,Allocator>& y)
{
return !(x==y);
}
template<typename Concept,typename Allocator>
void swap(
any_collection<Concept,Allocator>& x,any_collection<Concept,Allocator>& y)
{
x.swap(y);
}
} /* namespace */
using poly_collection::any_collection;
} /* namespace boost */
#endif

View File

@@ -0,0 +1,56 @@
/* Copyright 2016-2017 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_ANY_COLLECTION_FWD_HPP
#define BOOST_POLY_COLLECTION_ANY_COLLECTION_FWD_HPP
#if defined(_MSC_VER)
#pragma once
#endif
#include <memory>
namespace boost{
namespace poly_collection{
namespace detail{
template<typename Concept> struct any_model;
}
template<typename Concept>
using any_collection_value_type=
typename detail::any_model<Concept>::value_type;
template<
typename Concept,
typename Allocator=std::allocator<any_collection_value_type<Concept>>
>
class any_collection;
template<typename Concept,typename Allocator>
bool operator==(
const any_collection<Concept,Allocator>& x,
const any_collection<Concept,Allocator>& y);
template<typename Concept,typename Allocator>
bool operator!=(
const any_collection<Concept,Allocator>& x,
const any_collection<Concept,Allocator>& y);
template<typename Concept,typename Allocator>
void swap(
any_collection<Concept,Allocator>& x,any_collection<Concept,Allocator>& y);
} /* namespace poly_collection */
using poly_collection::any_collection;
} /* namespace boost */
#endif

View File

@@ -0,0 +1,78 @@
/* Copyright 2016-2017 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_BASE_COLLECTION_HPP
#define BOOST_POLY_COLLECTION_BASE_COLLECTION_HPP
#if defined(_MSC_VER)
#pragma once
#endif
#include <boost/poly_collection/base_collection_fwd.hpp>
#include <boost/poly_collection/detail/base_model.hpp>
#include <boost/poly_collection/detail/poly_collection.hpp>
#include <utility>
namespace boost{
namespace poly_collection{
template<typename Base,typename Allocator>
class base_collection:
public common_impl::poly_collection<detail::base_model<Base>,Allocator>
{
using base_type=common_impl::poly_collection<
detail::base_model<Base>,Allocator>;
base_type& base()noexcept{return *this;}
const base_type& base()const noexcept{return *this;}
public:
using base_type::base_type;
base_collection()=default;
base_collection(const base_collection& x)=default;
base_collection(base_collection&& x)=default;
base_collection& operator=(const base_collection& x)=default;
base_collection& operator=(base_collection&& x)=default;
template<typename B,typename A>
friend bool operator==(
const base_collection<B,A>&,const base_collection<B,A>&);
};
template<typename Base,typename Allocator>
bool operator==(
const base_collection<Base,Allocator>& x,
const base_collection<Base,Allocator>& y)
{
return x.base()==y.base();
}
template<typename Base,typename Allocator>
bool operator!=(
const base_collection<Base,Allocator>& x,
const base_collection<Base,Allocator>& y)
{
return !(x==y);
}
template<typename Base,typename Allocator>
void swap(
base_collection<Base,Allocator>& x,base_collection<Base,Allocator>& y)
{
x.swap(y);
}
} /* namespace */
using poly_collection::base_collection;
} /* namespace boost */
#endif

View File

@@ -0,0 +1,45 @@
/* Copyright 2016-2017 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_BASE_COLLECTION_FWD_HPP
#define BOOST_POLY_COLLECTION_BASE_COLLECTION_FWD_HPP
#if defined(_MSC_VER)
#pragma once
#endif
#include <memory>
namespace boost{
namespace poly_collection{
template<typename Base,typename Allocator=std::allocator<Base>>
class base_collection;
template<typename Base,typename Allocator>
bool operator==(
const base_collection<Base,Allocator>& x,
const base_collection<Base,Allocator>& y);
template<typename Base,typename Allocator>
bool operator!=(
const base_collection<Base,Allocator>& x,
const base_collection<Base,Allocator>& y);
template<typename Base,typename Allocator>
void swap(
base_collection<Base,Allocator>& x,base_collection<Base,Allocator>& y);
} /* namespace poly_collection */
using poly_collection::base_collection;
} /* namespace boost */
#endif

View File

@@ -0,0 +1,300 @@
/* Copyright 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_ALLOCATOR_ADAPTOR_HPP
#define BOOST_POLY_COLLECTION_DETAIL_ALLOCATOR_ADAPTOR_HPP
#if defined(_MSC_VER)
#pragma once
#endif
#include <boost/mp11/function.hpp>
#include <boost/mp11/integer_sequence.hpp>
#include <boost/poly_collection/detail/is_constructible.hpp>
#include <new>
#include <memory>
#include <tuple>
#include <type_traits>
#include <utility>
namespace boost{
namespace poly_collection{
namespace detail{
/* [container.requirements.general]/3 state that containers must use the
* allocator's construct/destroy member functions to construct/destroy
* elements and *not at all* for any other type. Since poly_collection is
* implemented as a multi-level structure of container and container-like
* objects, we need to use an adaptor for the user-provided Allocator that
* prevents intermediate entities from calling Allocator::[construct|destroy].
* allocator_adaptor<Allocator> does this by taking advantage of the fact that
* elements are ultimately held within a value_holder:
* - construct(value_holder<T>*,...) uses placement new construction and
* passes the wrapped Allocator object for value_holder<T> to use for
* its inner construction of T.
* - For the rest of types, construct uses placement new construction and
* passes down the adaptor object itself as an argument following an
* approach analogous to that of std::scoped_allocator_adaptor.
* - destroy(value_holder<T>) resorts to Allocator::destroy to destroy the
* contained T element.
* - For the rest of types, destroy(T) calls ~T directly.
*
* Code has been ripped and adapted from libc++'s implementation of
* std::scoped_allocator_adaptor.
*/
template<typename T>
class value_holder_base;
template<typename T>
class value_holder;
template<typename T,typename Allocator,typename... Args>
struct uses_alloc_ctor_impl
{
using RawAllocator=typename std::remove_cv<
typename std::remove_reference<Allocator>::type
>::type;
static const bool ua=std::uses_allocator<T,RawAllocator>::value;
static const int ic=is_constructible<
T,std::allocator_arg_t,Allocator,Args...>::value?1:0;
static const int value=ua?2-ic:0;
};
template<typename T,typename Allocator,typename... Args>
struct uses_alloc_ctor:
std::integral_constant<int,uses_alloc_ctor_impl<T,Allocator,Args...>::value>
{};
template<typename Allocator,typename=void>
struct allocator_is_always_equal:std::is_empty<Allocator>{};
template<typename Allocator>
struct allocator_is_always_equal<
Allocator,
mp11::mp_void<
typename std::allocator_traits<Allocator>::is_always_equal
>
>:std::allocator_traits<Allocator>::is_always_equal{};
template<typename Allocator>
struct allocator_adaptor:Allocator
{
using traits=std::allocator_traits<Allocator>;
using value_type=typename traits::value_type;
using size_type=typename traits::size_type;
using difference_type=typename traits::difference_type;
using pointer=typename traits::pointer;
using const_pointer=typename traits::const_pointer;
using void_pointer=typename traits::void_pointer;
using const_void_pointer=typename traits::const_void_pointer;
using propagate_on_container_copy_assignment=
typename traits::propagate_on_container_copy_assignment;
using propagate_on_container_move_assignment=
typename traits::propagate_on_container_move_assignment;
using propagate_on_container_swap=
typename traits::propagate_on_container_swap;
using is_always_equal=typename allocator_is_always_equal<Allocator>::type;
template<typename U>
struct rebind
{
using other=allocator_adaptor<typename traits::template rebind_alloc<U>>;
};
allocator_adaptor()=default;
allocator_adaptor(const allocator_adaptor&)=default;
template<
typename Allocator2,
typename std::enable_if<
is_constructible<Allocator,const Allocator2&>::value
>::type* =nullptr
>
allocator_adaptor(const Allocator2& x)noexcept:Allocator{x}{}
template<
typename Allocator2,
typename std::enable_if<
is_constructible<Allocator,const Allocator2&>::value
>::type* =nullptr
>
allocator_adaptor(const allocator_adaptor<Allocator2>& x)noexcept:
Allocator{x.allocator()}{}
allocator_adaptor& operator=(const allocator_adaptor&)=default;
Allocator& allocator()noexcept{return *this;}
const Allocator& allocator()const noexcept{return *this;}
template<typename T,typename... Args>
void construct(T* p,Args&&... args)
{
construct_(
uses_alloc_ctor<T,allocator_adaptor&,Args...>{},
p,std::forward<Args>(args)...);
}
template<typename T,typename... Args>
void construct(value_holder<T>* p,Args&&... args)
{
::new ((void*)p) value_holder<T>(allocator(),std::forward<Args>(args)...);
}
template<typename T1,typename T2,typename... Args1,typename... Args2>
void construct(
std::pair<T1,T2>* p,std::piecewise_construct_t,
std::tuple<Args1...> x,std::tuple<Args2...> y)
{
::new ((void*)p) std::pair<T1,T2>(
std::piecewise_construct,
transform_tuple(
uses_alloc_ctor<T1,allocator_adaptor&,Args1...>{},
std::move(x),
mp11::make_index_sequence<sizeof...(Args1)>{}),
transform_tuple(
uses_alloc_ctor<T2,allocator_adaptor&,Args2...>{},
std::move(y),
mp11::make_index_sequence<sizeof...(Args2)>{})
);
}
template<typename T1,typename T2>
void construct(std::pair<T1,T2>* p)
{
construct(p,std::piecewise_construct,std::tuple<>{},std::tuple<>{});
}
template<typename T1,typename T2,typename U,typename V>
void construct(std::pair<T1,T2>* p,U&& x,V&& y)
{
construct(
p,std::piecewise_construct,
std::forward_as_tuple(std::forward<U>(x)),
std::forward_as_tuple(std::forward<V>(y)));
}
template<typename T1,typename T2,typename U,typename V>
void construct(std::pair<T1,T2>* p,const std::pair<U,V>& x)
{
construct(
p,std::piecewise_construct,
std::forward_as_tuple(x.first),std::forward_as_tuple(x.second));
}
template<typename T1,typename T2,typename U,typename V>
void construct(std::pair<T1,T2>* p,std::pair<U,V>&& x)
{
construct(
p,std::piecewise_construct,
std::forward_as_tuple(std::forward<U>(x.first)),
std::forward_as_tuple(std::forward<V>(x.second)));
}
template<typename T>
void destroy(T* p)
{
p->~T();
}
template<typename T>
void destroy(value_holder<T>* p)
{
traits::destroy(
allocator(),
reinterpret_cast<T*>(static_cast<value_holder_base<T>*>(p)));
}
allocator_adaptor
select_on_container_copy_construction()const noexcept
{
return traits::select_on_container_copy_construction(allocator());
}
private:
template<typename T,typename... Args>
void construct_(
std::integral_constant<int,0>, /* doesn't use allocator */
T* p,Args&&... args)
{
::new ((void*)p) T(std::forward<Args>(args)...);
}
template<typename T,typename... Args>
void construct_(
std::integral_constant<int,1>, /* with std::allocator_arg */
T* p,Args&&... args)
{
::new ((void*)p) T(std::allocator_arg,*this,std::forward<Args>(args)...);
}
template<typename T,typename... Args>
void construct_(
std::integral_constant<int,2>, /* allocator at the end */
T* p,Args&&... args)
{
::new ((void*)p) T(std::forward<Args>(args)...,*this);
}
template<typename... Args,std::size_t... I>
std::tuple<Args&&...> transform_tuple(
std::integral_constant<int,0>, /* doesn't use allocator */
std::tuple<Args...>&& t,mp11::index_sequence<I...>)
{
return std::tuple<Args&&...>(std::get<I>(std::move(t))...);
}
template<typename... Args,std::size_t... I>
std::tuple<std::allocator_arg_t,allocator_adaptor&,Args&&...>
transform_tuple(
std::integral_constant<int,1>, /* with std::allocator_arg */
std::tuple<Args...>&& t,mp11::index_sequence<I...>)
{
return std::tuple<
std::allocator_arg_t,allocator_adaptor&,Args&&...>(
std::allocator_arg,*this,std::get<I>(std::move(t))...);
}
template<typename... Args,std::size_t... I>
std::tuple<Args&&...,allocator_adaptor&>
transform_tuple(
std::integral_constant<int,2>, /* allocator at the end */
std::tuple<Args...>&& t,mp11::index_sequence<I...>)
{
return std::tuple<Args&&...,allocator_adaptor&>(
std::get<I>(std::move(t))...,*this);
}
};
template<typename Allocator1,typename Allocator2>
bool operator==(
const allocator_adaptor<Allocator1>& x,
const allocator_adaptor<Allocator2>& y)noexcept
{
return x.allocator()==y.allocator();
}
template<typename Allocator1,typename Allocator2>
bool operator!=(
const allocator_adaptor<Allocator1>& x,
const allocator_adaptor<Allocator2>& y)noexcept
{
return !(x==y);
}
} /* namespace poly_collection::detail */
} /* namespace poly_collection */
} /* namespace boost */
#endif

View File

@@ -0,0 +1,92 @@
/* Copyright 2016 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_ANY_ITERATOR_HPP
#define BOOST_POLY_COLLECTION_DETAIL_ANY_ITERATOR_HPP
#if defined(_MSC_VER)
#pragma once
#endif
#include <boost/iterator/iterator_adaptor.hpp>
#include <boost/type_erasure/any_cast.hpp>
#include <type_traits>
#include <utility>
namespace boost{
namespace poly_collection{
namespace detail{
/* type_erasure::any<Concept>* adaptor convertible to pointer to wrapped
* entity.
*/
template<typename Any>
class any_iterator:public boost::iterator_adaptor<any_iterator<Any>,Any*>
{
public:
any_iterator()=default;
explicit any_iterator(Any* p)noexcept:any_iterator::iterator_adaptor_{p}{}
any_iterator(const any_iterator&)=default;
any_iterator& operator=(const any_iterator&)=default;
template<
typename NonConstAny,
typename std::enable_if<
std::is_same<Any,const NonConstAny>::value>::type* =nullptr
>
any_iterator(const any_iterator<NonConstAny>& x)noexcept:
any_iterator::iterator_adaptor_{x.base()}{}
template<
typename NonConstAny,
typename std::enable_if<
std::is_same<Any,const NonConstAny>::value>::type* =nullptr
>
any_iterator& operator=(const any_iterator<NonConstAny>& x)noexcept
{
this->base_reference()=x.base();
return *this;
}
/* interoperability with Any* */
any_iterator& operator=(Any* p)noexcept
{this->base_reference()=p;return *this;}
operator Any*()const noexcept{return this->base();}
/* interoperability with Concrete* */
template<
typename Concrete,
typename std::enable_if<
/* can't compile-time check concept compliance */
!std::is_const<Any>::value||std::is_const<Concrete>::value
>::type* =nullptr
>
explicit operator Concrete*()const noexcept
{
return const_cast<Concrete*>(
static_cast<typename std::remove_const<Concrete>::type*>(
type_erasure::any_cast<void*>(this->base())));
}
private:
template<typename>
friend class any_iterator;
};
} /* namespace poly_collection::detail */
} /* namespace poly_collection */
} /* namespace boost */
#endif

View File

@@ -0,0 +1,206 @@
/* Copyright 2016-2020 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_ANY_MODEL_HPP
#define BOOST_POLY_COLLECTION_DETAIL_ANY_MODEL_HPP
#if defined(_MSC_VER)
#pragma once
#endif
#include <boost/core/addressof.hpp>
#include <boost/mpl/map/map10.hpp>
#include <boost/mpl/pair.hpp>
#include <boost/mpl/vector/vector10.hpp>
#include <boost/poly_collection/detail/any_iterator.hpp>
#include <boost/poly_collection/detail/is_acceptable.hpp>
#include <boost/poly_collection/detail/segment_backend.hpp>
#include <boost/poly_collection/detail/split_segment.hpp>
#include <boost/type_erasure/any.hpp>
#include <boost/type_erasure/any_cast.hpp>
#include <boost/type_erasure/binding.hpp>
#include <boost/type_erasure/builtin.hpp>
#include <boost/type_erasure/concept_of.hpp>
#include <boost/type_erasure/is_subconcept.hpp>
#include <boost/type_erasure/relaxed.hpp>
#include <boost/type_erasure/static_binding.hpp>
#include <boost/type_erasure/typeid_of.hpp>
#include <memory>
#include <type_traits>
#include <typeinfo>
#include <utility>
namespace boost{
namespace poly_collection{
namespace detail{
/* model for any_collection */
template<typename Concept>
struct any_model;
/* Refine is_acceptable to cover type_erasure::any classes whose assignment
* operator won't compile.
*/
template<typename Concept,typename Concept2,typename T>
struct is_acceptable<
type_erasure::any<Concept2,T>,any_model<Concept>,
typename std::enable_if<
!type_erasure::is_relaxed<Concept2>::value&&
!type_erasure::is_subconcept<type_erasure::assignable<>,Concept2>::value&&
!type_erasure::is_subconcept<
type_erasure::assignable<type_erasure::_self,type_erasure::_self&&>,
Concept2>::value
>::type
>:std::false_type{};
/* is_terminal defined out-class to allow for partial specialization */
template<typename Concept,typename T>
using any_model_enable_if_has_typeid_=typename std::enable_if<
type_erasure::is_subconcept<
type_erasure::typeid_<typename std::decay<T>::type>,
Concept
>::value
>::type*;
template<typename T,typename=void*>
struct any_model_is_terminal:std::true_type{};
template<typename Concept,typename T>
struct any_model_is_terminal<
type_erasure::any<Concept,T>,any_model_enable_if_has_typeid_<Concept,T>
>:std::false_type{};
/* used for make_value_type */
template<typename T,typename Q>
struct any_model_make_reference
{
static T& apply(Q& x){return x;}
};
template<typename Concept>
struct any_model
{
using value_type=type_erasure::any<
typename std::conditional<
type_erasure::is_subconcept<type_erasure::typeid_<>,Concept>::value,
Concept,
mpl::vector2<Concept,type_erasure::typeid_<>>
>::type,
type_erasure::_self&
>;
template<typename Concrete>
using is_implementation=std::true_type; /* can't compile-time check concept
* compliance */
template<typename T>
using is_terminal=any_model_is_terminal<T>;
template<typename T>
static const std::type_info& subtypeid(const T&){return typeid(T);}
template<
typename Concept2,typename T,
any_model_enable_if_has_typeid_<Concept2,T> =nullptr
>
static const std::type_info& subtypeid(
const type_erasure::any<Concept2,T>& a)
{
return type_erasure::typeid_of(a);
}
template<typename T>
static void* subaddress(T& x){return boost::addressof(x);}
template<typename T>
static const void* subaddress(const T& x){return boost::addressof(x);}
template<
typename Concept2,typename T,
any_model_enable_if_has_typeid_<Concept2,T> =nullptr
>
static void* subaddress(type_erasure::any<Concept2,T>& a)
{
return type_erasure::any_cast<void*>(&a);
}
template<
typename Concept2,typename T,
any_model_enable_if_has_typeid_<Concept2,T> =nullptr
>
static const void* subaddress(const type_erasure::any<Concept2,T>& a)
{
return type_erasure::any_cast<const void*>(&a);
}
using base_iterator=any_iterator<value_type>;
using const_base_iterator=any_iterator<const value_type>;
using base_sentinel=value_type*;
using const_base_sentinel=const value_type*;
template<typename Concrete>
using iterator=Concrete*;
template<typename Concrete>
using const_iterator=const Concrete*;
template<typename Allocator>
using segment_backend=detail::segment_backend<any_model,Allocator>;
template<typename Concrete,typename Allocator>
using segment_backend_implementation=
split_segment<any_model,Concrete,Allocator>;
static base_iterator nonconst_iterator(const_base_iterator it)
{
return base_iterator{
const_cast<value_type*>(static_cast<const value_type*>(it))};
}
template<typename T>
static iterator<T> nonconst_iterator(const_iterator<T> it)
{
return const_cast<iterator<T>>(it);
}
private:
template<typename,typename,typename>
friend class split_segment;
template<typename Concrete>
static value_type make_value_type(Concrete& x){return value_type{x};}
template<typename Concept2,typename T>
static value_type make_value_type(type_erasure::any<Concept2,T>& x)
{
/* I don't pretend to understand what's going on here, see
* https://lists.boost.org/boost-users/2017/05/87556.php
*/
using ref_type=type_erasure::any<Concept2,T>;
using make_ref=any_model_make_reference<type_erasure::_self,ref_type>;
using concept_=typename type_erasure::concept_of<value_type>::type;
auto b=type_erasure::make_binding<
mpl::map1<mpl::pair<type_erasure::_self,ref_type>>>();
return {
type_erasure::call(type_erasure::binding<make_ref>{b},make_ref{},x),
type_erasure::binding<concept_>{b}
};
}
};
} /* namespace poly_collection::detail */
} /* namespace poly_collection */
} /* namespace boost */
#endif

View File

@@ -0,0 +1,56 @@
/* Copyright 2016 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_AUTO_ITERATOR_HPP
#define BOOST_POLY_COLLECTION_DETAIL_AUTO_ITERATOR_HPP
#if defined(_MSC_VER)
#pragma once
#endif
#include <boost/iterator/iterator_adaptor.hpp>
namespace boost{
namespace poly_collection{
namespace detail{
/* auto_iterator<Iterator> (for want of a better name) behaves like Iterator
* save for the fact that it derefs to Iterator& rather than
* Iterator::reference. This is useful to "lift" std algorithms so that
* user-defined predicates are passed iterators that can then be dereferenced
* internally.
*/
template<typename Iterator>
class auto_iterator:
public boost::iterator_adaptor<auto_iterator<Iterator>,Iterator,Iterator>
{
public:
auto_iterator()=default;
auto_iterator(const Iterator& it):auto_iterator::iterator_adaptor_{it}{}
auto_iterator(const auto_iterator&)=default;
auto_iterator& operator=(const auto_iterator&)=default;
private:
friend class boost::iterator_core_access;
Iterator& dereference()const noexcept
{
return const_cast<auto_iterator*>(this)->base_reference();
}
};
} /* namespace poly_collection::detail */
} /* namespace poly_collection */
} /* namespace boost */
#endif

View File

@@ -0,0 +1,120 @@
/* 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_BASE_MODEL_HPP
#define BOOST_POLY_COLLECTION_DETAIL_BASE_MODEL_HPP
#if defined(_MSC_VER)
#pragma once
#endif
#include <boost/core/addressof.hpp>
#include <boost/poly_collection/detail/is_final.hpp>
#include <boost/poly_collection/detail/packed_segment.hpp>
#include <boost/poly_collection/detail/stride_iterator.hpp>
#include <memory>
#include <type_traits>
#include <typeinfo>
#include <utility>
namespace boost{
namespace poly_collection{
namespace detail{
/* model for base_collection */
template<typename Base>
struct base_model
{
using value_type=Base;
template<typename Derived>
using is_implementation=std::is_base_of<Base,Derived>;
template<typename T>
using is_terminal=is_final<T>; //TODO: should we say !is_polymorhpic||is_final?
private:
template<typename T>
using enable_if_not_terminal=
typename std::enable_if<!is_terminal<T>::value>::type*;
template<typename T>
using enable_if_terminal=
typename std::enable_if<is_terminal<T>::value>::type*;
public:
template<typename T,enable_if_not_terminal<T> =nullptr>
static const std::type_info& subtypeid(const T& x){return typeid(x);}
template<typename T,enable_if_terminal<T> =nullptr>
static const std::type_info& subtypeid(const T&){return typeid(T);}
template<typename T,enable_if_not_terminal<T> =nullptr>
static void* subaddress(T& x)
{
return dynamic_cast<void*>(boost::addressof(x));
}
template<typename T,enable_if_not_terminal<T> =nullptr>
static const void* subaddress(const T& x)
{
return dynamic_cast<const void*>(boost::addressof(x));
}
template<typename T,enable_if_terminal<T> =nullptr>
static void* subaddress(T& x){return boost::addressof(x);}
template<typename T,enable_if_terminal<T> =nullptr>
static const void* subaddress(const T& x){return boost::addressof(x);}
using base_iterator=stride_iterator<Base>;
using const_base_iterator=stride_iterator<const Base>;
using base_sentinel=Base*;
using const_base_sentinel=const Base*;
template<typename Derived>
using iterator=Derived*;
template<typename Derived>
using const_iterator=const Derived*;
template<typename Allocator>
using segment_backend=detail::segment_backend<base_model,Allocator>;
template<typename Derived,typename Allocator>
using segment_backend_implementation=
packed_segment<base_model,Derived,Allocator>;
static base_iterator nonconst_iterator(const_base_iterator it)
{
return {
const_cast<value_type*>(static_cast<const value_type*>(it)),
it.stride()
};
}
template<typename T>
static iterator<T> nonconst_iterator(const_iterator<T> it)
{
return const_cast<iterator<T>>(it);
}
private:
template<typename,typename,typename>
friend class packed_segment;
template<typename Derived>
static const Base* value_ptr(const Derived* p)noexcept
{
return p;
}
};
} /* namespace poly_collection::detail */
} /* namespace poly_collection */
} /* namespace boost */
#endif

View File

@@ -0,0 +1,104 @@
/* Copyright 2016-2017 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_CALLABLE_WRAPPER_HPP
#define BOOST_POLY_COLLECTION_DETAIL_CALLABLE_WRAPPER_HPP
#if defined(_MSC_VER)
#pragma once
#endif
#include <boost/poly_collection/detail/is_invocable.hpp>
#include <functional>
#include <type_traits>
#include <typeinfo>
namespace boost{
namespace poly_collection{
namespace detail{
/* lightweight std::function look-alike over non-owned callable entities */
template<typename Signature>
class callable_wrapper;
template<typename R,typename... Args>
class callable_wrapper<R(Args...)>
{
public:
// TODO: we should prevent assignment by user code
template<
typename Callable,
typename std::enable_if<
!std::is_same<Callable,callable_wrapper>::value&&
is_invocable_r<R,Callable,Args...>::value
>::type* =nullptr
>
explicit callable_wrapper(Callable& x)noexcept:pt{info(x)},px{&x}{}
callable_wrapper(const callable_wrapper&)=default;
callable_wrapper& operator=(const callable_wrapper&)=default;
explicit operator bool()const noexcept{return true;}
R operator()(Args... args)const
{return pt->call(px,std::forward<Args>(args)...);}
const std::type_info& target_type()const noexcept{return pt->info;}
template<typename T>
T* target()noexcept
{return typeid(T)==pt->info?static_cast<T*>(px):nullptr;}
template<typename T>
const T* target()const noexcept
{return typeid(T)==pt->info?static_cast<const T*>(px):nullptr;}
/* not in std::function interface */
operator std::function<R(Args...)>()const noexcept{return pt->convert(px);}
void* data()noexcept{return px;}
const void* data()const noexcept{return px;}
private:
struct table
{
R(*call)(void*,Args...);
const std::type_info& info;
std::function<R(Args...)> (*convert)(void*);
};
template<typename Callable>
static table* info(Callable&)noexcept
{
static table t={
[](void* p,Args... args){
auto r=std::ref(*static_cast<Callable*>(p));
return static_cast<R>(r(std::forward<Args>(args)...));
},
typeid(Callable),
[](void* p){
auto r=std::ref(*static_cast<Callable*>(p));
return std::function<R(Args...)>{r};
}
};
return &t;
}
table* pt;
void* px;
};
} /* namespace poly_collection::detail */
} /* namespace poly_collection */
} /* namespace boost */
#endif

View File

@@ -0,0 +1,95 @@
/* Copyright 2016 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_CALLABLE_WRAPPER_ITERATOR_HPP
#define BOOST_POLY_COLLECTION_DETAIL_CALLABLE_WRAPPER_ITERATOR_HPP
#if defined(_MSC_VER)
#pragma once
#endif
#include <boost/iterator/iterator_adaptor.hpp>
#include <type_traits>
namespace boost{
namespace poly_collection{
namespace detail{
/* callable_wrapper<Sig>* adaptor convertible to pointer to wrapped entity */
template<typename CWrapper>
class callable_wrapper_iterator:public boost::iterator_adaptor<
callable_wrapper_iterator<CWrapper>,CWrapper*
>
{
public:
callable_wrapper_iterator()=default;
explicit callable_wrapper_iterator(CWrapper* p)noexcept:
callable_wrapper_iterator::iterator_adaptor_{p}{}
callable_wrapper_iterator(const callable_wrapper_iterator&)=default;
callable_wrapper_iterator& operator=(
const callable_wrapper_iterator&)=default;
template<
typename NonConstCWrapper,
typename std::enable_if<
std::is_same<CWrapper,const NonConstCWrapper>::value>::type* =nullptr
>
callable_wrapper_iterator(
const callable_wrapper_iterator<NonConstCWrapper>& x)noexcept:
callable_wrapper_iterator::iterator_adaptor_{x.base()}{}
template<
typename NonConstCWrapper,
typename std::enable_if<
std::is_same<CWrapper,const NonConstCWrapper>::value>::type* =nullptr
>
callable_wrapper_iterator& operator=(
const callable_wrapper_iterator<NonConstCWrapper>& x)noexcept
{
this->base_reference()=x.base();
return *this;
}
/* interoperability with CWrapper* */
callable_wrapper_iterator& operator=(CWrapper* p)noexcept
{this->base_reference()=p;return *this;}
operator CWrapper*()const noexcept{return this->base();}
/* interoperability with Callable* */
template<
typename Callable,
typename std::enable_if<
std::is_constructible<CWrapper,Callable&>::value&&
(!std::is_const<CWrapper>::value||std::is_const<Callable>::value)
>::type* =nullptr
>
explicit operator Callable*()const noexcept
{
return const_cast<Callable*>(
static_cast<const Callable*>(
const_cast<const void*>(
this->base()->data())));
}
private:
template<typename>
friend class callable_wrapper_iterator;
};
} /* namespace poly_collection::detail */
} /* namespace poly_collection */
} /* namespace boost */
#endif

View File

@@ -0,0 +1,126 @@
/* 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_FUNCTION_MODEL_HPP
#define BOOST_POLY_COLLECTION_DETAIL_FUNCTION_MODEL_HPP
#if defined(_MSC_VER)
#pragma once
#endif
#include <boost/core/addressof.hpp>
#include <boost/poly_collection/detail/callable_wrapper.hpp>
#include <boost/poly_collection/detail/callable_wrapper_iterator.hpp>
#include <boost/poly_collection/detail/is_invocable.hpp>
#include <boost/poly_collection/detail/segment_backend.hpp>
#include <boost/poly_collection/detail/split_segment.hpp>
#include <memory>
#include <type_traits>
#include <typeinfo>
#include <utility>
namespace boost{
namespace poly_collection{
namespace detail{
/* model for function_collection */
template<typename Signature>
struct function_model;
/* is_terminal defined out-class to allow for partial specialization */
template<typename T>
struct function_model_is_terminal:std::true_type{};
template<typename Signature>
struct function_model_is_terminal<callable_wrapper<Signature>>:
std::false_type{};
template<typename R,typename... Args>
struct function_model<R(Args...)>
{
using value_type=callable_wrapper<R(Args...)>;
template<typename Callable>
using is_implementation=is_invocable_r<R,Callable&,Args...>;
template<typename T>
using is_terminal=function_model_is_terminal<T>;
template<typename T>
static const std::type_info& subtypeid(const T&){return typeid(T);}
template<typename Signature>
static const std::type_info& subtypeid(
const callable_wrapper<Signature>& f)
{
return f.target_type();
}
template<typename T>
static void* subaddress(T& x){return boost::addressof(x);}
template<typename T>
static const void* subaddress(const T& x){return boost::addressof(x);}
template<typename Signature>
static void* subaddress(callable_wrapper<Signature>& f)
{
return f.data();
}
template<typename Signature>
static const void* subaddress(const callable_wrapper<Signature>& f)
{
return f.data();
}
using base_iterator=callable_wrapper_iterator<value_type>;
using const_base_iterator=callable_wrapper_iterator<const value_type>;
using base_sentinel=value_type*;
using const_base_sentinel=const value_type*;
template<typename Callable>
using iterator=Callable*;
template<typename Callable>
using const_iterator=const Callable*;
template<typename Allocator>
using segment_backend=detail::segment_backend<function_model,Allocator>;
template<typename Callable,typename Allocator>
using segment_backend_implementation=
split_segment<function_model,Callable,Allocator>;
static base_iterator nonconst_iterator(const_base_iterator it)
{
return base_iterator{
const_cast<value_type*>(static_cast<const value_type*>(it))};
}
template<typename T>
static iterator<T> nonconst_iterator(const_iterator<T> it)
{
return const_cast<iterator<T>>(it);
}
private:
template<typename,typename,typename>
friend class split_segment;
template<typename Callable>
static value_type make_value_type(Callable& x){return value_type{x};}
};
} /* namespace poly_collection::detail */
} /* namespace poly_collection */
} /* namespace boost */
#endif

View File

@@ -0,0 +1,201 @@
/* 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_FUNCTIONAL_HPP
#define BOOST_POLY_COLLECTION_DETAIL_FUNCTIONAL_HPP
#if defined(_MSC_VER)
#pragma once
#endif
#include <boost/config.hpp>
#include <boost/detail/workaround.hpp>
#include <boost/mp11/integer_sequence.hpp>
#include <tuple>
#include <utility>
/* Assorted functional utilities. Much of this would be almost trivial with
* C++14 generic lambdas.
*/
#if BOOST_WORKAROUND(BOOST_MSVC,>=1910)
/* https://lists.boost.org/Archives/boost/2017/06/235687.php */
#define BOOST_POLY_COLLECTION_DEFINE_OVERLOAD_SET(name,f) \
struct name \
{ \
template<typename... Args> \
auto operator()(Args&&... args)const \
{ \
return f(std::forward<Args>(args)...); \
} \
};
#else
#define BOOST_POLY_COLLECTION_DEFINE_OVERLOAD_SET(name,f) \
struct name \
{ \
template<typename... Args> \
auto operator()(Args&&... args)const-> \
decltype(f(std::forward<Args>(args)...)) \
{ \
return f(std::forward<Args>(args)...); \
} \
};
#endif
namespace boost{
namespace poly_collection{
namespace detail{
template<typename F,typename... TailArgs>
struct tail_closure_class
{
tail_closure_class(const F& f,std::tuple<TailArgs...> t):f(f),t(t){}
template<typename... Args>
using return_type=decltype(
std::declval<F>()(std::declval<Args>()...,std::declval<TailArgs>()...));
template<typename... Args,std::size_t... I>
return_type<Args&&...> call(mp11::index_sequence<I...>,Args&&... args)
{
return f(std::forward<Args>(args)...,std::get<I>(t)...);
}
template<typename... Args>
return_type<Args&&...> operator()(Args&&... args)
{
return call(
mp11::make_index_sequence<sizeof...(TailArgs)>{},
std::forward<Args>(args)...);
}
F f;
std::tuple<TailArgs...> t;
};
template<typename F,typename... Args>
tail_closure_class<F,Args&&...> tail_closure(const F& f,Args&&... args)
{
return {f,std::forward_as_tuple(std::forward<Args>(args)...)};
}
template<typename F,typename... HeadArgs>
struct head_closure_class
{
head_closure_class(const F& f,std::tuple<HeadArgs...> t):f(f),t(t){}
template<typename... Args>
using return_type=decltype(
std::declval<F>()(std::declval<HeadArgs>()...,std::declval<Args>()...));
template<typename... Args,std::size_t... I>
return_type<Args&&...> call(mp11::index_sequence<I...>,Args&&... args)
{
return f(std::get<I>(t)...,std::forward<Args>(args)...);
}
template<typename... Args>
return_type<Args&&...> operator()(Args&&... args)
{
return call(
mp11::make_index_sequence<sizeof...(HeadArgs)>{},
std::forward<Args>(args)...);
}
F f;
std::tuple<HeadArgs...> t;
};
template<typename F,typename... Args>
head_closure_class<F,Args&&...> head_closure(const F& f,Args&&... args)
{
return {f,std::forward_as_tuple(std::forward<Args>(args)...)};
}
template<typename ReturnType,typename F>
struct cast_return_class
{
cast_return_class(const F& f):f(f){}
template<typename... Args>
ReturnType operator()(Args&&... args)const
{
return static_cast<ReturnType>(f(std::forward<Args>(args)...));
}
F f;
};
template<typename ReturnType,typename F>
cast_return_class<ReturnType,F> cast_return(const F& f)
{
return {f};
}
template<typename F>
struct deref_to_class
{
deref_to_class(const F& f):f(f){}
template<typename... Args>
auto operator()(Args&&... args)->decltype(std::declval<F>()(*args...))
{
return f(*args...);
}
F f;
};
template<typename F>
deref_to_class<F> deref_to(const F& f)
{
return {f};
}
template<typename F>
struct deref_1st_to_class
{
deref_1st_to_class(const F& f):f(f){}
template<typename Arg,typename... Args>
auto operator()(Arg&& arg,Args&&... args)
->decltype(std::declval<F>()(*arg,std::forward<Args>(args)...))
{
return f(*arg,std::forward<Args>(args)...);
}
F f;
};
template<typename F>
deref_1st_to_class<F> deref_1st_to(const F& f)
{
return {f};
}
struct transparent_equal_to
{
template<typename T,typename U>
auto operator()(T&& x,U&& y)const
noexcept(noexcept(std::forward<T>(x)==std::forward<U>(y)))
->decltype(std::forward<T>(x)==std::forward<U>(y))
{
return std::forward<T>(x)==std::forward<U>(y);
}
};
} /* namespace poly_collection::detail */
} /* namespace poly_collection */
} /* namespace boost */
#endif

View File

@@ -0,0 +1,44 @@
/* Copyright 2016-2017 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_IS_ACCEPTABLE_HPP
#define BOOST_POLY_COLLECTION_DETAIL_IS_ACCEPTABLE_HPP
#if defined(_MSC_VER)
#pragma once
#endif
#include <type_traits>
namespace boost{
namespace poly_collection{
namespace detail{
/* This can be further specialized by Model when the std type trait classes
* fail to give the right info (as it can happen with class templates whose
* nominally existing operators do not compile for certain instantiations).
*/
template<typename T,typename Model,typename=void>
struct is_acceptable:std::integral_constant<
bool,
Model::template is_implementation<T>::value&&
std::is_move_constructible<typename std::decay<T>::type>::value&&
(std::is_move_assignable<typename std::decay<T>::type>::value||
std::is_nothrow_move_constructible<typename std::decay<T>::type>::value)
>{};
} /* namespace poly_collection::detail */
} /* namespace poly_collection */
} /* namespace boost */
#endif

View File

@@ -0,0 +1,65 @@
/* Copyright 2016-2017 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_IS_CONSTRUCIBLE_HPP
#define BOOST_POLY_COLLECTION_DETAIL_IS_CONSTRUCIBLE_HPP
#if defined(_MSC_VER)
#pragma once
#endif
#include <boost/config.hpp>
#include <boost/detail/workaround.hpp>
#if BOOST_WORKAROUND(BOOST_MSVC_FULL_VER,<190023918)
/* https://connect.microsoft.com/VisualStudio/Feedback/Details/2118677,
* fixed in VS2015U2 according to
* https://blogs.msdn.microsoft.com/vcblog/2016/03/31/
* visual-c-2015-update-2-bug-fixes/, via github.com/dodheim
*/
#include <boost/type_traits/is_constructible.hpp>
namespace boost{
namespace poly_collection{
namespace detail{
template<typename T,typename... Args>
struct is_constructible:std::integral_constant<
bool,
boost::is_constructible<T,Args...>::value
>{};
} /* namespace poly_collection::detail */
} /* namespace poly_collection */
} /* namespace boost */
#else
#include <type_traits>
namespace boost{
namespace poly_collection{
namespace detail{
template<typename T,typename... Args>
using is_constructible=std::is_constructible<T,Args...>;
} /* namespace poly_collection::detail */
} /* namespace poly_collection */
} /* namespace boost */
#endif
#endif

View File

@@ -0,0 +1,37 @@
/* Copyright 2017-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_IS_EQUALITY_COMPARABLE_HPP
#define BOOST_POLY_COLLECTION_DETAIL_IS_EQUALITY_COMPARABLE_HPP
#if defined(_MSC_VER)
#pragma once
#endif
#include <boost/type_traits/has_equal_to.hpp>
#include <type_traits>
namespace boost{
namespace poly_collection{
namespace detail{
template<typename T>
using is_equality_comparable=std::integral_constant<
bool,
has_equal_to<T,T,bool>::value
>;
} /* namespace poly_collection::detail */
} /* namespace poly_collection */
} /* namespace boost */
#endif

View File

@@ -0,0 +1,68 @@
/* Copyright 2016-2017 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_IS_FINAL_HPP
#define BOOST_POLY_COLLECTION_DETAIL_IS_FINAL_HPP
#if defined(_MSC_VER)
#pragma once
#endif
#include <boost/type_traits/is_final.hpp>
#include <type_traits>
/* technique explained at
* http://bannalia.blogspot.com/2016/09/compile-time-checking-existence-of.html
*/
namespace boost{
namespace poly_collection{
namespace detail{
namespace is_final_fallback{
template<typename T> using is_final=boost::is_final<T>;
struct hook{};
}}}}
namespace std{
template<>
struct is_void< ::boost::poly_collection::detail::is_final_fallback::hook>:
std::false_type
{
template<typename T>
static constexpr bool is_final_f()
{
using namespace ::boost::poly_collection::detail::is_final_fallback;
return is_final<T>::value;
}
};
} /* namespace std */
namespace boost{
namespace poly_collection{
namespace detail{
template<typename T>
struct is_final:std::integral_constant<
bool,
std::is_void<is_final_fallback::hook>::template is_final_f<T>()
>{};
} /* namespace poly_collection::detail */
} /* namespace poly_collection */
} /* namespace boost */
#endif

View File

@@ -0,0 +1,97 @@
/* Copyright 2016-2017 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_IS_INVOCABLE_HPP
#define BOOST_POLY_COLLECTION_DETAIL_IS_INVOCABLE_HPP
#if defined(_MSC_VER)
#pragma once
#endif
#include <functional>
#include <type_traits>
/* technique explained at
* http://bannalia.blogspot.com/2016/09/compile-time-checking-existence-of.html
*/
namespace boost{
namespace poly_collection{
namespace detail{
namespace is_invocable_fallback{
template <typename F,typename... Args>
struct is_invocable:
std::is_constructible<
std::function<void(Args...)>,
std::reference_wrapper<typename std::remove_reference<F>::type>
>
{};
template <typename R,typename F,typename... Args>
struct is_invocable_r:
std::is_constructible<
std::function<R(Args...)>,
std::reference_wrapper<typename std::remove_reference<F>::type>
>
{};
struct hook{};
}}}}
namespace std{
template<>
struct is_void< ::boost::poly_collection::detail::is_invocable_fallback::hook>:
std::false_type
{
template<typename F,typename... Args>
static constexpr bool is_invocable_f()
{
using namespace ::boost::poly_collection::detail::is_invocable_fallback;
return is_invocable<F,Args...>::value;
}
template<typename R,typename F,typename... Args>
static constexpr bool is_invocable_r_f()
{
using namespace ::boost::poly_collection::detail::is_invocable_fallback;
return is_invocable_r<R,F,Args...>::value;
}
};
} /* namespace std */
namespace boost{
namespace poly_collection{
namespace detail{
template<typename F,typename... Args>
struct is_invocable:std::integral_constant<
bool,
std::is_void<is_invocable_fallback::hook>::template
is_invocable_f<F,Args...>()
>{};
template<typename R,typename F,typename... Args>
struct is_invocable_r:std::integral_constant<
bool,
std::is_void<is_invocable_fallback::hook>::template
is_invocable_r_f<R,F,Args...>()
>{};
} /* namespace poly_collection::detail */
} /* namespace poly_collection */
} /* namespace boost */
#endif

View File

@@ -0,0 +1,46 @@
/* Copyright 2016-2017 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_IS_NOTHROW_EQ_COMPARABLE_HPP
#define BOOST_POLY_COLLECTION_DETAIL_IS_NOTHROW_EQ_COMPARABLE_HPP
#if defined(_MSC_VER)
#pragma once
#endif
#include <boost/poly_collection/detail/is_equality_comparable.hpp>
#include <type_traits>
#include <utility>
namespace boost{
namespace poly_collection{
namespace detail{
template<typename T,typename=void>
struct is_nothrow_equality_comparable:std::false_type{};
template<typename T>
struct is_nothrow_equality_comparable<
T,
typename std::enable_if<
is_equality_comparable<T>::value
>::type
>:std::integral_constant<
bool,
noexcept(std::declval<T>()==std::declval<T>())
>{};
} /* namespace poly_collection::detail */
} /* namespace poly_collection */
} /* namespace boost */
#endif

View File

@@ -0,0 +1,242 @@
/* Copyright 2016-2017 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_ITERATOR_IMPL_HPP
#define BOOST_POLY_COLLECTION_DETAIL_ITERATOR_IMPL_HPP
#if defined(_MSC_VER)
#pragma once
#endif
#include <boost/iterator/iterator_adaptor.hpp>
#include <boost/iterator/iterator_facade.hpp>
#include <boost/poly_collection/detail/is_constructible.hpp>
#include <boost/poly_collection/detail/iterator_traits.hpp>
#include <type_traits>
#include <typeinfo>
namespace boost{
namespace poly_collection{
namespace detail{
/* Implementations of poly_collection::[const_][local_[base_]]iterator moved
* out of class to allow for use in deduced contexts.
*/
template<typename PolyCollection,bool Const>
using iterator_impl_value_type=typename std::conditional<
Const,
const typename PolyCollection::value_type,
typename PolyCollection::value_type
>::type;
template<typename PolyCollection,bool Const>
class iterator_impl:
public boost::iterator_facade<
iterator_impl<PolyCollection,Const>,
iterator_impl_value_type<PolyCollection,Const>,
boost::forward_traversal_tag
>
{
using segment_type=typename PolyCollection::segment_type;
using const_segment_base_iterator=
typename PolyCollection::const_segment_base_iterator;
using const_segment_base_sentinel=
typename PolyCollection::const_segment_base_sentinel;
using const_segment_map_iterator=
typename PolyCollection::const_segment_map_iterator;
public:
using value_type=iterator_impl_value_type<PolyCollection,Const>;
private:
iterator_impl(
const_segment_map_iterator mapit,
const_segment_map_iterator mapend)noexcept:
mapit{mapit},mapend{mapend}
{
next_segment_position();
}
iterator_impl(
const_segment_map_iterator mapit_,const_segment_map_iterator mapend_,
const_segment_base_iterator segpos_)noexcept:
mapit{mapit_},mapend{mapend_},segpos{segpos_}
{
if(mapit!=mapend&&segpos==sentinel()){
++mapit;
next_segment_position();
}
}
public:
iterator_impl()=default;
iterator_impl(const iterator_impl&)=default;
iterator_impl& operator=(const iterator_impl&)=default;
template<bool Const2,typename std::enable_if<!Const2>::type* =nullptr>
iterator_impl(const iterator_impl<PolyCollection,Const2>& x):
mapit{x.mapit},mapend{x.mapend},segpos{x.segpos}{}
private:
template<typename,bool>
friend class iterator_impl;
friend PolyCollection;
friend class boost::iterator_core_access;
template<typename>
friend struct iterator_traits;
value_type& dereference()const noexcept
{return const_cast<value_type&>(*segpos);}
bool equal(const iterator_impl& x)const noexcept{return segpos==x.segpos;}
void increment()noexcept
{
if(++segpos==sentinel()){
++mapit;
next_segment_position();
}
}
void next_segment_position()noexcept
{
for(;mapit!=mapend;++mapit){
segpos=segment().begin();
if(segpos!=sentinel())return;
}
segpos=nullptr;
}
segment_type& segment()noexcept
{return const_cast<segment_type&>(mapit->second);}
const segment_type& segment()const noexcept{return mapit->second;}
const_segment_base_sentinel sentinel()const noexcept
{return segment().sentinel();}
const_segment_map_iterator mapit,mapend;
const_segment_base_iterator segpos;
};
template<typename PolyCollection,bool Const>
struct poly_collection_of<iterator_impl<PolyCollection,Const>>
{
using type=PolyCollection;
};
template<typename PolyCollection,typename BaseIterator>
class local_iterator_impl:
public boost::iterator_adaptor<
local_iterator_impl<PolyCollection,BaseIterator>,
BaseIterator
>
{
using segment_type=typename PolyCollection::segment_type;
using segment_base_iterator=typename PolyCollection::segment_base_iterator;
using const_segment_map_iterator=
typename PolyCollection::const_segment_map_iterator;
template<typename Iterator>
local_iterator_impl(
const_segment_map_iterator mapit,
Iterator it):
local_iterator_impl::iterator_adaptor_{BaseIterator(it)},
mapit{mapit}
{}
public:
using base_iterator=BaseIterator;
local_iterator_impl()=default;
local_iterator_impl(const local_iterator_impl&)=default;
local_iterator_impl& operator=(const local_iterator_impl&)=default;
template<
typename BaseIterator2,
typename std::enable_if<
std::is_convertible<BaseIterator2,BaseIterator>::value
>::type* =nullptr
>
local_iterator_impl(
const local_iterator_impl<PolyCollection,BaseIterator2>& x):
local_iterator_impl::iterator_adaptor_{x.base()},
mapit{x.mapit}{}
template<
typename BaseIterator2,
typename std::enable_if<
!std::is_convertible<BaseIterator2,BaseIterator>::value&&
is_constructible<BaseIterator,BaseIterator2>::value
>::type* =nullptr
>
explicit local_iterator_impl(
const local_iterator_impl<PolyCollection,BaseIterator2>& x):
local_iterator_impl::iterator_adaptor_{BaseIterator(x.base())},
mapit{x.mapit}{}
template<
typename BaseIterator2,
typename std::enable_if<
!is_constructible<BaseIterator,BaseIterator2>::value&&
is_constructible<BaseIterator,segment_base_iterator>::value&&
is_constructible<BaseIterator2,segment_base_iterator>::value
>::type* =nullptr
>
explicit local_iterator_impl(
const local_iterator_impl<PolyCollection,BaseIterator2>& x):
local_iterator_impl::iterator_adaptor_{
base_iterator_from(x.segment(),x.base())},
mapit{x.mapit}{}
/* define [] to avoid Boost.Iterator operator_brackets_proxy mess */
template<typename DifferenceType>
typename std::iterator_traits<BaseIterator>::reference
operator[](DifferenceType n)const{return *(*this+n);}
private:
template<typename,typename>
friend class local_iterator_impl;
friend PolyCollection;
template<typename>
friend struct iterator_traits;
template<typename BaseIterator2>
static BaseIterator base_iterator_from(
const segment_type& s,BaseIterator2 it)
{
segment_base_iterator bit=s.begin();
return BaseIterator{bit+(it-static_cast<BaseIterator2>(bit))};
}
base_iterator base()const noexcept
{return local_iterator_impl::iterator_adaptor_::base();}
const std::type_info& type_info()const{return *mapit->first;}
segment_type& segment()noexcept
{return const_cast<segment_type&>(mapit->second);}
const segment_type& segment()const noexcept{return mapit->second;}
const_segment_map_iterator mapit;
};
template<typename PolyCollection,typename BaseIterator>
struct poly_collection_of<local_iterator_impl<PolyCollection,BaseIterator>>
{
using type=PolyCollection;
};
} /* namespace poly_collection::detail */
} /* namespace poly_collection */
} /* namespace boost */
#endif

View File

@@ -0,0 +1,116 @@
/* Copyright 2016-2017 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_ITERATOR_TRAITS_HPP
#define BOOST_POLY_COLLECTION_DETAIL_ITERATOR_TRAITS_HPP
#if defined(_MSC_VER)
#pragma once
#endif
#include <iterator>
#include <type_traits>
namespace boost{
namespace poly_collection{
namespace common_impl{
template<typename Model,typename Allocator>
class poly_collection;
}
namespace detail{
/* (Internal) bunch of traits-grouped functions for const-preserving
* interoperatibility between iterators and local iterators of a
* poly_collection.
*/
template<typename Iterator>
struct poly_collection_of /* to be specialized for iterator impls */
{
using type=void;
};
template<typename PolyCollection>
struct model_of;
template<typename Model,typename Allocator>
struct model_of<common_impl::poly_collection<Model,Allocator>>
{
using type=Model;
};
template<typename Iterator>
struct iterator_traits
{
using container_type=typename poly_collection_of<Iterator>::type;
using is_const_iterator=typename std::is_const<
typename std::remove_reference<
typename std::iterator_traits<Iterator>::reference
>::type
>::type;
using iterator=typename std::conditional<
is_const_iterator::value,
typename container_type::const_iterator,
typename container_type::iterator
>::type;
using base_segment_info_iterator=typename std::conditional<
is_const_iterator::value,
typename container_type::const_base_segment_info_iterator,
typename container_type::base_segment_info_iterator
>::type;
using local_base_iterator=typename std::conditional<
is_const_iterator::value,
typename container_type::const_local_base_iterator,
typename container_type::local_base_iterator
>::type;
template<typename T>
using local_iterator=typename std::conditional<
is_const_iterator::value,
typename container_type::template const_local_iterator<T>,
typename container_type::template local_iterator<T>
>::type;
static base_segment_info_iterator
base_segment_info_iterator_from(iterator it)noexcept{return it.mapit;}
static base_segment_info_iterator
base_segment_info_iterator_from(local_base_iterator it)noexcept
{return it.mapit;}
static base_segment_info_iterator
end_base_segment_info_iterator_from(iterator it)noexcept{return it.mapend;}
static local_base_iterator
local_base_iterator_from(iterator it)noexcept
{
return {
it.mapit,
model_of<container_type>::type::nonconst_iterator(it.segpos)
};
}
static iterator
iterator_from(
local_base_iterator lbit,base_segment_info_iterator mapend)noexcept
{
return {lbit.mapit,mapend.base(),lbit.base()};
}
};
} /* namespace poly_collection::detail */
} /* namespace poly_collection */
} /* namespace boost */
#endif

View File

@@ -0,0 +1,338 @@
/* Copyright 2016-2020 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_PACKED_SEGMENT_HPP
#define BOOST_POLY_COLLECTION_DETAIL_PACKED_SEGMENT_HPP
#if defined(_MSC_VER)
#pragma once
#endif
#include <boost/detail/workaround.hpp>
#include <boost/poly_collection/detail/segment_backend.hpp>
#include <boost/poly_collection/detail/value_holder.hpp>
#include <memory>
#include <new>
#include <vector>
#include <utility>
namespace boost{
namespace poly_collection{
namespace detail{
/* segment_backend implementation where value_type& and Concrete& actually refer
* to the same stored entity.
*
* Requires:
* - [const_]base_iterator is a stride iterator constructible from
* {value_type*,sizeof(store_value_type)}.
* - Model provides a function value_ptr for
* const Concrete* -> const value_type* conversion.
*/
template<typename Model,typename Concrete,typename Allocator>
class packed_segment:public segment_backend<Model,Allocator>
{
using value_type=typename Model::value_type;
using store_value_type=value_holder<Concrete>;
using store=std::vector<
store_value_type,
typename std::allocator_traits<Allocator>::
template rebind_alloc<store_value_type>
>;
using store_iterator=typename store::iterator;
using const_store_iterator=typename store::const_iterator;
using segment_backend=detail::segment_backend<Model,Allocator>;
using typename segment_backend::segment_backend_unique_ptr;
using typename segment_backend::value_pointer;
using typename segment_backend::const_value_pointer;
using typename segment_backend::base_iterator;
using typename segment_backend::const_base_iterator;
using const_iterator=
typename segment_backend::template const_iterator<Concrete>;
using typename segment_backend::base_sentinel;
using typename segment_backend::range;
using segment_allocator_type=typename std::allocator_traits<Allocator>::
template rebind_alloc<packed_segment>;
public:
virtual ~packed_segment()=default;
static segment_backend_unique_ptr make(const segment_allocator_type& al)
{
return new_(al,al);
}
virtual segment_backend_unique_ptr copy()const
{
return new_(s.get_allocator(),store{s});
}
virtual segment_backend_unique_ptr copy(const Allocator& al)const
{
return new_(al,store{s,al});
}
virtual segment_backend_unique_ptr empty_copy(const Allocator& al)const
{
return new_(al,al);
}
virtual segment_backend_unique_ptr move(const Allocator& al)
{
return new_(al,store{std::move(s),al});
}
virtual bool equal(const segment_backend& x)const
{
return s==static_cast<const packed_segment&>(x).s;
}
virtual Allocator get_allocator()const noexcept{return s.get_allocator();}
virtual base_iterator begin()const noexcept{return nv_begin();}
base_iterator nv_begin()const noexcept
{
return {value_ptr(s.data()),sizeof(store_value_type)};
}
virtual base_iterator end()const noexcept{return nv_end();}
base_iterator nv_end()const noexcept
{
return {value_ptr(s.data()+s.size()),sizeof(store_value_type)};
}
virtual bool empty()const noexcept{return nv_empty();}
bool nv_empty()const noexcept{return s.empty();}
virtual std::size_t size()const noexcept{return nv_size();}
std::size_t nv_size()const noexcept{return s.size();}
virtual std::size_t max_size()const noexcept{return nv_max_size();}
std::size_t nv_max_size()const noexcept{return s.max_size();}
virtual std::size_t capacity()const noexcept{return nv_capacity();}
std::size_t nv_capacity()const noexcept{return s.capacity();}
virtual base_sentinel reserve(std::size_t n){return nv_reserve(n);}
base_sentinel nv_reserve(std::size_t n)
{s.reserve(n);return sentinel();}
virtual base_sentinel shrink_to_fit(){return nv_shrink_to_fit();}
base_sentinel nv_shrink_to_fit()
{s.shrink_to_fit();return sentinel();}
template<typename Iterator,typename... Args>
range nv_emplace(Iterator p,Args&&... args)
{
return range_from(
s.emplace(
iterator_from(p),
value_holder_emplacing_ctor,std::forward<Args>(args)...));
}
template<typename... Args>
range nv_emplace_back(Args&&... args)
{
s.emplace_back(value_holder_emplacing_ctor,std::forward<Args>(args)...);
return range_from(s.size()-1);
}
virtual range push_back(const_value_pointer x)
{return nv_push_back(const_concrete_ref(x));}
range nv_push_back(const Concrete& x)
{
s.emplace_back(x);
return range_from(s.size()-1);
}
virtual range push_back_move(value_pointer x)
{return nv_push_back(std::move(concrete_ref(x)));}
range nv_push_back(Concrete&& x)
{
s.emplace_back(std::move(x));
return range_from(s.size()-1);
}
virtual range insert(const_base_iterator p,const_value_pointer x)
{return nv_insert(const_iterator(p),const_concrete_ref(x));}
range nv_insert(const_iterator p,const Concrete& x)
{
return range_from(s.emplace(iterator_from(p),x));
}
virtual range insert_move(const_base_iterator p,value_pointer x)
{return nv_insert(const_iterator(p),std::move(concrete_ref(x)));}
range nv_insert(const_iterator p,Concrete&& x)
{
return range_from(s.emplace(iterator_from(p),std::move(x)));
}
template<typename InputIterator>
range nv_insert(InputIterator first,InputIterator last)
{
return nv_insert(
const_iterator(concrete_ptr(s.data()+s.size())),first,last);
}
template<typename InputIterator>
range nv_insert(const_iterator p,InputIterator first,InputIterator last)
{
#if BOOST_WORKAROUND(BOOST_LIBSTDCXX_VERSION,<40900)
/* std::vector::insert(pos,first,last) returns void rather than iterator */
auto n=const_store_value_type_ptr(p)-s.data();
s.insert(s.begin()+n,first,last);
return range_from(static_cast<std::size_t>(n));
#else
return range_from(s.insert(iterator_from(p),first,last));
#endif
}
virtual range erase(const_base_iterator p)
{return nv_erase(const_iterator(p));}
range nv_erase(const_iterator p)
{
return range_from(s.erase(iterator_from(p)));
}
virtual range erase(const_base_iterator first,const_base_iterator last)
{return nv_erase(const_iterator(first),const_iterator(last));}
range nv_erase(const_iterator first,const_iterator last)
{
return range_from(s.erase(iterator_from(first),iterator_from(last)));
}
virtual range erase_till_end(const_base_iterator first)
{
return range_from(s.erase(iterator_from(first),s.end()));
}
virtual range erase_from_begin(const_base_iterator last)
{
return range_from(s.erase(s.begin(),iterator_from(last)));
}
virtual base_sentinel clear()noexcept{return nv_clear();}
base_sentinel nv_clear()noexcept{s.clear();return sentinel();}
private:
template<typename... Args>
static segment_backend_unique_ptr new_(
segment_allocator_type al,Args&&... args)
{
auto p=std::allocator_traits<segment_allocator_type>::allocate(al,1);
try{
::new ((void*)p) packed_segment{std::forward<Args>(args)...};
}
catch(...){
std::allocator_traits<segment_allocator_type>::deallocate(al,p,1);
throw;
}
return {p,&delete_};
}
static void delete_(segment_backend* p)
{
auto q=static_cast<packed_segment*>(p);
auto al=segment_allocator_type{q->s.get_allocator()};
q->~packed_segment();
std::allocator_traits<segment_allocator_type>::deallocate(al,q,1);
}
packed_segment(const Allocator& al):s{typename store::allocator_type{al}}{}
packed_segment(store&& s):s{std::move(s)}{}
static Concrete& concrete_ref(value_pointer p)noexcept
{
return *static_cast<Concrete*>(p);
}
static const Concrete& const_concrete_ref(const_value_pointer p)noexcept
{
return *static_cast<const Concrete*>(p);
}
static Concrete* concrete_ptr(store_value_type* p)noexcept
{
return reinterpret_cast<Concrete*>(
static_cast<value_holder_base<Concrete>*>(p));
}
static const Concrete* const_concrete_ptr(const store_value_type* p)noexcept
{
return concrete_ptr(const_cast<store_value_type*>(p));
}
static value_type* value_ptr(const store_value_type* p)noexcept
{
return const_cast<value_type*>(Model::value_ptr(const_concrete_ptr(p)));
}
static const store_value_type* const_store_value_type_ptr(
const Concrete* p)noexcept
{
return static_cast<const value_holder<Concrete>*>(
reinterpret_cast<const value_holder_base<Concrete>*>(p));
}
/* It would have sufficed if iterator_from returned const_store_iterator
* except for the fact that some old versions of libstdc++ claiming to be
* C++11 compliant do not however provide std::vector modifier ops taking
* const_iterator's.
*/
store_iterator iterator_from(const_base_iterator p)
{
return iterator_from(static_cast<const_iterator>(p));
}
store_iterator iterator_from(const_iterator p)
{
return s.begin()+(const_store_value_type_ptr(p)-s.data());
}
base_sentinel sentinel()const noexcept
{
return base_iterator{
value_ptr(s.data()+s.size()),
sizeof(store_value_type)
};
}
range range_from(const_store_iterator it)const
{
return {
{value_ptr(s.data()+(it-s.begin())),sizeof(store_value_type)},
sentinel()
};
}
range range_from(std::size_t n)const
{
return {
{value_ptr(s.data()+n),sizeof(store_value_type)},
sentinel()
};
}
store s;
};
} /* namespace poly_collection::detail */
} /* namespace poly_collection */
} /* namespace boost */
#endif

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,316 @@
/* 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_SEGMENT_HPP
#define BOOST_POLY_COLLECTION_DETAIL_SEGMENT_HPP
#if defined(_MSC_VER)
#pragma once
#endif
#include <iterator>
#include <memory>
#include <type_traits>
#include <utility>
namespace boost{
namespace poly_collection{
namespace detail{
/* segment<Model,Allocator> encapsulates implementations of
* Model::segment_backend virtual interface under a value-semantics type for
* use by poly_collection. The techique is described by Sean Parent at slides
* 157-205 of
* https://github.com/sean-parent/sean-parent.github.com/wiki/
* presentations/2013-09-11-cpp-seasoning/cpp-seasoning.pdf
* with one twist: when the type of the implementation can be known at compile
* time, a downcast is done and non-virtual member functions (named with a nv_
* prefix) are used: this increases the performance of some operations.
*/
template<typename Model,typename Allocator>
class segment
{
public:
using value_type=typename Model::value_type;
using allocator_type=Allocator; /* needed for uses-allocator construction */
using base_iterator=typename Model::base_iterator;
using const_base_iterator=typename Model::const_base_iterator;
using base_sentinel=typename Model::base_sentinel;
using const_base_sentinel=typename Model::const_base_sentinel;
template<typename T>
using iterator=typename Model::template iterator<T>;
template<typename T>
using const_iterator=typename Model::template const_iterator<T>;
template<typename T>
static segment make(const allocator_type& al)
{
return segment_backend_implementation<T>::make(al);
}
/* clones the implementation of x with no elements */
static segment make_from_prototype(const segment& x,const allocator_type& al)
{
return {from_prototype{},x,al};
}
segment(const segment& x):
pimpl{x.impl().copy()}{set_sentinel();}
segment(segment&& x)=default;
segment(const segment& x,const allocator_type& al):
pimpl{x.impl().copy(al)}{set_sentinel();}
/* TODO: try ptr-level move before impl().move() */
segment(segment&& x,const allocator_type& al):
pimpl{x.impl().move(al)}{set_sentinel();}
segment& operator=(const segment& x)
{
pimpl=allocator_traits::propagate_on_container_copy_assignment::value?
x.impl().copy():x.impl().copy(impl().get_allocator());
set_sentinel();
return *this;
}
segment& operator=(segment&& x)
{
pimpl=x.impl().move(
allocator_traits::propagate_on_container_move_assignment::value?
x.impl().get_allocator():impl().get_allocator());
set_sentinel();
return *this;
}
friend bool operator==(const segment& x,const segment& y)
{
if(typeid(*(x.pimpl))!=typeid(*(y.pimpl)))return false;
else return x.impl().equal(y.impl());
}
friend bool operator!=(const segment& x,const segment& y){return !(x==y);}
base_iterator begin()const noexcept{return impl().begin();}
template<typename U>
base_iterator begin()const noexcept{return impl<U>().nv_begin();}
base_iterator end()const noexcept{return impl().end();}
template<typename U>
base_iterator end()const noexcept{return impl<U>().nv_end();}
base_sentinel sentinel()const noexcept{return snt;}
bool empty()const noexcept{return impl().empty();}
template<typename U>
bool empty()const noexcept{return impl<U>().nv_empty();}
std::size_t size()const noexcept{return impl().size();}
template<typename U>
std::size_t size()const noexcept{return impl<U>().nv_size();}
std::size_t max_size()const noexcept{return impl().max_size();}
template<typename U>
std::size_t max_size()const noexcept
{return impl<U>().nv_max_size();}
void reserve(std::size_t n){filter(impl().reserve(n));}
template<typename U>
void reserve(std::size_t n){filter(impl<U>().nv_reserve(n));}
std::size_t capacity()const noexcept{return impl().capacity();}
template<typename U>
std::size_t capacity()const noexcept
{return impl<U>().nv_capacity();}
void shrink_to_fit(){filter(impl().shrink_to_fit());}
template<typename U>
void shrink_to_fit(){filter(impl<U>().nv_shrink_to_fit());}
template<typename U,typename Iterator,typename... Args>
base_iterator emplace(Iterator it,Args&&... args)
{
return filter(impl<U>().nv_emplace(it,std::forward<Args>(args)...));
}
template<typename U,typename... Args>
base_iterator emplace_back(Args&&... args)
{
return filter(impl<U>().nv_emplace_back(std::forward<Args>(args)...));
}
template<typename T>
base_iterator push_back(const T& x)
{
return filter(impl().push_back(subaddress(x)));
}
template<
typename T,
typename std::enable_if<
!std::is_lvalue_reference<T>::value&&!std::is_const<T>::value
>::type* =nullptr
>
base_iterator push_back(T&& x)
{
return filter(impl().push_back_move(subaddress(x)));
}
template<typename U>
base_iterator push_back_terminal(U&& x)
{
return filter(
impl<typename std::decay<U>::type>().nv_push_back(std::forward<U>(x)));
}
template<typename T>
base_iterator insert(const_base_iterator it,const T& x)
{
return filter(impl().insert(it,subaddress(x)));
}
template<typename U,typename T>
base_iterator insert(const_iterator<U> it,const T& x)
{
return filter(
impl<U>().nv_insert(it,*static_cast<const U*>(subaddress(x))));
}
template<
typename T,
typename std::enable_if<
!std::is_lvalue_reference<T>::value&&!std::is_const<T>::value
>::type* =nullptr
>
base_iterator insert(const_base_iterator it,T&& x)
{
return filter(impl().insert_move(it,subaddress(x)));
}
template<
typename U,typename T,
typename std::enable_if<
!std::is_lvalue_reference<T>::value&&!std::is_const<T>::value
>::type* =nullptr
>
base_iterator insert(const_iterator<U> it,T&& x)
{
return filter(
impl<U>().nv_insert(it,std::move(*static_cast<U*>(subaddress(x)))));
}
template<typename InputIterator>
base_iterator insert(InputIterator first,InputIterator last)
{
return filter(
impl<typename std::iterator_traits<InputIterator>::value_type>().
nv_insert(first,last));
}
template<typename InputIterator>
base_iterator insert(
const_base_iterator it,InputIterator first,InputIterator last)
{
return insert(
const_iterator<
typename std::iterator_traits<InputIterator>::value_type>(it),
first,last);
}
template<typename U,typename InputIterator>
base_iterator insert(
const_iterator<U> it,InputIterator first,InputIterator last)
{
return filter(impl<U>().nv_insert(it,first,last));
}
base_iterator erase(const_base_iterator it)
{
return filter(impl().erase(it));
}
template<typename U>
base_iterator erase(const_iterator<U> it)
{
return filter(impl<U>().nv_erase(it));
}
base_iterator erase(const_base_iterator f,const_base_iterator l)
{
return filter(impl().erase(f,l));
}
template<typename U>
base_iterator erase(const_iterator<U> f,const_iterator<U> l)
{
return filter(impl<U>().nv_erase(f,l));
}
template<typename Iterator>
base_iterator erase_till_end(Iterator f)
{
return filter(impl().erase_till_end(f));
}
template<typename Iterator>
base_iterator erase_from_begin(Iterator l)
{
return filter(impl().erase_from_begin(l));
}
void clear()noexcept{filter(impl().clear());}
template<typename U>
void clear()noexcept{filter(impl<U>().nv_clear());}
private:
using allocator_traits=std::allocator_traits<Allocator>;
using segment_backend=typename Model::template segment_backend<Allocator>;
template<typename Concrete>
using segment_backend_implementation=typename Model::
template segment_backend_implementation<Concrete,Allocator>;
using segment_backend_unique_ptr=
typename segment_backend::segment_backend_unique_ptr;
using range=typename segment_backend::range;
struct from_prototype{};
segment(segment_backend_unique_ptr&& pimpl):
pimpl{std::move(pimpl)}{set_sentinel();}
segment(from_prototype,const segment& x,const allocator_type& al):
pimpl{x.impl().empty_copy(al)}{set_sentinel();}
segment_backend& impl()noexcept{return *pimpl;}
const segment_backend& impl()const noexcept{return *pimpl;}
template<typename Concrete>
segment_backend_implementation<Concrete>& impl()noexcept
{
return static_cast<segment_backend_implementation<Concrete>&>(impl());
}
template<typename Concrete>
const segment_backend_implementation<Concrete>& impl()const noexcept
{
return
static_cast<const segment_backend_implementation<Concrete>&>(impl());
}
template<typename T>
static void* subaddress(T& x){return Model::subaddress(x);}
template<typename T>
static const void* subaddress(const T& x){return Model::subaddress(x);}
void set_sentinel(){filter(impl().end());}
void filter(base_sentinel x){snt=x;}
base_iterator filter(const range& x){snt=x.second;return x.first;}
segment_backend_unique_ptr pimpl;
base_sentinel snt;
};
} /* namespace poly_collection::detail */
} /* namespace poly_collection */
} /* namespace boost */
#endif

View File

@@ -0,0 +1,85 @@
/* Copyright 2016-2020 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_SEGMENT_BACKEND_HPP
#define BOOST_POLY_COLLECTION_DETAIL_SEGMENT_BACKEND_HPP
#if defined(_MSC_VER)
#pragma once
#endif
#include <cstddef>
#include <memory>
#include <utility>
namespace boost{
namespace poly_collection{
namespace detail{
/* Internal *virtual* interface of segment<Model,Allocator> (please note that
* a non-virtual interface exists accessible through downcasting). Member
* functions have been defined to minimize virtual function calls according to
* usage patterns by poly_collection. For instance, ranges are returned rather
* than iterators to allow for caching of and end sentinel at a higher level.
* Passed elements are type erased with [const_]value_pointer.
*/
template<typename Model,typename Allocator>
struct segment_backend
{
using segment_backend_unique_ptr=
std::unique_ptr<segment_backend,void(*)(segment_backend*)>;
using value_pointer=void*;
using const_value_pointer=const void*;
using base_iterator=typename Model::base_iterator;
using const_base_iterator=typename Model::const_base_iterator;
template<typename T>
using const_iterator=typename Model::template const_iterator<T>;
using base_sentinel=typename Model::base_sentinel;
using range=std::pair<base_iterator,base_sentinel>;
segment_backend()=default;
segment_backend(const segment_backend&)=delete;
segment_backend& operator=(const segment_backend&)=delete;
virtual ~segment_backend()=default;
virtual segment_backend_unique_ptr copy()const=0;
virtual segment_backend_unique_ptr copy(const Allocator&)const=0;
virtual segment_backend_unique_ptr empty_copy(const Allocator&)const=0;
virtual segment_backend_unique_ptr move(const Allocator&)=0;
virtual bool equal(const segment_backend&)const=0;
virtual Allocator get_allocator()const noexcept=0;
virtual base_iterator begin()const noexcept=0;
virtual base_iterator end()const noexcept=0;
virtual bool empty()const noexcept=0;
virtual std::size_t size()const noexcept=0;
virtual std::size_t max_size()const noexcept=0;
virtual std::size_t capacity()const noexcept=0;
virtual base_sentinel reserve(std::size_t)=0;
virtual base_sentinel shrink_to_fit()=0;
virtual range push_back(const_value_pointer)=0;
virtual range push_back_move(value_pointer)=0;
virtual range insert(const_base_iterator,const_value_pointer)=0;
virtual range insert_move(const_base_iterator,value_pointer)=0;
virtual range erase(const_base_iterator)=0;
virtual range erase(const_base_iterator,const_base_iterator)=0;
virtual range erase_till_end(const_base_iterator)=0;
virtual range erase_from_begin(const_base_iterator)=0;
virtual base_sentinel clear()noexcept=0;
};
} /* namespace poly_collection::detail */
} /* namespace poly_collection */
} /* namespace boost */
#endif

View File

@@ -0,0 +1,154 @@
/* Copyright 2016-2017 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_SEGMENT_SPLIT_HPP
#define BOOST_POLY_COLLECTION_DETAIL_SEGMENT_SPLIT_HPP
#if defined(_MSC_VER)
#pragma once
#endif
#include <boost/iterator/iterator_facade.hpp>
#include <boost/poly_collection/detail/iterator_traits.hpp>
#include <typeinfo>
#include <utility>
namespace boost{
namespace poly_collection{
namespace detail{
/* breakdown of an iterator range into local_base_iterator segments */
template<typename PolyCollectionIterator>
class segment_splitter
{
using traits=iterator_traits<PolyCollectionIterator>;
using local_base_iterator=typename traits::local_base_iterator;
using base_segment_info_iterator=typename traits::base_segment_info_iterator;
public:
struct info
{
const std::type_info& type_info()const noexcept{return *pinfo_;}
local_base_iterator begin()const noexcept{return begin_;}
local_base_iterator end()const noexcept{return end_;}
const std::type_info* pinfo_;
local_base_iterator begin_,end_;
};
struct iterator:iterator_facade<iterator,info,std::input_iterator_tag,info>
{
iterator()=default;
private:
friend class segment_splitter;
friend class boost::iterator_core_access;
iterator(
base_segment_info_iterator it,
const PolyCollectionIterator& first,const PolyCollectionIterator& last):
it{it},pfirst{&first},plast{&last}{}
iterator(
const PolyCollectionIterator& first,const PolyCollectionIterator& last):
it{traits::base_segment_info_iterator_from(first)},
pfirst{&first},plast{&last}
{}
info dereference()const noexcept
{
return {
&it->type_info(),
it==traits::base_segment_info_iterator_from(*pfirst)?
traits::local_base_iterator_from(*pfirst):it->begin(),
it==traits::base_segment_info_iterator_from(*plast)?
traits::local_base_iterator_from(*plast):it->end()
};
}
bool equal(const iterator& x)const noexcept{return it==x.it;}
void increment()noexcept{++it;}
base_segment_info_iterator it;
const PolyCollectionIterator* pfirst;
const PolyCollectionIterator* plast;
};
segment_splitter(
const PolyCollectionIterator& first,const PolyCollectionIterator& last):
pfirst{&first},plast{&last}{}
iterator begin()const noexcept{return {*pfirst,*plast};}
iterator end()const noexcept
{
auto slast=traits::base_segment_info_iterator_from(*plast);
if(slast!=traits::end_base_segment_info_iterator_from(*plast))++slast;
return {slast,*plast,*plast};
}
private:
const PolyCollectionIterator* pfirst;
const PolyCollectionIterator* plast;
};
template<typename PolyCollectionIterator>
segment_splitter<PolyCollectionIterator>
segment_split(
const PolyCollectionIterator& first,const PolyCollectionIterator& last)
{
return {first,last};
}
#if 1
/* equivalent to for(auto i:segment_split(first,last))f(i) */
template<typename PolyCollectionIterator,typename F>
void for_each_segment(
const PolyCollectionIterator& first,const PolyCollectionIterator& last,F&& f)
{
using traits=iterator_traits<PolyCollectionIterator>;
using info=typename segment_splitter<PolyCollectionIterator>::info;
auto sfirst=traits::base_segment_info_iterator_from(first),
slast=traits::base_segment_info_iterator_from(last),
send=traits::end_base_segment_info_iterator_from(last);
auto lbfirst=traits::local_base_iterator_from(first),
lblast=traits::local_base_iterator_from(last);
if(sfirst!=slast){
for(;;){
f(info{&sfirst->type_info(),lbfirst,sfirst->end()});
++sfirst;
if(sfirst==slast)break;
lbfirst=sfirst->begin();
}
if(sfirst!=send)f(info{&sfirst->type_info(),sfirst->begin(),lblast});
}
else if(sfirst!=send){
f(info{&sfirst->type_info(),lbfirst,lblast});
}
}
#else
template<typename PolyCollectionIterator,typename F>
void for_each_segment(
const PolyCollectionIterator& first,const PolyCollectionIterator& last,F&& f)
{
for(auto i:segment_split(first,last))f(i);
}
#endif
} /* namespace poly_collection::detail */
} /* namespace poly_collection */
} /* namespace boost */
#endif

View File

@@ -0,0 +1,510 @@
/* Copyright 2016-2020 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_SPLIT_SEGMENT_HPP
#define BOOST_POLY_COLLECTION_DETAIL_SPLIT_SEGMENT_HPP
#if defined(_MSC_VER)
#pragma once
#endif
#include <boost/poly_collection/detail/segment_backend.hpp>
#include <boost/poly_collection/detail/value_holder.hpp>
#include <iterator>
#include <memory>
#include <new>
#include <utility>
#include <vector>
namespace boost{
namespace poly_collection{
namespace detail{
/* segment_backend implementation that maintains two internal vectors, one for
* value_type's (the index) and another for the concrete elements those refer
* to (the store).
*
* Requires:
* - [const_]base_iterator is constructible from value_type*.
* - value_type is copy constructible.
* - Model::make_value_type(x) returns a value_type created from a reference
* to the concrete type.
*
* Conversion from base_iterator to local_iterator<Concrete> requires accesing
* value_type internal info, so the end() base_iterator has to be made to point
* to a valid element of index, which implies size(index)=size(store)+1. This
* slightly complicates the memory management.
*/
template<typename Model,typename Concrete,typename Allocator>
class split_segment:public segment_backend<Model,Allocator>
{
using value_type=typename Model::value_type;
using store_value_type=value_holder<Concrete>;
using store=std::vector<
store_value_type,
typename std::allocator_traits<Allocator>::
template rebind_alloc<store_value_type>
>;
using store_iterator=typename store::iterator;
using const_store_iterator=typename store::const_iterator;
using index=std::vector<
value_type,
typename std::allocator_traits<Allocator>::
template rebind_alloc<value_type>
>;
using const_index_iterator=typename index::const_iterator;
using segment_backend=detail::segment_backend<Model,Allocator>;
using typename segment_backend::segment_backend_unique_ptr;
using typename segment_backend::value_pointer;
using typename segment_backend::const_value_pointer;
using typename segment_backend::base_iterator;
using typename segment_backend::const_base_iterator;
using const_iterator=
typename segment_backend::template const_iterator<Concrete>;
using typename segment_backend::base_sentinel;
using typename segment_backend::range;
using segment_allocator_type=typename std::allocator_traits<Allocator>::
template rebind_alloc<split_segment>;
public:
virtual ~split_segment()=default;
static segment_backend_unique_ptr make(const segment_allocator_type& al)
{
return new_(al,al);
}
virtual segment_backend_unique_ptr copy()const
{
return new_(s.get_allocator(),store{s});
}
virtual segment_backend_unique_ptr copy(const Allocator& al)const
{
return new_(al,store{s,al});
}
virtual segment_backend_unique_ptr empty_copy(const Allocator& al)const
{
return new_(al,al);
}
virtual segment_backend_unique_ptr move(const Allocator& al)
{
return new_(al,store{std::move(s),al});
}
virtual bool equal(const segment_backend& x)const
{
return s==static_cast<const split_segment&>(x).s;
}
virtual Allocator get_allocator()const noexcept
{return s.get_allocator();}
virtual base_iterator begin()const noexcept{return nv_begin();}
base_iterator nv_begin()const noexcept
{return base_iterator{value_ptr(i.data())};}
virtual base_iterator end()const noexcept{return nv_end();}
base_iterator nv_end()const noexcept
{return base_iterator{value_ptr(i.data()+s.size())};}
virtual bool empty()const noexcept{return nv_empty();}
bool nv_empty()const noexcept{return s.empty();}
virtual std::size_t size()const noexcept{return nv_size();}
std::size_t nv_size()const noexcept{return s.size();}
virtual std::size_t max_size()const noexcept{return nv_max_size();}
std::size_t nv_max_size()const noexcept{return s.max_size()-1;}
virtual std::size_t capacity()const noexcept{return nv_capacity();}
std::size_t nv_capacity()const noexcept{return s.capacity();}
virtual base_sentinel reserve(std::size_t n){return nv_reserve(n);}
base_sentinel nv_reserve(std::size_t n)
{
bool rebuild=n>s.capacity();
i.reserve(n+1);
s.reserve(n);
if(rebuild)rebuild_index();
return sentinel();
};
virtual base_sentinel shrink_to_fit(){return nv_shrink_to_fit();}
base_sentinel nv_shrink_to_fit()
{
try{
auto p=s.data();
if(!s.empty())s.shrink_to_fit();
else{
store ss{s.get_allocator()};
ss.reserve(1); /* --> s.data()!=nullptr */
s.swap(ss);
}
if(p!=s.data()){
index ii{{},i.get_allocator()};
ii.reserve(s.capacity()+1);
i.swap(ii);
build_index();
}
}
catch(...){
rebuild_index();
throw;
}
return sentinel();
}
template<typename Iterator,typename... Args>
range nv_emplace(Iterator p,Args&&... args)
{
auto q=prereserve(p);
auto it=s.emplace(
iterator_from(q),
value_holder_emplacing_ctor,std::forward<Args>(args)...);
push_index_entry();
return range_from(it);
}
template<typename... Args>
range nv_emplace_back(Args&&... args)
{
prereserve();
s.emplace_back(value_holder_emplacing_ctor,std::forward<Args>(args)...);
push_index_entry();
return range_from(s.size()-1);
}
virtual range push_back(const_value_pointer x)
{return nv_push_back(const_concrete_ref(x));}
range nv_push_back(const Concrete& x)
{
prereserve();
s.emplace_back(x);
push_index_entry();
return range_from(s.size()-1);
}
virtual range push_back_move(value_pointer x)
{return nv_push_back(std::move(concrete_ref(x)));}
range nv_push_back(Concrete&& x)
{
prereserve();
s.emplace_back(std::move(x));
push_index_entry();
return range_from(s.size()-1);
}
virtual range insert(const_base_iterator p,const_value_pointer x)
{return nv_insert(const_iterator(p),const_concrete_ref(x));}
range nv_insert(const_iterator p,const Concrete& x)
{
p=prereserve(p);
auto it=s.emplace(iterator_from(p),x);
push_index_entry();
return range_from(it);
}
virtual range insert_move(const_base_iterator p,value_pointer x)
{return nv_insert(const_iterator(p),std::move(concrete_ref(x)));}
range nv_insert(const_iterator p,Concrete&& x)
{
p=prereserve(p);
auto it=s.emplace(iterator_from(p),std::move(x));
push_index_entry();
return range_from(it);
}
template<typename InputIterator>
range nv_insert(InputIterator first,InputIterator last)
{
return nv_insert(
const_iterator(concrete_ptr(s.data()+s.size())),first,last);
}
template<typename InputIterator>
range nv_insert(const_iterator p,InputIterator first,InputIterator last)
{
return insert(
p,first,last,
typename std::iterator_traits<InputIterator>::iterator_category{});
}
virtual range erase(const_base_iterator p)
{return nv_erase(const_iterator(p));}
range nv_erase(const_iterator p)
{
pop_index_entry();
return range_from(s.erase(iterator_from(p)));
}
virtual range erase(const_base_iterator first,const_base_iterator last)
{return nv_erase(const_iterator(first),const_iterator(last));}
range nv_erase(const_iterator first,const_iterator last)
{
std::size_t n=s.size();
auto it=s.erase(iterator_from(first),iterator_from(last));
pop_index_entry(n-s.size());
return range_from(it);
}
virtual range erase_till_end(const_base_iterator first)
{
std::size_t n=s.size();
auto it=s.erase(iterator_from(first),s.end());
pop_index_entry(n-s.size());
return range_from(it);
}
virtual range erase_from_begin(const_base_iterator last)
{
std::size_t n=s.size();
auto it=s.erase(s.begin(),iterator_from(last));
pop_index_entry(n-s.size());
return range_from(it);
}
base_sentinel clear()noexcept{return nv_clear();}
base_sentinel nv_clear()noexcept
{
s.clear();
for(std::size_t n=i.size()-1;n--;)i.pop_back();
return sentinel();
}
private:
template<typename... Args>
static segment_backend_unique_ptr new_(
segment_allocator_type al,Args&&... args)
{
auto p=std::allocator_traits<segment_allocator_type>::allocate(al,1);
try{
::new ((void*)p) split_segment{std::forward<Args>(args)...};
}
catch(...){
std::allocator_traits<segment_allocator_type>::deallocate(al,p,1);
throw;
}
return {p,&delete_};
}
static void delete_(segment_backend* p)
{
auto q=static_cast<split_segment*>(p);
auto al=segment_allocator_type{q->s.get_allocator()};
q->~split_segment();
std::allocator_traits<segment_allocator_type>::deallocate(al,q,1);
}
split_segment(const Allocator& al):
s{typename store::allocator_type{al}},
i{{},typename index::allocator_type{al}}
{
s.reserve(1); /* --> s.data()!=nullptr */
build_index();
}
split_segment(store&& s_):
s{std::move(s_)},i{{},typename index::allocator_type{s.get_allocator()}}
{
s.reserve(1); /* --> s.data()!=nullptr */
build_index();
}
void prereserve()
{
if(s.size()==s.capacity())expand();
}
const_base_iterator prereserve(const_base_iterator p)
{
if(s.size()==s.capacity()){
auto n=p-i.data();
expand();
return const_base_iterator{i.data()+n};
}
else return p;
}
const_iterator prereserve(const_iterator p)
{
if(s.size()==s.capacity()){
auto n=p-const_concrete_ptr(s.data());
expand();
return const_concrete_ptr(s.data())+n;
}
else return p;
}
const_iterator prereserve(const_iterator p,std::size_t m)
{
if(s.size()+m>s.capacity()){
auto n=p-const_concrete_ptr(s.data());
expand(m);
return const_concrete_ptr(s.data())+n;
}
else return p;
}
void expand()
{
std::size_t c=
s.size()<=1||(s.max_size()-1-s.size())/2<s.size()?
s.size()+1:
s.size()+s.size()/2;
i.reserve(c+1);
s.reserve(c);
rebuild_index();
}
void expand(std::size_t m)
{
i.reserve(s.size()+m+1);
s.reserve(s.size()+m);
rebuild_index();
}
void build_index(std::size_t start=0)
{
for(std::size_t n=start,m=s.size();n<=m;++n){
i.push_back(Model::make_value_type(concrete_ref(s.data()[n])));
};
}
void rebuild_index()
{
i.clear();
build_index();
}
void push_index_entry()
{
build_index(s.size());
}
void pop_index_entry(std::size_t n=1)
{
while(n--)i.pop_back();
}
static Concrete& concrete_ref(value_pointer p)noexcept
{
return *static_cast<Concrete*>(p);
}
static Concrete& concrete_ref(store_value_type& r)noexcept
{
return *concrete_ptr(&r);
}
static const Concrete& const_concrete_ref(const_value_pointer p)noexcept
{
return *static_cast<const Concrete*>(p);
}
static Concrete* concrete_ptr(store_value_type* p)noexcept
{
return reinterpret_cast<Concrete*>(
static_cast<value_holder_base<Concrete>*>(p));
}
static const Concrete* const_concrete_ptr(const store_value_type* p)noexcept
{
return concrete_ptr(const_cast<store_value_type*>(p));
}
static value_type* value_ptr(const value_type* p)noexcept
{
return const_cast<value_type*>(p);
}
/* It would have sufficed if iterator_from returned const_store_iterator
* except for the fact that some old versions of libstdc++ claiming to be
* C++11 compliant do not however provide std::vector modifier ops taking
* const_iterator's.
*/
store_iterator iterator_from(const_base_iterator p)
{
return s.begin()+(p-i.data());
}
store_iterator iterator_from(const_iterator p)
{
return s.begin()+(p-const_concrete_ptr(s.data()));
}
base_sentinel sentinel()const noexcept
{
return base_iterator{value_ptr(i.data()+s.size())};
}
range range_from(const_store_iterator it)const
{
return {base_iterator{value_ptr(i.data()+(it-s.begin()))},sentinel()};
}
range range_from(std::size_t n)const
{
return {base_iterator{value_ptr(i.data()+n)},sentinel()};
}
template<typename InputIterator>
range insert(
const_iterator p,InputIterator first,InputIterator last,
std::input_iterator_tag)
{
std::size_t n=0;
for(;first!=last;++first,++n,++p){
p=prereserve(p);
s.emplace(iterator_from(p),*first);
push_index_entry();
}
return range_from(iterator_from(p-n));
}
template<typename InputIterator>
range insert(
const_iterator p,InputIterator first,InputIterator last,
std::forward_iterator_tag)
{
auto n=s.size();
auto m=static_cast<std::size_t>(std::distance(first,last));
if(m){
p=prereserve(p,m);
try{
s.insert(iterator_from(p),first,last);
}
catch(...){
build_index(n+1);
throw;
}
build_index(n+1);
}
return range_from(iterator_from(p));
}
store s;
index i;
};
} /* namespace poly_collection::detail */
} /* namespace poly_collection */
} /* namespace boost */
#endif

View File

@@ -0,0 +1,155 @@
/* Copyright 2016-2019 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_STRIDE_ITERATOR_HPP
#define BOOST_POLY_COLLECTION_DETAIL_STRIDE_ITERATOR_HPP
#if defined(_MSC_VER)
#pragma once
#endif
#include <boost/detail/workaround.hpp>
#include <boost/iterator/iterator_facade.hpp>
#include <type_traits>
namespace boost{
namespace poly_collection{
namespace detail{
/* random-access iterator to Value elements laid out stride *chars* apart */
template<typename Value>
class stride_iterator:
public boost::iterator_facade<
stride_iterator<Value>,
Value,
boost::random_access_traversal_tag
>
{
public:
stride_iterator()=default;
stride_iterator(Value* p,std::size_t stride)noexcept:p{p},stride_{stride}{}
stride_iterator(const stride_iterator&)=default;
stride_iterator& operator=(const stride_iterator&)=default;
template<
typename NonConstValue,
typename std::enable_if<
std::is_same<Value,const NonConstValue>::value>::type* =nullptr
>
stride_iterator(const stride_iterator<NonConstValue>& x)noexcept:
p{x.p},stride_{x.stride_}{}
template<
typename NonConstValue,
typename std::enable_if<
std::is_same<Value,const NonConstValue>::value>::type* =nullptr
>
stride_iterator& operator=(const stride_iterator<NonConstValue>& x)noexcept
{
p=x.p;stride_=x.stride_;
return *this;
}
/* interoperability with [Derived]Value* */
stride_iterator& operator=(Value* p_)noexcept{p=p_;return *this;}
operator Value*()const noexcept{return p;}
template<
typename DerivedValue,
typename std::enable_if<
std::is_base_of<Value,DerivedValue>::value&&
(std::is_const<Value>::value||!std::is_const<DerivedValue>::value)
>::type* =nullptr
>
explicit stride_iterator(DerivedValue* x)noexcept:
p{x},stride_{sizeof(DerivedValue)}{}
#if BOOST_WORKAROUND(BOOST_GCC_VERSION,>=40900)||\
BOOST_WORKAROUND(BOOST_CLANG,>=1)&&\
(__clang_major__>3 || __clang_major__==3 && __clang_minor__ >= 8)
/* https://github.com/boostorg/poly_collection/issues/15 */
#define BOOST_POLY_COLLECTION_NO_SANITIZE
/* UBSan seems not to be supported in some environments */
#if defined(BOOST_GCC_VERSION)
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wattributes"
#elif defined(BOOST_CLANG)
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wattributes"
#endif
#endif
template<
typename DerivedValue,
typename std::enable_if<
std::is_base_of<Value,DerivedValue>::value&&
(!std::is_const<Value>::value||std::is_const<DerivedValue>::value)
>::type* =nullptr
>
#if defined(BOOST_POLY_COLLECTION_NO_SANITIZE)
__attribute__((no_sanitize("undefined")))
#endif
explicit operator DerivedValue*()const noexcept
{return static_cast<DerivedValue*>(p);}
#if defined(BOOST_POLY_COLLECTION_NO_SANITIZE)
#if defined(BOOST_GCC_VERSION)
#pragma GCC diagnostic pop
#elif defined(BOOST_CLANG)
#pragma clang diagnostic pop
#endif
#undef BOOST_POLY_COLLECTION_NO_SANITIZE
#endif
std::size_t stride()const noexcept{return stride_;}
private:
template<typename>
friend class stride_iterator;
using char_pointer=typename std::conditional<
std::is_const<Value>::value,
const char*,
char*
>::type;
static char_pointer char_ptr(Value* p)noexcept
{return reinterpret_cast<char_pointer>(p);}
static Value* value_ptr(char_pointer p)noexcept
{return reinterpret_cast<Value*>(p);}
friend class boost::iterator_core_access;
Value& dereference()const noexcept{return *p;}
bool equal(const stride_iterator& x)const noexcept{return p==x.p;}
void increment()noexcept{p=value_ptr(char_ptr(p)+stride_);}
void decrement()noexcept{p=value_ptr(char_ptr(p)-stride_);}
template<typename Integral>
void advance(Integral n)noexcept
{p=value_ptr(char_ptr(p)+n*(std::ptrdiff_t)stride_);}
std::ptrdiff_t distance_to(const stride_iterator& x)const noexcept
{return (char_ptr(x.p)-char_ptr(p))/(std::ptrdiff_t)stride_;}
Value* p;
std::size_t stride_;
};
} /* namespace poly_collection::detail */
} /* namespace poly_collection */
} /* namespace boost */
#endif

View File

@@ -0,0 +1,258 @@
/* Copyright 2016-2020 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_TYPE_INFO_MAP_HPP
#define BOOST_POLY_COLLECTION_DETAIL_TYPE_INFO_MAP_HPP
#if defined(_MSC_VER)
#pragma once
#endif
#include <boost/detail/workaround.hpp>
#include <functional>
#include <iterator>
#include <memory>
#include <type_traits>
#include <typeinfo>
#include <unordered_map>
#include <utility>
namespace boost{
namespace poly_collection{
namespace detail{
/* To cope with dynamic modules/libs, the standard allows for different
* std::type_info instances to describe the same type, which implies that
* std::type_info::operator== and std::type_info::hash_code are costly
* operations typically relying on the stored type name.
* type_info_ptr_hash<T> behaves roughly as a
* std::unordered_map<std::type_index,T> but maintains an internal cache of
* passed std::type_info instances so that lookup is performed (when there's a
* cache hit) without invoking std::type_info equality and hashing ops.
*/
struct type_info_ptr_hash
{
std::size_t operator()(const std::type_info* p)const noexcept
{return p->hash_code();}
};
struct type_info_ptr_equal_to
{
bool operator()(
const std::type_info* p,const std::type_info* q)const noexcept
{return *p==*q;}
};
template<typename T,typename Allocator>
class type_info_map
{
using map_type=std::unordered_map<
const std::type_info*,T,
type_info_ptr_hash,type_info_ptr_equal_to,
typename std::allocator_traits<Allocator>::template
rebind_alloc<std::pair<const std::type_info* const,T>>
>;
public:
using key_type=std::type_info;
using mapped_type=T;
using value_type=typename map_type::value_type;
using allocator_type=typename map_type::allocator_type;
using iterator=typename map_type::iterator;
using const_iterator=typename map_type::const_iterator;
type_info_map()=default;
type_info_map(const type_info_map& x):
map{x.map},
cache{make<cache_type>(std::allocator_traits<cache_allocator_type>::
select_on_container_copy_construction(x.cache.get_allocator()))}
{build_cache(x.cache);}
type_info_map(type_info_map&& x)=default;
type_info_map(const allocator_type& al):
map{make<map_type>(al)},cache{make<cache_type>(al)}{}
type_info_map(const type_info_map& x,const allocator_type& al):
map{make(x.map,al)},cache{make<cache_type>(al)}
{build_cache(x.cache);}
type_info_map(type_info_map&& x,const allocator_type& al):
map{make(std::move(x.map),al)},
cache{
al==allocator_type{x.map.get_allocator()}&&x.map.empty()?
make(std::move(x.cache),al):
make<cache_type>(al)
}
{
if(!(al==allocator_type{x.map.get_allocator()}&&x.map.empty())){
build_cache(x.cache);
}
x.map.clear();
x.cache.clear();
}
type_info_map& operator=(const type_info_map& x)
{
if(this!=&x)try{
map=x.map;
cache=make<cache_type>(map.get_allocator());
build_cache(x.cache);
}
catch(...){
map.clear();
cache.clear();
throw;
}
return *this;
}
type_info_map& operator=(type_info_map&& x)
{
if(this!=&x)try{
map=std::move(x.map);
if(map.get_allocator()==x.map.get_allocator()){
cache=std::move(x.cache);
}
else{
cache=make<cache_type>(map.get_allocator());
build_cache(x.cache);
x.cache.clear();
}
}
catch(...){
map.clear();
cache.clear();
x.map.clear();
x.cache.clear();
throw;
}
return *this;
}
allocator_type get_allocator()const noexcept{return map.get_allocator();}
iterator begin()noexcept{return map.begin();}
iterator end()noexcept{return map.end();}
const_iterator begin()const noexcept{return map.begin();}
const_iterator end()const noexcept{return map.end();}
const_iterator cbegin()const noexcept{return map.cbegin();}
const_iterator cend()const noexcept{return map.cend();}
iterator find(const key_type& key)
{
auto cit=cache.find(&key);
if(cit!=cache.end())return cit->second;
auto mit=map.find(&key);
if(mit!=map.end())cache.insert({&key,mit});
return mit;
}
const_iterator find(const key_type& key)const
{
auto cit=cache.find(&key);
if(cit!=cache.end())return cit->second;
return map.find(&key);
}
template<typename P>
std::pair<iterator,bool> insert(const key_type& key,P&& x)
{
auto c=map.bucket_count();
auto p=map.emplace(&key,std::forward<P>(x));
if(map.bucket_count()!=c)rebuild_cache();
cache.insert({&key,p.first});
return p;
}
void swap(type_info_map& x){map.swap(x.map);cache.swap(x.cache);}
private:
using cache_type=std::unordered_map<
const std::type_info*,iterator,
std::hash<const std::type_info*>,std::equal_to<const std::type_info*>,
typename std::allocator_traits<Allocator>::template
rebind_alloc<std::pair<const std::type_info* const,iterator>>
>;
using cache_allocator_type=typename cache_type::allocator_type;
#if BOOST_WORKAROUND(BOOST_LIBSTDCXX_VERSION,<40900)
/* std::unordered_map(const allocator_type&),
* std::unordered_map(const unordered_map&,const allocator_type&) and
* std::unordered_map(unordered_map&&,const allocator_type&) not available.
*/
template<typename UnorderedMap>
static UnorderedMap make(const typename UnorderedMap::allocator_type& al)
{
return UnorderedMap{
10,typename UnorderedMap::hasher{},typename UnorderedMap::key_equal{},al
};
}
template<typename UnorderedMap>
static typename std::decay<UnorderedMap>::type make(
UnorderedMap&& x,
const typename std::decay<UnorderedMap>::type::allocator_type& al)
{
using RawUnorderedMap=typename std::decay<UnorderedMap>::type;
using iterator=typename std::conditional<
!std::is_lvalue_reference<UnorderedMap>::value&&
!std::is_const<UnorderedMap>::value,
std::move_iterator<typename RawUnorderedMap::iterator>,
typename RawUnorderedMap::const_iterator
>::type;
return RawUnorderedMap{
iterator{x.begin()},iterator{x.end()},0,
typename RawUnorderedMap::hasher{},typename RawUnorderedMap::key_equal{},
al
};
}
#else
template<typename UnorderedMap>
static UnorderedMap make(const typename UnorderedMap::allocator_type& al)
{
return UnorderedMap{al};
}
template<typename UnorderedMap>
static typename std::decay<UnorderedMap>::type make(
UnorderedMap&& x,
const typename std::decay<UnorderedMap>::type::allocator_type& al)
{
return {std::forward<UnorderedMap>(x),al};
}
#endif
void build_cache(const cache_type& x)
{
for(const auto& p:x)cache.insert({p.first,map.find(p.first)});
}
void rebuild_cache()
{
for(auto& p:cache)p.second=map.find(p.first);
}
map_type map;
cache_type cache;
};
template<typename T,typename Allocator>
void swap(type_info_map<T,Allocator>& x,type_info_map<T,Allocator>& y)
{
x.swap(y);
}
} /* namespace poly_collection::detail */
} /* namespace poly_collection */
} /* namespace boost */
#endif

View File

@@ -0,0 +1,199 @@
/* Copyright 2016-2017 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_TYPE_RESTITUTION_HPP
#define BOOST_POLY_COLLECTION_DETAIL_TYPE_RESTITUTION_HPP
#if defined(_MSC_VER)
#pragma once
#endif
#include <boost/poly_collection/detail/functional.hpp>
#include <boost/poly_collection/detail/iterator_traits.hpp>
#include <typeinfo>
#include <utility>
namespace boost{
namespace poly_collection{
namespace detail{
/* Given types Ts..., a const std::type_info& info and a local_base_iterator
* it, we denote by restitute<Ts...>(info,it):
* - a local_iterator<Ti> from it, if info==typeid(Ti) for some Ti in Ts...
* - it otherwise.
*
* Using this notation, restitute_range<Ts...>(f,args...)(s) resolves to
* f(restitute<Ts...>(info,begin),restitute<Ts...>(info,end),args...) where
* info=s.type_info(), begin=s.begin(), end=s.end().
*/
template<typename F,typename... Ts>
struct restitute_range_class;
template<typename F,typename T,typename... Ts>
struct restitute_range_class<F,T,Ts...>:
restitute_range_class<F,Ts...>
{
using super=restitute_range_class<F,Ts...>;
using super::super;
template<typename SegmentInfo>
auto operator()(SegmentInfo&& s)
->decltype(std::declval<F>()(s.begin(),s.end()))
{
using traits=iterator_traits<decltype(s.begin())>;
using local_iterator=typename traits::template local_iterator<T>;
if(s.type_info()==typeid(T))
return (this->f)(
local_iterator{s.begin()},local_iterator{s.end()});
else
return super::operator()(std::forward<SegmentInfo>(s));
}
};
template<typename F>
struct restitute_range_class<F>
{
restitute_range_class(const F& f):f(f){}
template<typename SegmentInfo>
auto operator()(SegmentInfo&& s)
->decltype(std::declval<F>()(s.begin(),s.end()))
{
return f(s.begin(),s.end());
}
F f;
};
template<typename... Ts,typename F,typename... Args>
auto restitute_range(const F& f,Args&&... args)
->restitute_range_class<
decltype(tail_closure(f,std::forward<Args>(args)...)),
Ts...
>
{
return tail_closure(f,std::forward<Args>(args)...);
}
/* restitute_iterator<Ts...>(f,args2...)(index,it,args1...) resolves to
* f(restitute<Ts...>(index,it),args1...,args2...).
*/
template<typename F,typename... Ts>
struct restitute_iterator_class;
template<typename F,typename T,typename... Ts>
struct restitute_iterator_class<F,T,Ts...>:
restitute_iterator_class<F,Ts...>
{
using super=restitute_iterator_class<F,Ts...>;
using super::super;
template<typename Iterator,typename... Args>
auto operator()(
const std::type_info& info,Iterator&& it,Args&&... args)
->decltype(
std::declval<F>()
(std::forward<Iterator>(it),std::forward<Args>(args)...))
{
using traits=iterator_traits<typename std::decay<Iterator>::type>;
using local_iterator=typename traits::template local_iterator<T>;
if(info==typeid(T))
return (this->f)(
local_iterator{it},std::forward<Args>(args)...);
else
return super::operator()(
info,std::forward<Iterator>(it),std::forward<Args>(args)...);
}
};
template<typename F>
struct restitute_iterator_class<F>
{
restitute_iterator_class(const F& f):f(f){}
template<typename Iterator,typename... Args>
auto operator()(
const std::type_info&,Iterator&& it,Args&&... args)
->decltype(
std::declval<F>()
(std::forward<Iterator>(it),std::forward<Args>(args)...))
{
return f(std::forward<Iterator>(it),std::forward<Args>(args)...);
}
F f;
};
template<typename... Ts,typename F,typename... Args>
auto restitute_iterator(const F& f,Args&&... args)
->restitute_iterator_class<
decltype(tail_closure(f,std::forward<Args>(args)...)),
Ts...
>
{
return tail_closure(f,std::forward<Args>(args)...);
}
/* binary_restitute_iterator<Ts...>(f,args...)(index1,it1,index2,it2) resolves
* to f(restitute<Ts...>(index1,it1),restitute<Ts...>(index2,it2),args...).
*/
template<typename F,typename... Ts>
struct binary_restitute_iterator_class
{
binary_restitute_iterator_class(const F& f):f(f){}
template<typename Iterator1,typename Iterator2>
auto operator()(
const std::type_info& info1,Iterator1&& it1,
const std::type_info& info2,Iterator2&& it2)
->decltype(
std::declval<F>()
(std::forward<Iterator1>(it1),std::forward<Iterator2>(it2)))
{
return restitute_iterator<Ts...>(*this)(
info2,std::forward<Iterator2>(it2),info1,std::forward<Iterator1>(it1));
}
template<typename Iterator2,typename Iterator1>
auto operator()(
Iterator2&& it2,const std::type_info& info1,Iterator1&& it1)
->decltype(
std::declval<F>()
(std::forward<Iterator1>(it1),std::forward<Iterator2>(it2)))
{
return restitute_iterator<Ts...>(f)(
info1,std::forward<Iterator1>(it1),std::forward<Iterator2>(it2));
}
F f;
};
template<typename... Ts,typename F,typename... Args>
auto binary_restitute_iterator(const F& f,Args&&... args)
->binary_restitute_iterator_class<
decltype(tail_closure(f,std::forward<Args>(args)...)),
Ts...
>
{
return tail_closure(f,std::forward<Args>(args)...);
}
} /* namespace poly_collection::detail */
} /* namespace poly_collection */
} /* namespace boost */
#endif

View File

@@ -0,0 +1,233 @@
/* 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_VALUE_HOLDER_HPP
#define BOOST_POLY_COLLECTION_DETAIL_VALUE_HOLDER_HPP
#if defined(_MSC_VER)
#pragma once
#endif
#include <boost/core/addressof.hpp>
#include <boost/poly_collection/detail/is_constructible.hpp>
#include <boost/poly_collection/detail/is_equality_comparable.hpp>
#include <boost/poly_collection/detail/is_nothrow_eq_comparable.hpp>
#include <boost/poly_collection/exception.hpp>
#include <new>
#include <memory>
#include <type_traits>
#include <utility>
namespace boost{
namespace poly_collection{
namespace detail{
/* Segments of a poly_collection maintain vectors of value_holder<T>
* rather than directly T. This serves several purposes:
* - value_holder<T> is copy constructible and equality comparable even if T
* is not: executing the corresponding op results in a reporting exception
* being thrown. This allows the segment to offer its full virtual
* interface regardless of the properties of the concrete class contained.
* - value_holder<T> emulates move assignment when T is not move assignable
* (nothrow move constructibility required); this happens most notably with
* lambda functions, whose assignment operator is deleted by standard
* mandate [expr.prim.lambda]/20 even if the compiler generated one would
* work (capture by value).
* - value_holder ctors accept a first allocator arg passed by
* boost::poly_collection::detail::allocator_adaptor, for purposes
* explained there.
*
* A pointer to value_holder_base<T> can be reinterpret_cast'ed to T*.
* Emplacing is explicitly signalled with value_holder_emplacing_ctor to
* protect us from greedy T's constructible from anything (like
* boost::type_erasure::any).
*/
struct value_holder_emplacing_ctor_t{};
constexpr value_holder_emplacing_ctor_t value_holder_emplacing_ctor=
value_holder_emplacing_ctor_t();
template<typename T>
class value_holder_base
{
protected:
typename std::aligned_storage<sizeof(T),alignof(T)>::type s;
};
template<typename T>
class value_holder:public value_holder_base<T>
{
template<typename U>
using enable_if_not_emplacing_ctor_t=typename std::enable_if<
!std::is_same<
typename std::decay<U>::type,value_holder_emplacing_ctor_t
>::value
>::type*;
using is_nothrow_move_constructible=std::is_nothrow_move_constructible<T>;
using is_copy_constructible=std::is_copy_constructible<T>;
using is_nothrow_copy_constructible=std::is_nothrow_copy_constructible<T>;
using is_move_assignable=std::is_move_assignable<T>;
using is_nothrow_move_assignable=std::is_nothrow_move_assignable<T>;
using is_equality_comparable=detail::is_equality_comparable<T>;
using is_nothrow_equality_comparable=
detail::is_nothrow_equality_comparable<T>;
T* data()noexcept{return reinterpret_cast<T*>(&this->s);}
const T* data()const noexcept
{return reinterpret_cast<const T*>(&this->s);}
T& value()noexcept{return *static_cast<T*>(data());}
const T& value()const noexcept{return *static_cast<const T*>(data());}
public:
template<
typename Allocator,
enable_if_not_emplacing_ctor_t<Allocator> =nullptr
>
value_holder(Allocator& al,const T& x)
noexcept(is_nothrow_copy_constructible::value)
{copy(al,x);}
template<
typename Allocator,
enable_if_not_emplacing_ctor_t<Allocator> =nullptr
>
value_holder(Allocator& al,T&& x)
noexcept(is_nothrow_move_constructible::value)
{std::allocator_traits<Allocator>::construct(al,data(),std::move(x));}
template<
typename Allocator,typename... Args,
enable_if_not_emplacing_ctor_t<Allocator> =nullptr
>
value_holder(Allocator& al,value_holder_emplacing_ctor_t,Args&&... args)
{std::allocator_traits<Allocator>::construct(
al,data(),std::forward<Args>(args)...);}
template<
typename Allocator,
enable_if_not_emplacing_ctor_t<Allocator> =nullptr
>
value_holder(Allocator& al,const value_holder& x)
noexcept(is_nothrow_copy_constructible::value)
{copy(al,x.value());}
template<
typename Allocator,
enable_if_not_emplacing_ctor_t<Allocator> =nullptr
>
value_holder(Allocator& al,value_holder&& x)
noexcept(is_nothrow_move_constructible::value)
{std::allocator_traits<Allocator>::construct(
al,data(),std::move(x.value()));}
/* stdlib implementations in current use are notoriously lacking at
* complying with [container.requirements.general]/3, so we keep the
* following to make their life easier.
*/
value_holder(const T& x)
noexcept(is_nothrow_copy_constructible::value)
{copy(x);}
value_holder(T&& x)
noexcept(is_nothrow_move_constructible::value)
{::new ((void*)data()) T(std::move(x));}
template<typename... Args>
value_holder(value_holder_emplacing_ctor_t,Args&&... args)
{::new ((void*)data()) T(std::forward<Args>(args)...);}
value_holder(const value_holder& x)
noexcept(is_nothrow_copy_constructible::value)
{copy(x.value());}
value_holder(value_holder&& x)
noexcept(is_nothrow_move_constructible::value)
{::new ((void*)data()) T(std::move(x.value()));}
value_holder& operator=(const value_holder& x)=delete;
value_holder& operator=(value_holder&& x)
noexcept(is_nothrow_move_assignable::value||!is_move_assignable::value)
/* if 2nd clause: nothrow move constructibility required */
{
move_assign(std::move(x.value()));
return *this;
}
~value_holder()noexcept{value().~T();}
friend bool operator==(const value_holder& x,const value_holder& y)
noexcept(is_nothrow_equality_comparable::value)
{
return x.equal(y.value());
}
private:
template<typename Allocator>
void copy(Allocator& al,const T& x){copy(al,x,is_copy_constructible{});}
template<typename Allocator>
void copy(Allocator& al,const T& x,std::true_type)
{
std::allocator_traits<Allocator>::construct(al,data(),x);
}
template<typename Allocator>
void copy(Allocator&,const T&,std::false_type)
{
throw not_copy_constructible{typeid(T)};
}
void copy(const T& x){copy(x,is_copy_constructible{});}
void copy(const T& x,std::true_type)
{
::new (data()) T(x);
}
void copy(const T&,std::false_type)
{
throw not_copy_constructible{typeid(T)};
}
void move_assign(T&& x){move_assign(std::move(x),is_move_assignable{});}
void move_assign(T&& x,std::true_type)
{
value()=std::move(x);
}
void move_assign(T&& x,std::false_type)
{
/* emulated assignment */
static_assert(is_nothrow_move_constructible::value,
"type should be move assignable or nothrow move constructible");
if(data()!=boost::addressof(x)){
value().~T();
::new (data()) T(std::move(x));
}
}
bool equal(const T& x)const{return equal(x,is_equality_comparable{});}
bool equal(const T& x,std::true_type)const
{
return value()==x;
}
bool equal(const T&,std::false_type)const
{
throw not_equality_comparable{typeid(T)};
}
};
} /* namespace poly_collection::detail */
} /* namespace poly_collection */
} /* namespace boost */
#endif

View File

@@ -0,0 +1,57 @@
/* Copyright 2016-2017 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_EXCEPTION_HPP
#define BOOST_POLY_COLLECTION_EXCEPTION_HPP
#if defined(_MSC_VER)
#pragma once
#endif
#include <stdexcept>
#include <typeinfo>
namespace boost{
namespace poly_collection{
struct unregistered_type:std::logic_error
{
unregistered_type(const std::type_info& info):
std::logic_error{"type not registered"},
pinfo{&info}
{}
const std::type_info* pinfo;
};
struct not_copy_constructible:std::logic_error
{
not_copy_constructible(const std::type_info& info):
std::logic_error{"type is not copy constructible"},
pinfo{&info}
{}
const std::type_info* pinfo;
};
struct not_equality_comparable:std::logic_error
{
not_equality_comparable(const std::type_info& info):
std::logic_error{"type does not support equality comparison"},
pinfo{&info}
{}
const std::type_info* pinfo;
};
} /* namespace poly_collection */
} /* namespace boost */
#endif

View File

@@ -0,0 +1,80 @@
/* Copyright 2016-2017 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_FUNCTION_COLLECTION_HPP
#define BOOST_POLY_COLLECTION_FUNCTION_COLLECTION_HPP
#if defined(_MSC_VER)
#pragma once
#endif
#include <boost/poly_collection/function_collection_fwd.hpp>
#include <boost/poly_collection/detail/function_model.hpp>
#include <boost/poly_collection/detail/poly_collection.hpp>
#include <utility>
namespace boost{
namespace poly_collection{
template<typename Signature,typename Allocator>
class function_collection:
public common_impl::poly_collection<
detail::function_model<Signature>,Allocator>
{
using base_type=common_impl::poly_collection<
detail::function_model<Signature>,Allocator>;
base_type& base()noexcept{return *this;}
const base_type& base()const noexcept{return *this;}
public:
using base_type::base_type;
function_collection()=default;
function_collection(const function_collection& x)=default;
function_collection(function_collection&& x)=default;
function_collection& operator=(const function_collection& x)=default;
function_collection& operator=(function_collection&& x)=default;
template<typename S,typename A>
friend bool operator==(
const function_collection<S,A>&,const function_collection<S,A>&);
};
template<typename Signature,typename Allocator>
bool operator==(
const function_collection<Signature,Allocator>& x,
const function_collection<Signature,Allocator>& y)
{
return x.base()==y.base();
}
template<typename Signature,typename Allocator>
bool operator!=(
const function_collection<Signature,Allocator>& x,
const function_collection<Signature,Allocator>& y)
{
return !(x==y);
}
template<typename Signature,typename Allocator>
void swap(
function_collection<Signature,Allocator>& x,
function_collection<Signature,Allocator>& y)
{
x.swap(y);
}
} /* namespace */
using poly_collection::function_collection;
} /* namespace boost */
#endif

View File

@@ -0,0 +1,57 @@
/* Copyright 2016 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_FUNCTION_COLLECTION_FWD_HPP
#define BOOST_POLY_COLLECTION_FUNCTION_COLLECTION_FWD_HPP
#if defined(_MSC_VER)
#pragma once
#endif
#include <memory>
namespace boost{
namespace poly_collection{
namespace detail{
template<typename Signature> struct function_model;
}
template<typename Signature>
using function_collection_value_type=
typename detail::function_model<Signature>::value_type;
template<
typename Signature,
typename Allocator=std::allocator<function_collection_value_type<Signature>>
>
class function_collection;
template<typename Signature,typename Allocator>
bool operator==(
const function_collection<Signature,Allocator>& x,
const function_collection<Signature,Allocator>& y);
template<typename Signature,typename Allocator>
bool operator!=(
const function_collection<Signature,Allocator>& x,
const function_collection<Signature,Allocator>& y);
template<typename Signature,typename Allocator>
void swap(
function_collection<Signature,Allocator>& x,
function_collection<Signature,Allocator>& y);
} /* namespace poly_collection */
using poly_collection::function_collection;
} /* namespace boost */
#endif