diff options
Diffstat (limited to 'boost/poly_collection/detail')
-rw-r--r-- | boost/poly_collection/detail/allocator_adaptor.hpp | 300 | ||||
-rw-r--r-- | boost/poly_collection/detail/any_model.hpp | 21 | ||||
-rw-r--r-- | boost/poly_collection/detail/base_model.hpp | 20 | ||||
-rw-r--r-- | boost/poly_collection/detail/function_model.hpp | 21 | ||||
-rw-r--r-- | boost/poly_collection/detail/newdelete_allocator.hpp | 102 | ||||
-rw-r--r-- | boost/poly_collection/detail/packed_segment.hpp | 43 | ||||
-rw-r--r-- | boost/poly_collection/detail/poly_collection.hpp | 16 | ||||
-rw-r--r-- | boost/poly_collection/detail/segment.hpp | 44 | ||||
-rw-r--r-- | boost/poly_collection/detail/segment_backend.hpp | 9 | ||||
-rw-r--r-- | boost/poly_collection/detail/split_segment.hpp | 48 | ||||
-rw-r--r-- | boost/poly_collection/detail/type_info_map.hpp | 152 | ||||
-rw-r--r-- | boost/poly_collection/detail/value_holder.hpp | 88 |
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 */ |