feat():initial version
This commit is contained in:
1186
install/boost_1_75_0/include/boost/poly_collection/algorithm.hpp
Normal file
1186
install/boost_1_75_0/include/boost/poly_collection/algorithm.hpp
Normal file
File diff suppressed because it is too large
Load Diff
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
Reference in New Issue
Block a user