summaryrefslogtreecommitdiff
path: root/boost/poly_collection/detail
diff options
context:
space:
mode:
Diffstat (limited to 'boost/poly_collection/detail')
-rw-r--r--boost/poly_collection/detail/allocator_adaptor.hpp300
-rw-r--r--boost/poly_collection/detail/any_model.hpp21
-rw-r--r--boost/poly_collection/detail/base_model.hpp20
-rw-r--r--boost/poly_collection/detail/function_model.hpp21
-rw-r--r--boost/poly_collection/detail/newdelete_allocator.hpp102
-rw-r--r--boost/poly_collection/detail/packed_segment.hpp43
-rw-r--r--boost/poly_collection/detail/poly_collection.hpp16
-rw-r--r--boost/poly_collection/detail/segment.hpp44
-rw-r--r--boost/poly_collection/detail/segment_backend.hpp9
-rw-r--r--boost/poly_collection/detail/split_segment.hpp48
-rw-r--r--boost/poly_collection/detail/type_info_map.hpp152
-rw-r--r--boost/poly_collection/detail/value_holder.hpp88
12 files changed, 520 insertions, 344 deletions
diff --git a/boost/poly_collection/detail/allocator_adaptor.hpp b/boost/poly_collection/detail/allocator_adaptor.hpp
new file mode 100644
index 0000000000..9652e26938
--- /dev/null
+++ b/boost/poly_collection/detail/allocator_adaptor.hpp
@@ -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
diff --git a/boost/poly_collection/detail/any_model.hpp b/boost/poly_collection/detail/any_model.hpp
index 9daeb70db0..5245bfe8ff 100644
--- a/boost/poly_collection/detail/any_model.hpp
+++ b/boost/poly_collection/detail/any_model.hpp
@@ -1,4 +1,4 @@
-/* Copyright 2016-2017 Joaquin M Lopez Munoz.
+/* 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)
@@ -151,16 +151,11 @@ struct any_model
using iterator=Concrete*;
template<typename Concrete>
using const_iterator=const Concrete*;
- using segment_backend=detail::segment_backend<any_model>;
+ 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,
- typename std::allocator_traits<Allocator>::
- template rebind_alloc<Concrete>
- >;
- using segment_backend_unique_ptr=
- typename segment_backend::segment_backend_unique_ptr;
+ using segment_backend_implementation=
+ split_segment<any_model,Concrete,Allocator>;
static base_iterator nonconst_iterator(const_base_iterator it)
{
@@ -174,12 +169,6 @@ struct any_model
return const_cast<iterator<T>>(it);
}
- template<typename Concrete,typename Allocator>
- static segment_backend_unique_ptr make(const Allocator& al)
- {
- return segment_backend_implementation<Concrete,Allocator>::new_(al,al);
- }
-
private:
template<typename,typename,typename>
friend class split_segment;
diff --git a/boost/poly_collection/detail/base_model.hpp b/boost/poly_collection/detail/base_model.hpp
index f6d44bb263..62c209f740 100644
--- a/boost/poly_collection/detail/base_model.hpp
+++ b/boost/poly_collection/detail/base_model.hpp
@@ -1,4 +1,4 @@
-/* Copyright 2016-2017 Joaquin M Lopez Munoz.
+/* 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)
@@ -80,15 +80,11 @@ public:
using iterator=Derived*;
template<typename Derived>
using const_iterator=const Derived*;
- using segment_backend=detail::segment_backend<base_model>;
+ 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,
- typename std::allocator_traits<Allocator>::template rebind_alloc<Derived>
- >;
- using segment_backend_unique_ptr=
- typename segment_backend::segment_backend_unique_ptr;
+ using segment_backend_implementation=
+ packed_segment<base_model,Derived,Allocator>;
static base_iterator nonconst_iterator(const_base_iterator it)
{
@@ -104,12 +100,6 @@ public:
return const_cast<iterator<T>>(it);
}
- template<typename Derived,typename Allocator>
- static segment_backend_unique_ptr make(const Allocator& al)
- {
- return segment_backend_implementation<Derived,Allocator>::new_(al,al);
- }
-
private:
template<typename,typename,typename>
friend class packed_segment;
diff --git a/boost/poly_collection/detail/function_model.hpp b/boost/poly_collection/detail/function_model.hpp
index 895f19d39b..2d1d8328c7 100644
--- a/boost/poly_collection/detail/function_model.hpp
+++ b/boost/poly_collection/detail/function_model.hpp
@@ -1,4 +1,4 @@
-/* Copyright 2016-2017 Joaquin M Lopez Munoz.
+/* 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)
@@ -91,16 +91,11 @@ struct function_model<R(Args...)>
using iterator=Callable*;
template<typename Callable>
using const_iterator=const Callable*;
- using segment_backend=detail::segment_backend<function_model>;
+ 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,
- typename std::allocator_traits<Allocator>::
- template rebind_alloc<Callable>
- >;
- using segment_backend_unique_ptr=
- typename segment_backend::segment_backend_unique_ptr;
+ using segment_backend_implementation=
+ split_segment<function_model,Callable,Allocator>;
static base_iterator nonconst_iterator(const_base_iterator it)
{
@@ -114,12 +109,6 @@ struct function_model<R(Args...)>
return const_cast<iterator<T>>(it);
}
- template<typename Callable,typename Allocator>
- static segment_backend_unique_ptr make(const Allocator& al)
- {
- return segment_backend_implementation<Callable,Allocator>::new_(al,al);
- }
-
private:
template<typename,typename,typename>
friend class split_segment;
diff --git a/boost/poly_collection/detail/newdelete_allocator.hpp b/boost/poly_collection/detail/newdelete_allocator.hpp
deleted file mode 100644
index 1c66db3b7a..0000000000
--- a/boost/poly_collection/detail/newdelete_allocator.hpp
+++ /dev/null
@@ -1,102 +0,0 @@
-/* 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_NEWDELETE_ALLOCATOR_HPP
-#define BOOST_POLY_COLLECTION_DETAIL_NEWDELETE_ALLOCATOR_HPP
-
-#if defined(_MSC_VER)
-#pragma once
-#endif
-
-#include <boost/poly_collection/detail/is_constructible.hpp>
-#include <memory>
-#include <new>
-#include <utility>
-
-namespace boost{
-
-namespace poly_collection{
-
-namespace detail{
-
-/* In order to comply with [container.requirements.general]/3,
- * newdelete_allocator_adaptor<Allocator> overrides
- * Allocator::construct/destroy with vanilla new/delete implementations.
- * Used therefore in all auxiliary internal structures.
- */
-
-template<typename Allocator>
-struct newdelete_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;
-
- template<typename U>
- struct rebind
- {
- using other=newdelete_allocator_adaptor<
- typename traits::template rebind_alloc<U>>;
- };
-
- newdelete_allocator_adaptor()=default;
- newdelete_allocator_adaptor(const newdelete_allocator_adaptor&)=default;
-
- template<
- typename Allocator2,
- typename std::enable_if<
- is_constructible<Allocator,Allocator2>::value
- >::type* =nullptr
- >
- newdelete_allocator_adaptor(const Allocator2& x)noexcept:Allocator{x}{}
-
- template<
- typename Allocator2,
- typename std::enable_if<
- is_constructible<Allocator,Allocator2>::value
- >::type* =nullptr
- >
- newdelete_allocator_adaptor(
- const newdelete_allocator_adaptor<Allocator2>& x)noexcept:
- Allocator{static_cast<const Allocator2&>(x)}{}
-
- newdelete_allocator_adaptor& operator=(
- const newdelete_allocator_adaptor&)=default;
-
- template<typename T,typename... Args>
- void construct(T* p,Args&&... args)
- {
- ::new ((void*)p) T(std::forward<Args>(args)...);
- }
-
- template<typename T>
- void destroy(T* p)
- {
- p->~T();
- }
-};
-
-} /* namespace poly_collection::detail */
-
-} /* namespace poly_collection */
-
-} /* namespace boost */
-
-#endif
diff --git a/boost/poly_collection/detail/packed_segment.hpp b/boost/poly_collection/detail/packed_segment.hpp
index 4d241e27b4..625de2d0b1 100644
--- a/boost/poly_collection/detail/packed_segment.hpp
+++ b/boost/poly_collection/detail/packed_segment.hpp
@@ -1,4 +1,4 @@
-/* Copyright 2016-2017 Joaquin M Lopez Munoz.
+/* 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)
@@ -14,7 +14,6 @@
#endif
#include <boost/detail/workaround.hpp>
-#include <boost/poly_collection/detail/newdelete_allocator.hpp>
#include <boost/poly_collection/detail/segment_backend.hpp>
#include <boost/poly_collection/detail/value_holder.hpp>
#include <memory>
@@ -39,20 +38,18 @@ namespace detail{
*/
template<typename Model,typename Concrete,typename Allocator>
-class packed_segment:public segment_backend<Model>
+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,
- value_holder_allocator_adaptor<
- typename std::allocator_traits<Allocator>::
- template rebind_alloc<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>;
+ 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;
@@ -62,21 +59,35 @@ class packed_segment:public segment_backend<Model>
typename segment_backend::template const_iterator<Concrete>;
using typename segment_backend::base_sentinel;
using typename segment_backend::range;
- using segment_allocator_type=newdelete_allocator_adaptor<
- typename std::allocator_traits<Allocator>::
- template rebind_alloc<packed_segment>
- >;
+ 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 empty_copy()const
+ virtual segment_backend_unique_ptr copy(const Allocator& al)const
{
- return new_(s.get_allocator(),s.get_allocator());
+ 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)const
+ {
+ return new_(al,store{std::move(s),al});
}
virtual bool equal(const segment_backend& x)const
@@ -84,6 +95,8 @@ public:
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
@@ -214,8 +227,6 @@ public:
base_sentinel nv_clear()noexcept{s.clear();return sentinel();}
private:
- friend Model;
-
template<typename... Args>
static segment_backend_unique_ptr new_(
segment_allocator_type al,Args&&... args)
diff --git a/boost/poly_collection/detail/poly_collection.hpp b/boost/poly_collection/detail/poly_collection.hpp
index 2334347419..f7bcfc4efc 100644
--- a/boost/poly_collection/detail/poly_collection.hpp
+++ b/boost/poly_collection/detail/poly_collection.hpp
@@ -1,4 +1,4 @@
-/* Copyright 2016-2017 Joaquin M Lopez Munoz.
+/* 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)
@@ -16,11 +16,11 @@
#include <algorithm>
#include <boost/assert.hpp>
#include <boost/iterator/iterator_adaptor.hpp>
+#include <boost/poly_collection/detail/allocator_adaptor.hpp>
#include <boost/poly_collection/detail/iterator_impl.hpp>
#include <boost/poly_collection/detail/is_acceptable.hpp>
#include <boost/poly_collection/detail/is_constructible.hpp>
#include <boost/poly_collection/detail/is_final.hpp>
-#include <boost/poly_collection/detail/newdelete_allocator.hpp>
#include <boost/poly_collection/detail/segment.hpp>
#include <boost/poly_collection/detail/type_info_map.hpp>
#include <boost/poly_collection/exception.hpp>
@@ -103,7 +103,8 @@ class poly_collection
using enable_if_not_constructible=
typename std::enable_if<!is_constructible<T,U>::value>::type*;
- using segment_type=detail::segment<Model,Allocator>;
+ using segment_allocator_type=allocator_adaptor<Allocator>;
+ using segment_type=detail::segment<Model,segment_allocator_type>;
using segment_base_iterator=typename segment_type::base_iterator;
using const_segment_base_iterator=
typename segment_type::const_base_iterator;
@@ -117,10 +118,8 @@ class poly_collection
typename segment_type::template const_iterator<T>;
using segment_map=type_info_map<
segment_type,
- newdelete_allocator_adaptor<
- typename std::allocator_traits<Allocator>::template
- rebind_alloc<segment_type>
- >
+ typename std::allocator_traits<segment_allocator_type>::template
+ rebind_alloc<segment_type>
>;
using segment_map_allocator_type=typename segment_map::allocator_type;
using segment_map_iterator=typename segment_map::iterator;
@@ -1020,7 +1019,8 @@ private:
const auto& id=subtypeid(x);
auto it=map.find(id);
if(it!=map.end())return it;
- else return map.insert(id,segment_type::make_from_prototype(seg)).first;
+ else return map.insert(
+ id,segment_type::make_from_prototype(seg,get_allocator())).first;
}
template<typename T>
diff --git a/boost/poly_collection/detail/segment.hpp b/boost/poly_collection/detail/segment.hpp
index 52aa4d4a66..a080839790 100644
--- a/boost/poly_collection/detail/segment.hpp
+++ b/boost/poly_collection/detail/segment.hpp
@@ -1,4 +1,4 @@
-/* Copyright 2016-2017 Joaquin M Lopez Munoz.
+/* 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)
@@ -40,6 +40,7 @@ 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;
@@ -50,24 +51,42 @@ public:
using const_iterator=typename Model::template const_iterator<T>;
template<typename T>
- static segment make(const Allocator& al)
+ static segment make(const allocator_type& al)
{
- return Model::template make<T>(al);
+ return segment_backend_implementation<T>::make(al);
}
/* clones the implementation of x with no elements */
- static segment make_from_prototype(const segment& x)
+ static segment make_from_prototype(const segment& x,const allocator_type& al)
{
- return {from_prototype{},x};
+ return {from_prototype{},x,al};
}
- segment(const segment& x):pimpl{x.impl().copy()}{set_sentinel();}
+ segment(const segment& x):
+ pimpl{x.impl().copy()}{set_sentinel();}
segment(segment&& x)=default;
- segment& operator=(segment x) // TODO: Why do we need this?
+ 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=std::move(x.pimpl);
- snt=x.snt;
+ pimpl=x.impl().move(
+ allocator_traits::propagate_on_container_move_assignment::value?
+ x.impl().get_allocator():impl().get_allocator());
+ set_sentinel();
return *this;
}
@@ -243,7 +262,8 @@ public:
void clear()noexcept{filter(impl<U>().nv_clear());}
private:
- using segment_backend=typename Model::segment_backend;
+ 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>;
@@ -255,8 +275,8 @@ private:
segment(segment_backend_unique_ptr&& pimpl):
pimpl{std::move(pimpl)}{set_sentinel();}
- segment(from_prototype,const segment& x):
- pimpl{x.impl().empty_copy()}{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;}
diff --git a/boost/poly_collection/detail/segment_backend.hpp b/boost/poly_collection/detail/segment_backend.hpp
index f097ac2edc..922f370b92 100644
--- a/boost/poly_collection/detail/segment_backend.hpp
+++ b/boost/poly_collection/detail/segment_backend.hpp
@@ -1,4 +1,4 @@
-/* Copyright 2016-2017 Joaquin M Lopez Munoz.
+/* 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)
@@ -31,7 +31,7 @@ namespace detail{
* Passed elements are type erased with [const_]value_pointer.
*/
-template<typename Model>
+template<typename Model,typename Allocator>
struct segment_backend
{
using segment_backend_unique_ptr=
@@ -51,9 +51,12 @@ struct segment_backend
virtual ~segment_backend()=default;
virtual segment_backend_unique_ptr copy()const=0;
- virtual segment_backend_unique_ptr empty_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&)const=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;
diff --git a/boost/poly_collection/detail/split_segment.hpp b/boost/poly_collection/detail/split_segment.hpp
index feccf44e30..cd585c1fa9 100644
--- a/boost/poly_collection/detail/split_segment.hpp
+++ b/boost/poly_collection/detail/split_segment.hpp
@@ -1,4 +1,4 @@
-/* Copyright 2016-2017 Joaquin M Lopez Munoz.
+/* 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)
@@ -13,7 +13,6 @@
#pragma once
#endif
-#include <boost/poly_collection/detail/newdelete_allocator.hpp>
#include <boost/poly_collection/detail/segment_backend.hpp>
#include <boost/poly_collection/detail/value_holder.hpp>
#include <iterator>
@@ -45,28 +44,24 @@ namespace detail{
*/
template<typename Model,typename Concrete,typename Allocator>
-class split_segment:public segment_backend<Model>
+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,
- value_holder_allocator_adaptor<
- typename std::allocator_traits<Allocator>::
- template rebind_alloc<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,
- newdelete_allocator_adaptor<
- typename std::allocator_traits<Allocator>::
- template rebind_alloc<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>;
+ 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;
@@ -76,22 +71,35 @@ class split_segment:public segment_backend<Model>
typename segment_backend::template const_iterator<Concrete>;
using typename segment_backend::base_sentinel;
using typename segment_backend::range;
- using segment_allocator_type=newdelete_allocator_adaptor<
- typename std::allocator_traits<Allocator>::
- template rebind_alloc<split_segment>
- >;
+ 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 empty_copy()const
+ virtual segment_backend_unique_ptr copy(const Allocator& al)const
{
- return new_(s.get_allocator(),s.get_allocator());
+ 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)const
+ {
+ return new_(al,store{std::move(s),al});
}
virtual bool equal(const segment_backend& x)const
@@ -99,6 +107,8 @@ public:
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())};}
@@ -276,8 +286,6 @@ public:
}
private:
- friend Model;
-
template<typename... Args>
static segment_backend_unique_ptr new_(
segment_allocator_type al,Args&&... args)
diff --git a/boost/poly_collection/detail/type_info_map.hpp b/boost/poly_collection/detail/type_info_map.hpp
index 43dd6ddfc8..fcc6a8cef5 100644
--- a/boost/poly_collection/detail/type_info_map.hpp
+++ b/boost/poly_collection/detail/type_info_map.hpp
@@ -1,4 +1,4 @@
-/* Copyright 2016-2017 Joaquin M Lopez Munoz.
+/* 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)
@@ -14,8 +14,9 @@
#endif
#include <boost/detail/workaround.hpp>
-#include <boost/poly_collection/detail/newdelete_allocator.hpp>
#include <functional>
+#include <memory>
+#include <type_traits>
#include <typeinfo>
#include <unordered_map>
#include <utility>
@@ -49,7 +50,6 @@ struct type_info_ptr_equal_to
{return *p==*q;}
};
-
template<typename T,typename Allocator>
class type_info_map
{
@@ -68,70 +68,70 @@ public:
using iterator=typename map_type::iterator;
using const_iterator=typename map_type::const_iterator;
-#if BOOST_WORKAROUND(BOOST_LIBSTDCXX_VERSION,<40900)
- /* std::unordered_map(const unordered_map&,const allocator_type&),
- * std::unordered_map(unordered_map&&,const allocator_type&) and
- * std::unordered_map(const allocator_type&) not available.
- */
-
-#define BOOST_POLY_COLLECTION_MAP_CONT_ALLOC_CTOR(x,al) \
-x.begin(),x.end(), \
-0,typename map_type::hasher{},typename map_type::key_equal{},al
-#define BOOST_POLY_COLLECTION_MAP_ALLOC_CTOR(al) \
-10,typename map_type::hasher{},typename map_type::key_equal{},al
-#define BOOST_POLY_COLLECTION_CACHE_ALLOC_CTOR(al) \
-10,typename cache_type::hasher{},typename cache_type::key_equal{},al
-
-#else
-
-#define BOOST_POLY_COLLECTION_MAP_CONT_ALLOC_CTOR(x,al) x,al
-#define BOOST_POLY_COLLECTION_MAP_ALLOC_CTOR(al) al
-#define BOOST_POLY_COLLECTION_CACHE_ALLOC_CTOR(al) al
-
-#endif
-
type_info_map()=default;
type_info_map(const type_info_map& x):
map{x.map},
- cache{BOOST_POLY_COLLECTION_CACHE_ALLOC_CTOR(x.cache.get_allocator())}
+ 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{BOOST_POLY_COLLECTION_MAP_ALLOC_CTOR(al)},
- cache{BOOST_POLY_COLLECTION_CACHE_ALLOC_CTOR(cache_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{BOOST_POLY_COLLECTION_MAP_CONT_ALLOC_CTOR(x.map,al)},
- cache{BOOST_POLY_COLLECTION_CACHE_ALLOC_CTOR(cache_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{BOOST_POLY_COLLECTION_MAP_CONT_ALLOC_CTOR(std::move(x.map),al)},
- cache{BOOST_POLY_COLLECTION_CACHE_ALLOC_CTOR(cache_allocator_type{al})}
- {
- if(al==x.map.get_allocator()&&
- cache_allocator_type{al}==x.cache.get_allocator()){
- cache=std::move(x.cache);
+ 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)
}
- else{
+ {
+ if(!(al==allocator_type{x.map.get_allocator()}&&x.map.empty())){
build_cache(x.cache);
- x.cache.clear();
}
+ x.map.clear();
+ x.cache.clear();
}
-#undef BOOST_POLY_COLLECTION_MAP_CONT_ALLOC_CTOR
-#undef BOOST_POLY_COLLECTION_MAP_ALLOC_CTOR
-#undef BOOST_POLY_COLLECTION_CACHE_ALLOC_CTOR
-
type_info_map& operator=(const type_info_map& x)
{
- if(this!=&x){
- type_info_map c{x};
- swap(c);
+ 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)=default;
+ 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();}
@@ -161,7 +161,9 @@ x.begin(),x.end(), \
template<typename P>
std::pair<iterator,bool> insert(const key_type& key,P&& x)
{
- auto p=map.insert({&key,std::forward<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;
}
@@ -172,18 +174,64 @@ 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*>,
- newdelete_allocator_adaptor<
- typename std::allocator_traits<Allocator>::template
- rebind_alloc<std::pair<const std::type_info* const,iterator>>
- >
+ 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.
+ * We make move construction decay to copy construction.
+ */
+
+ 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;
+
+ return RawUnorderedMap{
+ x.begin(),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;
};
diff --git a/boost/poly_collection/detail/value_holder.hpp b/boost/poly_collection/detail/value_holder.hpp
index bd2f25c6f8..fe06efd652 100644
--- a/boost/poly_collection/detail/value_holder.hpp
+++ b/boost/poly_collection/detail/value_holder.hpp
@@ -1,4 +1,4 @@
-/* Copyright 2016-2017 Joaquin M Lopez Munoz.
+/* 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)
@@ -40,10 +40,9 @@ namespace detail{
* 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).
- * - To comply with [container.requirements.general]/3 (or, more precisely,
- * its natural extension to polymorphic containers), value_holder ctors
- * accept a first allocator arg passed by value_holder_allocator_adaptor,
- * which must therefore be used in the vectors of value_holder's.
+ * - 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
@@ -225,85 +224,6 @@ private:
}
};
-template<typename Allocator>
-struct value_holder_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;
-
- template<typename U>
- struct rebind
- {
- using other=value_holder_allocator_adaptor<
- typename traits::template rebind_alloc<U>>;
- };
-
- value_holder_allocator_adaptor()=default;
- value_holder_allocator_adaptor(
- const value_holder_allocator_adaptor&)=default;
-
- template<
- typename Allocator2,
- typename std::enable_if<
- is_constructible<Allocator,Allocator2>::value
- >::type* =nullptr
- >
- value_holder_allocator_adaptor(const Allocator2& x)noexcept:Allocator{x}{}
-
- template<
- typename Allocator2,
- typename std::enable_if<
- is_constructible<Allocator,Allocator2>::value
- >::type* =nullptr
- >
- value_holder_allocator_adaptor(
- const value_holder_allocator_adaptor<Allocator2>& x)noexcept:
- Allocator{static_cast<const Allocator2&>(x)}{}
-
- value_holder_allocator_adaptor& operator=(
- const value_holder_allocator_adaptor&)=default;
-
- template<typename T,typename... Args>
- void construct(T* p,Args&&... args)
- {
- ::new ((void*)p) T(std::forward<Args>(args)...);
- }
-
- template<typename T,typename... Args>
- void construct(value_holder<T>* p,Args&&... args)
- {
- ::new ((void*)p) value_holder<T>(
- static_cast<Allocator&>(*this),std::forward<Args>(args)...);
- }
-
- template<typename T>
- void destroy(T* p)
- {
- p->~T();
- }
-
- template<typename T>
- void destroy(value_holder<T>* p)
- {
- traits::destroy(
- static_cast<Allocator&>(*this),
- reinterpret_cast<T*>(static_cast<value_holder_base<T>*>(p)));
- }
-};
-
} /* namespace poly_collection::detail */
} /* namespace poly_collection */