////////////////////////////////////////////////////////////////////////////// // // (C) Copyright Pablo Halpern 2009. 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) // ////////////////////////////////////////////////////////////////////////////// // // (C) Copyright Ion Gaztanaga 2011-2012. 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/container for documentation. // ////////////////////////////////////////////////////////////////////////////// #ifndef BOOST_CONTAINER_ALLOCATOR_SCOPED_ALLOCATOR_HPP #define BOOST_CONTAINER_ALLOCATOR_SCOPED_ALLOCATOR_HPP #if (defined MSC_VER) && (_MSC_VER >= 1200) # pragma once #endif #include #include #include #include #include #include #include #include #include #if defined(BOOST_NO_VARIADIC_TEMPLATES) #include #endif namespace boost { namespace container { #if defined(BOOST_CONTAINER_PERFECT_FORWARDING) #if !defined(BOOST_CONTAINER_UNIMPLEMENTED_PACK_EXPANSION_TO_FIXED_LIST) template class scoped_allocator_adaptor; #else // #if !defined(BOOST_CONTAINER_UNIMPLEMENTED_PACK_EXPANSION_TO_FIXED_LIST) template class scoped_allocator_adaptor; template class scoped_allocator_adaptor; #endif // #if !defined(BOOST_CONTAINER_UNIMPLEMENTED_PACK_EXPANSION_TO_FIXED_LIST) #else // #if defined(BOOST_CONTAINER_PERFECT_FORWARDING) || defined(BOOST_CONTAINER_DOXYGEN_INVOKED) template class scoped_allocator_adaptor; #endif //! The allocator_arg_t struct is an empty structure type used as a unique type to //! disambiguate constructor and function overloading. Specifically, several types //! have constructors with allocator_arg_t as the first argument, immediately followed //! by an argument of a type that satisfies the Allocator requirements struct allocator_arg_t{}; //! A instance of type allocator_arg_t //! static const allocator_arg_t allocator_arg = allocator_arg_t(); //! Remark: if a specialization is derived from true_type, indicates that T may be constructed //! with an allocator as its last constructor argument. Ideally, all constructors of T (including the //! copy and move constructors) should have a variant that accepts a final argument of //! allocator_type. //! //! Requires: if a specialization is derived from true_type, T must have a nested type, //! allocator_type and at least one constructor for which allocator_type is the last //! parameter. If not all constructors of T can be called with a final allocator_type argument, //! and if T is used in a context where a container must call such a constructor, then the program is //! ill-formed. //! //! [Example: //! template > //! class Z { //! public: //! typedef A allocator_type; //! //! // Default constructor with optional allocator suffix //! Z(const allocator_type& a = allocator_type()); //! //! // Copy constructor and allocator-extended copy constructor //! Z(const Z& zz); //! Z(const Z& zz, const allocator_type& a); //! }; //! //! // Specialize trait for class template Z //! template > //! struct constructible_with_allocator_suffix > //! : ::boost::true_type { }; //! -- end example] //! //! Note: This trait is a workaround inspired by "N2554: The Scoped Allocator Model (Rev 2)" //! (Pablo Halpern, 2008-02-29) to backport the scoped allocator model to C++03, as //! in C++03 there is no mechanism to detect if a type can be constructed from arbitrary arguments. //! Applications aiming portability with several compilers should always define this trait. //! //! In conforming C++11 compilers or compilers supporting SFINAE expressions //! (when BOOST_NO_SFINAE_EXPR is NOT defined), this trait is ignored and C++11 rules will be used //! to detect if a type should be constructed with suffix or prefix allocator arguments. template struct constructible_with_allocator_suffix : ::boost::false_type {}; //! Remark: if a specialization is derived from true_type, indicates that T may be constructed //! with allocator_arg and T::allocator_type as its first two constructor arguments. //! Ideally, all constructors of T (including the copy and move constructors) should have a variant //! that accepts these two initial arguments. //! //! Requires: if a specialization is derived from true_type, T must have a nested type, //! allocator_type and at least one constructor for which allocator_arg_t is the first //! parameter and allocator_type is the second parameter. If not all constructors of T can be //! called with these initial arguments, and if T is used in a context where a container must call such //! a constructor, then the program is ill-formed. //! //! [Example: //! template > //! class Y { //! public: //! typedef A allocator_type; //! //! // Default constructor with and allocator-extended default constructor //! Y(); //! Y(allocator_arg_t, const allocator_type& a); //! //! // Copy constructor and allocator-extended copy constructor //! Y(const Y& yy); //! Y(allocator_arg_t, const allocator_type& a, const Y& yy); //! //! // Variadic constructor and allocator-extended variadic constructor //! template Y(Args&& args...); //! template //! Y(allocator_arg_t, const allocator_type& a, Args&&... args); //! }; //! //! // Specialize trait for class template Y //! template > //! struct constructible_with_allocator_prefix > //! : ::boost::true_type { }; //! //! -- end example] //! //! Note: This trait is a workaround inspired by "N2554: The Scoped Allocator Model (Rev 2)" //! (Pablo Halpern, 2008-02-29) to backport the scoped allocator model to C++03, as //! in C++03 there is no mechanism to detect if a type can be constructed from arbitrary arguments. //! Applications aiming portability with several compilers should always define this trait. //! //! In conforming C++11 compilers or compilers supporting SFINAE expressions //! (when BOOST_NO_SFINAE_EXPR is NOT defined), this trait is ignored and C++11 rules will be used //! to detect if a type should be constructed with suffix or prefix allocator arguments. template struct constructible_with_allocator_prefix : ::boost::false_type {}; ///@cond namespace container_detail { template struct uses_allocator_imp { // Use SFINAE (Substitution Failure Is Not An Error) to detect the // presence of an 'allocator_type' nested type convertilble from Alloc. private: // Match this function if TypeT::allocator_type exists and is // implicitly convertible from Alloc template static char test(int, typename U::allocator_type); // Match this function if TypeT::allocator_type does not exist or is // not convertible from Alloc. template static int test(LowPriorityConversion, LowPriorityConversion); static Alloc alloc; // Declared but not defined public: enum { value = sizeof(test(0, alloc)) == sizeof(char) }; }; } //namespace container_detail { ///@endcond //! Remark: Automatically detects if T has a nested allocator_type that is convertible from //! Alloc. Meets the BinaryTypeTrait requirements ([meta.rqmts] 20.4.1). A program may //! specialize this type to derive from true_type for a T of user-defined type if T does not //! have a nested allocator_type but is nonetheless constructible using the specified Alloc. //! //! Result: derived from true_type if Convertible and //! derived from false_type otherwise. template struct uses_allocator : boost::integral_constant::value> {}; ///@cond namespace container_detail { template struct is_scoped_allocator_imp { template static char test(int, typename T::outer_allocator_type*); template static int test(LowPriorityConversion, void*); static const bool value = (sizeof(char) == sizeof(test(0, 0))); }; template::value > struct outermost_allocator_type_impl { typedef typename MaybeScopedAlloc::outer_allocator_type outer_type; typedef typename outermost_allocator_type_impl::type type; }; template struct outermost_allocator_type_impl { typedef MaybeScopedAlloc type; }; template::value > struct outermost_allocator_imp { typedef MaybeScopedAlloc type; static type &get(MaybeScopedAlloc &a) { return a; } static const type &get(const MaybeScopedAlloc &a) { return a; } }; template struct outermost_allocator_imp { typedef typename MaybeScopedAlloc::outer_allocator_type outer_type; typedef typename outermost_allocator_type_impl::type type; static type &get(MaybeScopedAlloc &a) { return outermost_allocator_imp::get(a.outer_allocator()); } static const type &get(const MaybeScopedAlloc &a) { return outermost_allocator_imp::get(a.outer_allocator()); } }; } //namespace container_detail { template struct is_scoped_allocator : boost::integral_constant::value> {}; template struct outermost_allocator : container_detail::outermost_allocator_imp {}; template typename container_detail::outermost_allocator_imp::type & get_outermost_allocator(Alloc &a) { return container_detail::outermost_allocator_imp::get(a); } template const typename container_detail::outermost_allocator_imp::type & get_outermost_allocator(const Alloc &a) { return container_detail::outermost_allocator_imp::get(a); } namespace container_detail { // Check if we can detect is_convertible using advanced SFINAE expressions #if !defined(BOOST_NO_SFINAE_EXPR) //! Code inspired by Mathias Gaunard's is_convertible.cpp found in the Boost mailing list //! http://boost.2283326.n4.nabble.com/type-traits-is-constructible-when-decltype-is-supported-td3575452.html //! Thanks Mathias! //With variadic templates, we need a single class to implement the trait #if !defined(BOOST_NO_VARIADIC_TEMPLATES) template struct is_constructible_impl { typedef char yes_type; struct no_type { char padding[2]; }; template struct dummy; template static yes_type test(dummy()...))>*); template static no_type test(...); static const bool value = sizeof(test(0)) == sizeof(yes_type); }; template struct is_constructible : boost::integral_constant::value> {}; template struct is_constructible_with_allocator_prefix : is_constructible {}; #else // #if !defined(BOOST_NO_VARIADIC_TEMPLATES) //Without variadic templates, we need to use de preprocessor to generate //some specializations. #define BOOST_CONTAINER_MAX_IS_CONSTRUCTIBLE_PARAMETERS \ BOOST_PP_ADD(BOOST_CONTAINER_MAX_CONSTRUCTOR_PARAMETERS, 3) //! //Generate N+1 template parameters so that we can specialize N template struct is_constructible_impl; //Generate N specializations, from 0 to //BOOST_CONTAINER_MAX_IS_CONSTRUCTIBLE_PARAMETERS parameters #define BOOST_PP_LOCAL_MACRO(n) \ template \ struct is_constructible_impl \ \ { \ typedef char yes_type; \ struct no_type \ { char padding[2]; }; \ \ template \ struct dummy; \ \ template \ static yes_type test(dummy*); \ \ template \ static no_type test(...); \ \ static const bool value = sizeof(test(0)) == sizeof(yes_type); \ }; \ //! #define BOOST_PP_LOCAL_LIMITS (0, BOOST_CONTAINER_MAX_IS_CONSTRUCTIBLE_PARAMETERS) #include BOOST_PP_LOCAL_ITERATE() //Finally just inherit from the implementation to define he trait template< class T BOOST_PP_ENUM_TRAILING( BOOST_CONTAINER_MAX_IS_CONSTRUCTIBLE_PARAMETERS , BOOST_CONTAINER_PP_TEMPLATE_PARAM_WITH_DEFAULT , void) > struct is_constructible : boost::integral_constant < bool , is_constructible_impl < T BOOST_PP_ENUM_TRAILING_PARAMS(BOOST_CONTAINER_MAX_IS_CONSTRUCTIBLE_PARAMETERS, P) , void>::value > {}; //Finally just inherit from the implementation to define he trait template struct is_constructible_with_allocator_prefix : is_constructible < T, allocator_arg_t, InnerAlloc BOOST_PP_ENUM_TRAILING_PARAMS(BOOST_PP_SUB(BOOST_CONTAINER_MAX_IS_CONSTRUCTIBLE_PARAMETERS, 2), P) > {}; /* template struct is_constructible_with_allocator_suffix : is_constructible < T BOOST_PP_ENUM_TRAILING_PARAMS(BOOST_PP_SUB(BOOST_CONTAINER_MAX_IS_CONSTRUCTIBLE_PARAMETERS, 1), P) , InnerAlloc > {};*/ #endif // #if !defined(BOOST_NO_VARIADIC_TEMPLATES) #else // #if !defined(BOOST_NO_SFINAE_EXPR) //Without advanced SFINAE expressions, we can't use is_constructible //so backup to constructible_with_allocator_xxx #if !defined(BOOST_NO_VARIADIC_TEMPLATES) template < class T, class InnerAlloc, class ...Args> struct is_constructible_with_allocator_prefix : constructible_with_allocator_prefix {}; /* template < class T, class InnerAlloc, class ...Args> struct is_constructible_with_allocator_suffix : constructible_with_allocator_suffix {};*/ #else // #if !defined(BOOST_NO_VARIADIC_TEMPLATES) template < class T , class InnerAlloc BOOST_PP_ENUM_TRAILING( BOOST_CONTAINER_MAX_CONSTRUCTOR_PARAMETERS , BOOST_CONTAINER_PP_TEMPLATE_PARAM_WITH_DEFAULT , void) > struct is_constructible_with_allocator_prefix : constructible_with_allocator_prefix {}; /* template < class T , class InnerAlloc BOOST_PP_ENUM_TRAILING( BOOST_CONTAINER_MAX_CONSTRUCTOR_PARAMETERS , BOOST_CONTAINER_PP_TEMPLATE_PARAM_WITH_DEFAULT , void) > struct is_constructible_with_allocator_suffix : constructible_with_allocator_suffix {};*/ #endif // #if !defined(BOOST_NO_VARIADIC_TEMPLATES) #endif // #if !defined(BOOST_NO_SFINAE_EXPR) #if !defined(BOOST_NO_VARIADIC_TEMPLATES) template < typename OutermostAlloc , typename InnerAlloc , typename T , class ...Args > inline void dispatch_allocator_prefix_suffix ( boost::true_type use_alloc_prefix, OutermostAlloc& outermost_alloc , InnerAlloc& inner_alloc, T* p, BOOST_FWD_REF(Args) ...args) { (void)use_alloc_prefix; allocator_traits::construct ( outermost_alloc, p, allocator_arg, inner_alloc, ::boost::forward(args)...); } template < typename OutermostAlloc , typename InnerAlloc , typename T , class ...Args > inline void dispatch_allocator_prefix_suffix ( boost::false_type use_alloc_prefix, OutermostAlloc& outermost_alloc , InnerAlloc &inner_alloc, T* p, BOOST_FWD_REF(Args)...args) { (void)use_alloc_prefix; allocator_traits::construct (outermost_alloc, p, ::boost::forward(args)..., inner_alloc); } template < typename OutermostAlloc , typename InnerAlloc , typename T , class ...Args > inline void dispatch_uses_allocator ( boost::true_type uses_allocator, OutermostAlloc& outermost_alloc , InnerAlloc& inner_alloc, T* p, BOOST_FWD_REF(Args)...args) { (void)uses_allocator; //BOOST_STATIC_ASSERT((is_constructible_with_allocator_prefix::value || // is_constructible_with_allocator_suffix::value )); dispatch_allocator_prefix_suffix ( is_constructible_with_allocator_prefix() , outermost_alloc, inner_alloc, p, ::boost::forward(args)...); } template < typename OutermostAlloc , typename InnerAlloc , typename T , class ...Args > inline void dispatch_uses_allocator ( boost::false_type uses_allocator, OutermostAlloc & outermost_alloc , InnerAlloc & inner_alloc ,T* p, BOOST_FWD_REF(Args)...args) { (void)uses_allocator; (void)inner_alloc; allocator_traits::construct (outermost_alloc, p, ::boost::forward(args)...); } #else //#if !defined(BOOST_NO_VARIADIC_TEMPLATES) #define BOOST_PP_LOCAL_MACRO(n) \ template < typename OutermostAlloc \ , typename InnerAlloc \ , typename T \ BOOST_PP_ENUM_TRAILING_PARAMS(n, class P) \ > \ inline void dispatch_allocator_prefix_suffix( \ boost::true_type use_alloc_prefix, \ OutermostAlloc& outermost_alloc, \ InnerAlloc& inner_alloc, \ T* p \ BOOST_PP_ENUM_TRAILING(n, BOOST_CONTAINER_PP_PARAM_LIST, _)) \ { \ (void)use_alloc_prefix, \ allocator_traits::construct \ (outermost_alloc, p, allocator_arg, inner_alloc \ BOOST_PP_ENUM_TRAILING(n, BOOST_CONTAINER_PP_PARAM_FORWARD, _)); \ } \ \ template < typename OutermostAlloc \ , typename InnerAlloc \ , typename T \ BOOST_PP_ENUM_TRAILING_PARAMS(n, class P) \ > \ inline void dispatch_allocator_prefix_suffix( \ boost::false_type use_alloc_prefix, \ OutermostAlloc& outermost_alloc, \ InnerAlloc& inner_alloc, \ T* p BOOST_PP_ENUM_TRAILING(n, BOOST_CONTAINER_PP_PARAM_LIST, _)) \ { \ (void)use_alloc_prefix; \ allocator_traits::construct \ (outermost_alloc, p \ BOOST_PP_ENUM_TRAILING(n, BOOST_CONTAINER_PP_PARAM_FORWARD, _) \ , inner_alloc); \ } \ \ template < typename OutermostAlloc \ , typename InnerAlloc \ , typename T \ BOOST_PP_ENUM_TRAILING_PARAMS(n, class P) \ > \ inline void dispatch_uses_allocator(boost::true_type uses_allocator, \ OutermostAlloc& outermost_alloc, \ InnerAlloc& inner_alloc, \ T* p BOOST_PP_ENUM_TRAILING(n, BOOST_CONTAINER_PP_PARAM_LIST, _)) \ { \ (void)uses_allocator; \ dispatch_allocator_prefix_suffix \ (is_constructible_with_allocator_prefix \ < T, InnerAlloc BOOST_PP_ENUM_TRAILING_PARAMS(n, P)>() \ , outermost_alloc, inner_alloc, p \ BOOST_PP_ENUM_TRAILING(n, BOOST_CONTAINER_PP_PARAM_FORWARD, _)); \ } \ \ template < typename OutermostAlloc \ , typename InnerAlloc \ , typename T \ BOOST_PP_ENUM_TRAILING_PARAMS(n, class P) \ > \ inline void dispatch_uses_allocator(boost::false_type uses_allocator \ ,OutermostAlloc & outermost_alloc \ ,InnerAlloc & inner_alloc \ ,T* p BOOST_PP_ENUM_TRAILING(n, BOOST_CONTAINER_PP_PARAM_LIST, _)) \ { \ (void)uses_allocator; (void)inner_alloc; \ allocator_traits::construct \ (outermost_alloc, p BOOST_PP_ENUM_TRAILING(n, BOOST_CONTAINER_PP_PARAM_FORWARD, _)); \ } \ //! #define BOOST_PP_LOCAL_LIMITS (0, BOOST_CONTAINER_MAX_CONSTRUCTOR_PARAMETERS) #include BOOST_PP_LOCAL_ITERATE() #endif //#if !defined(BOOST_NO_VARIADIC_TEMPLATES) #if !defined(BOOST_NO_VARIADIC_TEMPLATES) template class scoped_allocator_adaptor_base : public OuterAlloc { typedef allocator_traits outer_traits_type; BOOST_COPYABLE_AND_MOVABLE(scoped_allocator_adaptor_base) public: template struct rebind_base { typedef scoped_allocator_adaptor_base other; }; typedef OuterAlloc outer_allocator_type; typedef scoped_allocator_adaptor inner_allocator_type; typedef boost::integral_constant< bool, outer_traits_type::propagate_on_container_copy_assignment::value || inner_allocator_type::propagate_on_container_copy_assignment::value > propagate_on_container_copy_assignment; typedef boost::integral_constant< bool, outer_traits_type::propagate_on_container_move_assignment::value || inner_allocator_type::propagate_on_container_move_assignment::value > propagate_on_container_move_assignment; typedef boost::integral_constant< bool, outer_traits_type::propagate_on_container_swap::value || inner_allocator_type::propagate_on_container_swap::value > propagate_on_container_swap; scoped_allocator_adaptor_base() {} template scoped_allocator_adaptor_base(BOOST_FWD_REF(OuterA2) outerAlloc, const InnerAllocs &...args) : outer_allocator_type(::boost::forward(outerAlloc)) , m_inner(args...) {} scoped_allocator_adaptor_base(const scoped_allocator_adaptor_base& other) : outer_allocator_type(other.outer_allocator()) , m_inner(other.inner_allocator()) {} scoped_allocator_adaptor_base(BOOST_RV_REF(scoped_allocator_adaptor_base) other) : outer_allocator_type(::boost::move(other.outer_allocator())) , m_inner(::boost::move(other.inner_allocator())) {} template scoped_allocator_adaptor_base (const scoped_allocator_adaptor_base& other) : outer_allocator_type(other.outer_allocator()) , m_inner(other.inner_allocator()) {} template scoped_allocator_adaptor_base (BOOST_RV_REF_BEG scoped_allocator_adaptor_base BOOST_RV_REF_END other) : outer_allocator_type(other.outer_allocator()) , m_inner(other.inner_allocator()) {} protected: struct internal_type_t{}; template scoped_allocator_adaptor_base ( internal_type_t , BOOST_FWD_REF(OuterA2) outerAlloc , const inner_allocator_type &inner) : outer_allocator_type(::boost::forward(outerAlloc)) , m_inner(inner) {} public: scoped_allocator_adaptor_base &operator= (BOOST_COPY_ASSIGN_REF(scoped_allocator_adaptor_base) other) { outer_allocator_type::operator=(other.outer_allocator()); m_inner = other.inner_allocator(); return *this; } scoped_allocator_adaptor_base &operator=(BOOST_RV_REF(scoped_allocator_adaptor_base) other) { outer_allocator_type::operator=(boost::move(other.outer_allocator())); m_inner = ::boost::move(other.inner_allocator()); return *this; } inner_allocator_type& inner_allocator() { return m_inner; } inner_allocator_type const& inner_allocator() const { return m_inner; } outer_allocator_type & outer_allocator() { return static_cast(*this); } const outer_allocator_type &outer_allocator() const { return static_cast(*this); } private: inner_allocator_type m_inner; }; #else //#if !defined(BOOST_NO_VARIADIC_TEMPLATES) //Let's add a dummy first template parameter to allow creating //specializations up to maximum InnerAlloc count template < typename OuterAlloc , bool Dummy BOOST_PP_ENUM_TRAILING_PARAMS(BOOST_CONTAINER_MAX_CONSTRUCTOR_PARAMETERS, class Q) > class scoped_allocator_adaptor_base; //Specializations for the adaptor with InnerAlloc allocators #define BOOST_PP_LOCAL_MACRO(n) \ template \ class scoped_allocator_adaptor_base \ : public OuterAlloc \ { \ typedef allocator_traits outer_traits_type; \ BOOST_COPYABLE_AND_MOVABLE(scoped_allocator_adaptor_base) \ \ public: \ template \ struct rebind_base \ { \ typedef scoped_allocator_adaptor_base other; \ }; \ \ typedef OuterAlloc outer_allocator_type; \ typedef scoped_allocator_adaptor inner_allocator_type; \ typedef boost::integral_constant< \ bool, \ outer_traits_type::propagate_on_container_copy_assignment::value || \ inner_allocator_type::propagate_on_container_copy_assignment::value \ > propagate_on_container_copy_assignment; \ typedef boost::integral_constant< \ bool, \ outer_traits_type::propagate_on_container_move_assignment::value || \ inner_allocator_type::propagate_on_container_move_assignment::value \ > propagate_on_container_move_assignment; \ typedef boost::integral_constant< \ bool, \ outer_traits_type::propagate_on_container_swap::value || \ inner_allocator_type::propagate_on_container_swap::value \ > propagate_on_container_swap; \ \ scoped_allocator_adaptor_base() \ {} \ \ template \ scoped_allocator_adaptor_base(BOOST_FWD_REF(OuterA2) outerAlloc \ BOOST_PP_ENUM_TRAILING(n, BOOST_CONTAINER_PP_CONST_REF_PARAM_LIST_Q, _)) \ : outer_allocator_type(::boost::forward(outerAlloc)) \ , m_inner(BOOST_PP_ENUM_PARAMS(n, q)) \ {} \ \ scoped_allocator_adaptor_base(const scoped_allocator_adaptor_base& other) \ : outer_allocator_type(other.outer_allocator()) \ , m_inner(other.inner_allocator()) \ {} \ \ scoped_allocator_adaptor_base(BOOST_RV_REF(scoped_allocator_adaptor_base) other) \ : outer_allocator_type(::boost::move(other.outer_allocator())) \ , m_inner(::boost::move(other.inner_allocator())) \ {} \ \ template \ scoped_allocator_adaptor_base(const scoped_allocator_adaptor_base& other) \ : outer_allocator_type(other.outer_allocator()) \ , m_inner(other.inner_allocator()) \ {} \ \ template \ scoped_allocator_adaptor_base \ (BOOST_RV_REF_BEG scoped_allocator_adaptor_base BOOST_RV_REF_END other) \ : outer_allocator_type(other.outer_allocator()) \ , m_inner(other.inner_allocator()) \ {} \ \ protected: \ struct internal_type_t{}; \ \ template \ scoped_allocator_adaptor_base \ ( internal_type_t \ , BOOST_FWD_REF(OuterA2) outerAlloc \ , const inner_allocator_type &inner) \ : outer_allocator_type(::boost::forward(outerAlloc)) \ , m_inner(inner) \ {} \ \ public: \ scoped_allocator_adaptor_base &operator= \ (BOOST_COPY_ASSIGN_REF(scoped_allocator_adaptor_base) other) \ { \ outer_allocator_type::operator=(other.outer_allocator()); \ m_inner = other.inner_allocator(); \ return *this; \ } \ \ scoped_allocator_adaptor_base &operator=(BOOST_RV_REF(scoped_allocator_adaptor_base) other) \ { \ outer_allocator_type::operator=(boost::move(other.outer_allocator())); \ m_inner = ::boost::move(other.inner_allocator()); \ return *this; \ } \ \ inner_allocator_type& inner_allocator() \ { return m_inner; } \ \ inner_allocator_type const& inner_allocator() const \ { return m_inner; } \ \ outer_allocator_type & outer_allocator() \ { return static_cast(*this); } \ \ const outer_allocator_type &outer_allocator() const \ { return static_cast(*this); } \ \ private: \ inner_allocator_type m_inner; \ }; \ //! #define BOOST_PP_LOCAL_LIMITS (1, BOOST_CONTAINER_MAX_CONSTRUCTOR_PARAMETERS) #include BOOST_PP_LOCAL_ITERATE() #endif //#if !defined(BOOST_NO_VARIADIC_TEMPLATES) //Specialization for adaptor without any InnerAlloc template class scoped_allocator_adaptor_base < OuterAlloc #if defined(BOOST_NO_VARIADIC_TEMPLATES) , true BOOST_PP_ENUM_TRAILING(BOOST_CONTAINER_MAX_CONSTRUCTOR_PARAMETERS, BOOST_CONTAINER_PP_IDENTITY, nat) #endif > : public OuterAlloc { BOOST_COPYABLE_AND_MOVABLE(scoped_allocator_adaptor_base) public: template struct rebind_base { typedef scoped_allocator_adaptor_base ::template portable_rebind_alloc::type #if defined(BOOST_NO_VARIADIC_TEMPLATES) , true BOOST_PP_ENUM_TRAILING(BOOST_CONTAINER_MAX_CONSTRUCTOR_PARAMETERS, BOOST_CONTAINER_PP_IDENTITY, container_detail::nat) #endif > other; }; typedef OuterAlloc outer_allocator_type; typedef allocator_traits outer_traits_type; typedef scoped_allocator_adaptor inner_allocator_type; typedef typename outer_traits_type:: propagate_on_container_copy_assignment propagate_on_container_copy_assignment; typedef typename outer_traits_type:: propagate_on_container_move_assignment propagate_on_container_move_assignment; typedef typename outer_traits_type:: propagate_on_container_swap propagate_on_container_swap; scoped_allocator_adaptor_base() {} template scoped_allocator_adaptor_base(BOOST_FWD_REF(OuterA2) outerAlloc) : outer_allocator_type(::boost::forward(outerAlloc)) {} scoped_allocator_adaptor_base(const scoped_allocator_adaptor_base& other) : outer_allocator_type(other.outer_allocator()) {} scoped_allocator_adaptor_base(BOOST_RV_REF(scoped_allocator_adaptor_base) other) : outer_allocator_type(::boost::move(other.outer_allocator())) {} template scoped_allocator_adaptor_base (const scoped_allocator_adaptor_base< OuterA2 #if defined(BOOST_NO_VARIADIC_TEMPLATES) , true BOOST_PP_ENUM_TRAILING(BOOST_CONTAINER_MAX_CONSTRUCTOR_PARAMETERS, BOOST_CONTAINER_PP_IDENTITY, container_detail::nat) #endif >& other) : outer_allocator_type(other.outer_allocator()) {} template scoped_allocator_adaptor_base (BOOST_RV_REF_BEG scoped_allocator_adaptor_base< OuterA2 #if defined(BOOST_NO_VARIADIC_TEMPLATES) , true BOOST_PP_ENUM_TRAILING(BOOST_CONTAINER_MAX_CONSTRUCTOR_PARAMETERS, BOOST_CONTAINER_PP_IDENTITY, container_detail::nat) #endif > BOOST_RV_REF_END other) : outer_allocator_type(other.outer_allocator()) {} protected: struct internal_type_t{}; template scoped_allocator_adaptor_base(internal_type_t, BOOST_FWD_REF(OuterA2) outerAlloc, const inner_allocator_type &) : outer_allocator_type(::boost::forward(outerAlloc)) {} public: scoped_allocator_adaptor_base &operator=(BOOST_COPY_ASSIGN_REF(scoped_allocator_adaptor_base) other) { outer_allocator_type::operator=(other.outer_allocator()); return *this; } scoped_allocator_adaptor_base &operator=(BOOST_RV_REF(scoped_allocator_adaptor_base) other) { outer_allocator_type::operator=(boost::move(other.outer_allocator())); return *this; } inner_allocator_type& inner_allocator() { return static_cast(*this); } inner_allocator_type const& inner_allocator() const { return static_cast(*this); } outer_allocator_type & outer_allocator() { return static_cast(*this); } const outer_allocator_type &outer_allocator() const { return static_cast(*this); } }; } //namespace container_detail { ///@endcond //Scoped allocator #if !defined(BOOST_NO_VARIADIC_TEMPLATES) || defined(BOOST_CONTAINER_DOXYGEN_INVOKED) #if !defined(BOOST_CONTAINER_UNIMPLEMENTED_PACK_EXPANSION_TO_FIXED_LIST) //! This class is a C++03-compatible implementation of std::scoped_allocator_adaptor. //! The class template scoped_allocator_adaptor is an allocator template that specifies //! the memory resource (the outer allocator) to be used by a container (as any other //! allocator does) and also specifies an inner allocator resource to be passed to //! the constructor of every element within the container. //! //! This adaptor is //! instantiated with one outer and zero or more inner allocator types. If //! instantiated with only one allocator type, the inner allocator becomes the //! scoped_allocator_adaptor itself, thus using the same allocator resource for the //! container and every element within the container and, if the elements themselves //! are containers, each of their elements recursively. If instantiated with more than //! one allocator, the first allocator is the outer allocator for use by the container, //! the second allocator is passed to the constructors of the container's elements, //! and, if the elements themselves are containers, the third allocator is passed to //! the elements' elements, and so on. If containers are nested to a depth greater //! than the number of allocators, the last allocator is used repeatedly, as in the //! single-allocator case, for any remaining recursions. //! //! [Note: The //! scoped_allocator_adaptor is derived from the outer allocator type so it can be //! substituted for the outer allocator type in most expressions. -end note] //! //! In the construct member functions, `OUTERMOST(x)` is x if x does not have //! an `outer_allocator()` member function and //! `OUTERMOST(x.outer_allocator())` otherwise; `OUTERMOST_ALLOC_TRAITS(x)` is //! `allocator_traits`. //! //! [Note: `OUTERMOST(x)` and //! `OUTERMOST_ALLOC_TRAITS(x)` are recursive operations. It is incumbent upon //! the definition of `outer_allocator()` to ensure that the recursion terminates. //! It will terminate for all instantiations of scoped_allocator_adaptor. -end note] template class scoped_allocator_adaptor #else // #if !defined(BOOST_CONTAINER_UNIMPLEMENTED_PACK_EXPANSION_TO_FIXED_LIST) template class scoped_allocator_adaptor #endif // #if !defined(BOOST_CONTAINER_UNIMPLEMENTED_PACK_EXPANSION_TO_FIXED_LIST) #else // #if !defined(BOOST_NO_VARIADIC_TEMPLATES) || defined(BOOST_CONTAINER_DOXYGEN_INVOKED) template class scoped_allocator_adaptor #endif : public container_detail::scoped_allocator_adaptor_base { BOOST_COPYABLE_AND_MOVABLE(scoped_allocator_adaptor) public: /// @cond typedef container_detail::scoped_allocator_adaptor_base base_type; typedef typename base_type::internal_type_t internal_type_t; /// @endcond typedef OuterAlloc outer_allocator_type; //! Type: For exposition only //! typedef allocator_traits outer_traits_type; //! Type: `scoped_allocator_adaptor` if `sizeof...(InnerAllocs)` is zero; otherwise, //! `scoped_allocator_adaptor`. typedef typename base_type::inner_allocator_type inner_allocator_type; typedef typename outer_traits_type::value_type value_type; typedef typename outer_traits_type::size_type size_type; typedef typename outer_traits_type::difference_type difference_type; typedef typename outer_traits_type::pointer pointer; typedef typename outer_traits_type::const_pointer const_pointer; typedef typename outer_traits_type::void_pointer void_pointer; typedef typename outer_traits_type::const_void_pointer const_void_pointer; //! Type: `true_type` if `allocator_traits::propagate_on_container_copy_assignment::value` is //! true for any `A` in the set of `OuterAlloc` and `InnerAllocs...`; otherwise, false_type. typedef typename base_type:: propagate_on_container_copy_assignment propagate_on_container_copy_assignment; //! Type: `true_type` if `allocator_traits::propagate_on_container_move_assignment::value` is //! true for any `A` in the set of `OuterAlloc` and `InnerAllocs...`; otherwise, false_type. typedef typename base_type:: propagate_on_container_move_assignment propagate_on_container_move_assignment; //! Type: `true_type` if `allocator_traits::propagate_on_container_swap::value` is true for any //! `A` in the set of `OuterAlloc` and `InnerAllocs...`; otherwise, false_type. typedef typename base_type:: propagate_on_container_swap propagate_on_container_swap; //! Type: Rebinds scoped allocator to //! `typedef scoped_allocator_adaptor //! < typename outer_traits_type::template portable_rebind_alloc::type //! , InnerAllocs... >` template struct rebind { typedef scoped_allocator_adaptor < typename outer_traits_type::template portable_rebind_alloc::type #if !defined(BOOST_NO_VARIADIC_TEMPLATES) || defined(BOOST_CONTAINER_DOXYGEN_INVOKED) , InnerAllocs... #else BOOST_PP_ENUM_TRAILING_PARAMS(BOOST_CONTAINER_MAX_CONSTRUCTOR_PARAMETERS, Q) #endif > other; }; //! Effects: value-initializes the OuterAlloc base class //! and the inner allocator object. scoped_allocator_adaptor() {} ~scoped_allocator_adaptor() {} //! Effects: initializes each allocator within the adaptor with //! the corresponding allocator from other. scoped_allocator_adaptor(const scoped_allocator_adaptor& other) : base_type(other.base()) {} //! Effects: move constructs each allocator within the adaptor with //! the corresponding allocator from other. scoped_allocator_adaptor(BOOST_RV_REF(scoped_allocator_adaptor) other) : base_type(::boost::move(other.base())) {} #if !defined(BOOST_NO_VARIADIC_TEMPLATES) || defined(BOOST_CONTAINER_DOXYGEN_INVOKED) //! Requires: OuterAlloc shall be constructible from OuterA2. //! //! Effects: initializes the OuterAlloc base class with boost::forward(outerAlloc) and inner //! with innerAllocs...(hence recursively initializing each allocator within the adaptor with the //! corresponding allocator from the argument list). template scoped_allocator_adaptor(BOOST_FWD_REF(OuterA2) outerAlloc, const InnerAllocs & ...innerAllocs) : base_type(::boost::forward(outerAlloc), innerAllocs...) {} #else // #if !defined(BOOST_NO_VARIADIC_TEMPLATES) || defined(BOOST_CONTAINER_DOXYGEN_INVOKED) #define BOOST_PP_LOCAL_MACRO(n) \ template \ scoped_allocator_adaptor(BOOST_FWD_REF(OuterA2) outerAlloc \ BOOST_PP_ENUM_TRAILING(n, BOOST_CONTAINER_PP_CONST_REF_PARAM_LIST_Q, _)) \ : base_type(::boost::forward(outerAlloc) \ BOOST_PP_ENUM_TRAILING_PARAMS(n, q) \ ) \ {} \ //! #define BOOST_PP_LOCAL_LIMITS (0, BOOST_CONTAINER_MAX_CONSTRUCTOR_PARAMETERS) #include BOOST_PP_LOCAL_ITERATE() #endif // #if !defined(BOOST_NO_VARIADIC_TEMPLATES) || defined(BOOST_CONTAINER_DOXYGEN_INVOKED) //! Requires: OuterAlloc shall be constructible from OuterA2. //! //! Effects: initializes each allocator within the adaptor with the corresponding allocator from other. template scoped_allocator_adaptor(const scoped_allocator_adaptor &other) : base_type(other.base()) {} //! Requires: OuterAlloc shall be constructible from OuterA2. //! //! Effects: initializes each allocator within the adaptor with the corresponding allocator //! rvalue from other. template scoped_allocator_adaptor(BOOST_RV_REF_BEG scoped_allocator_adaptor BOOST_RV_REF_END other) : base_type(::boost::move(other.base())) {} scoped_allocator_adaptor &operator=(BOOST_COPY_ASSIGN_REF(scoped_allocator_adaptor) other) { base_type::operator=(static_cast(other)); return *this; } scoped_allocator_adaptor &operator=(BOOST_RV_REF(scoped_allocator_adaptor) other) { base_type::operator=(boost::move(static_cast(other))); return *this; } //! Returns: //! `static_cast(*this)`. outer_allocator_type & outer_allocator() { return *this; } //! Returns: //! `static_cast(*this)`. const outer_allocator_type &outer_allocator() const { return *this; } //! Returns: //! *this if `sizeof...(InnerAllocs)` is zero; otherwise, inner. inner_allocator_type& inner_allocator() { return base_type::inner_allocator(); } //! Returns: //! *this if `sizeof...(InnerAllocs)` is zero; otherwise, inner. inner_allocator_type const& inner_allocator() const { return base_type::inner_allocator(); } //! Returns: //! `allocator_traits::max_size(outer_allocator())`. size_type max_size() const { return outer_traits_type::max_size(this->outer_allocator()); } //! Effects: //! calls `OUTERMOST_ALLOC_TRAITS(*this)::destroy(OUTERMOST(*this), p)`. template void destroy(T* p) { allocator_traits::type> ::destroy(get_outermost_allocator(this->outer_allocator()), p); } //! Returns: //! `allocator_traits::allocate(outer_allocator(), n)`. pointer allocate(size_type n) { return outer_traits_type::allocate(this->outer_allocator(), n); } //! Returns: //! `allocator_traits::allocate(outer_allocator(), n, hint)`. pointer allocate(size_type n, const_void_pointer hint) { return outer_traits_type::allocate(this->outer_allocator(), n, hint); } //! Effects: //! `allocator_traits::deallocate(outer_allocator(), p, n)`. void deallocate(pointer p, size_type n) { outer_traits_type::deallocate(this->outer_allocator(), p, n); } //! Returns: A new scoped_allocator_adaptor object where each allocator //! A in the adaptor is initialized from the result of calling //! `allocator_traits::select_on_container_copy_construction()` on //! the corresponding allocator in *this. scoped_allocator_adaptor select_on_container_copy_construction() const { return scoped_allocator_adaptor (internal_type_t() ,outer_traits_type::select_on_container_copy_construction(this->outer_allocator()) ,outer_traits_type::select_on_container_copy_construction(this->inner_allocator()) ); } /// @cond base_type &base() { return *this; } const base_type &base() const { return *this; } /// @endcond #if !defined(BOOST_NO_VARIADIC_TEMPLATES) || defined(BOOST_CONTAINER_DOXYGEN_INVOKED) //! Effects: //! 1) If `uses_allocator::value` is false calls //! `OUTERMOST_ALLOC_TRAITS(*this)::construct //! (OUTERMOST(*this), p, std::forward(args)...)`. //! //! 2) Otherwise, if `uses_allocator::value` is true and //! `is_constructible::value` is true, calls //! `OUTERMOST_ALLOC_TRAITS(*this)::construct(OUTERMOST(*this), p, allocator_arg, //! inner_allocator(), std::forward(args)...)`. //! //! [Note: In compilers without advanced decltype SFINAE support, `is_constructible` can't //! be implemented so that condition will be replaced by //! constructible_with_allocator_prefix::value. -end note] //! //! 3) Otherwise, if uses_allocator::value is true and //! `is_constructible::value` is true, calls //! `OUTERMOST_ALLOC_TRAITS(*this)::construct(OUTERMOST(*this), p, //! std::forward(args)..., inner_allocator())`. //! //! [Note: In compilers without advanced decltype SFINAE support, `is_constructible` can't be //! implemented so that condition will be replaced by //! `constructible_with_allocator_suffix::value`. -end note] //! //! 4) Otherwise, the program is ill-formed. //! //! [Note: An error will result if `uses_allocator` evaluates //! to true but the specific constructor does not take an allocator. This definition prevents a silent //! failure to pass an inner allocator to a contained element. -end note] template < typename T, class ...Args> #if defined(BOOST_CONTAINER_DOXYGEN_INVOKED) void #else typename container_detail::enable_if_c::value, void>::type #endif construct(T* p, BOOST_FWD_REF(Args)...args) { container_detail::dispatch_uses_allocator ( uses_allocator() , get_outermost_allocator(this->outer_allocator()) , this->inner_allocator() , p, ::boost::forward(args)...); } #else // #if !defined(BOOST_NO_VARIADIC_TEMPLATES) || defined(BOOST_CONTAINER_DOXYGEN_INVOKED) //Disable this overload if the first argument is pair as some compilers have //overload selection problems when the first parameter is a pair. #define BOOST_PP_LOCAL_MACRO(n) \ template < typename T \ BOOST_PP_ENUM_TRAILING_PARAMS(n, class P) \ > \ typename container_detail::enable_if_c::value, void>::type \ construct(T* p BOOST_PP_ENUM_TRAILING(n, BOOST_CONTAINER_PP_PARAM_LIST, _)) \ { \ container_detail::dispatch_uses_allocator \ ( uses_allocator() \ , get_outermost_allocator(this->outer_allocator()) \ , this->inner_allocator() \ , p BOOST_PP_ENUM_TRAILING(n, BOOST_CONTAINER_PP_PARAM_FORWARD, _)); \ } \ //! #define BOOST_PP_LOCAL_LIMITS (0, BOOST_CONTAINER_MAX_CONSTRUCTOR_PARAMETERS) #include BOOST_PP_LOCAL_ITERATE() #endif // #if !defined(BOOST_NO_VARIADIC_TEMPLATES) || defined(BOOST_CONTAINER_DOXYGEN_INVOKED) template void construct(std::pair* p) { this->construct_pair(p); } template void construct(container_detail::pair* p) { this->construct_pair(p); } template void construct(std::pair* p, BOOST_FWD_REF(U) x, BOOST_FWD_REF(V) y) { this->construct_pair(p, ::boost::forward(x), ::boost::forward(y)); } template void construct(container_detail::pair* p, BOOST_FWD_REF(U) x, BOOST_FWD_REF(V) y) { this->construct_pair(p, ::boost::forward(x), ::boost::forward(y)); } template void construct(std::pair* p, const std::pair& x) { this->construct_pair(p, x); } template void construct( container_detail::pair* p , const container_detail::pair& x) { this->construct_pair(p, x); } template void construct( std::pair* p , BOOST_RV_REF_BEG std::pair BOOST_RV_REF_END x) { this->construct_pair(p, x); } template void construct( container_detail::pair* p , BOOST_RV_REF_BEG container_detail::pair BOOST_RV_REF_END x) { this->construct_pair(p, x); } /// @cond private: template void construct_pair(Pair* p) { this->construct(container_detail::addressof(p->first)); try { this->construct(container_detail::addressof(p->second)); } catch (...) { this->destroy(container_detail::addressof(p->first)); throw; } } template void construct_pair(Pair* p, BOOST_FWD_REF(U) x, BOOST_FWD_REF(V) y) { this->construct(container_detail::addressof(p->first), ::boost::forward(x)); try { this->construct(container_detail::addressof(p->second), ::boost::forward(y)); } catch (...) { this->destroy(container_detail::addressof(p->first)); throw; } } template void construct_pair(Pair* p, const Pair2& pr) { this->construct(container_detail::addressof(p->first), pr.first); try { this->construct(container_detail::addressof(p->second), pr.second); } catch (...) { this->destroy(container_detail::addressof(p->first)); throw; } } template void construct_pair(Pair* p, BOOST_RV_REF(Pair2) pr) { this->construct(container_detail::addressof(p->first), ::boost::move(pr.first)); try { this->construct(container_detail::addressof(p->second), ::boost::move(pr.second)); } catch (...) { this->destroy(container_detail::addressof(p->first)); throw; } } //template //void construct(pair* p, piecewise_construct_t, tuple x, tuple y); private: template scoped_allocator_adaptor(internal_type_t, BOOST_FWD_REF(OuterA2) outer, const inner_allocator_type& inner) : base_type(internal_type_t(), ::boost::forward(outer), inner) {} /// @endcond }; template inline bool operator==( const scoped_allocator_adaptor& a, const scoped_allocator_adaptor& b) { #if !defined(BOOST_NO_VARIADIC_TEMPLATES) || defined(BOOST_CONTAINER_DOXYGEN_INVOKED) const bool has_zero_inner = sizeof...(InnerAllocs) == 0u; #else const bool has_zero_inner = boost::container::container_detail::is_same ::value; #endif return a.outer_allocator() == b.outer_allocator() && (has_zero_inner || a.inner_allocator() == b.inner_allocator()); } template inline bool operator!=( const scoped_allocator_adaptor& a, const scoped_allocator_adaptor& b) { return ! (a == b); } }} // namespace boost { namespace container { #include #endif // BOOST_CONTAINER_ALLOCATOR_SCOPED_ALLOCATOR_HPP