| ////////////////////////////////////////////////////////////////////////////// |
| // |
| // (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_ALLOCATOR_TRAITS_HPP |
| #define BOOST_CONTAINER_ALLOCATOR_ALLOCATOR_TRAITS_HPP |
| |
| #if (defined _MSC_VER) && (_MSC_VER >= 1200) |
| # pragma once |
| #endif |
| |
| #include <ndnboost/container/detail/config_begin.hpp> |
| #include <ndnboost/container/detail/workaround.hpp> |
| #include <ndnboost/intrusive/pointer_traits.hpp> |
| #include <ndnboost/intrusive/detail/memory_util.hpp> |
| #include <ndnboost/container/detail/memory_util.hpp> |
| #include <ndnboost/type_traits/integral_constant.hpp> |
| #include <ndnboost/container/detail/mpl.hpp> |
| #include <ndnboost/move/utility.hpp> |
| #include <limits> //numeric_limits<>::max() |
| #include <new> //placement new |
| #include <memory> //std::allocator |
| |
| #if defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) |
| #include <ndnboost/container/detail/preprocessor.hpp> |
| #endif |
| |
| ///@cond |
| |
| namespace ndnboost { |
| namespace container { |
| namespace container_detail { |
| |
| //workaround needed for C++03 compilers with no construct() |
| //supporting rvalue references |
| template<class A> |
| struct is_std_allocator |
| { static const bool value = false; }; |
| |
| template<class T> |
| struct is_std_allocator< std::allocator<T> > |
| { static const bool value = true; }; |
| |
| } //namespace container_detail { |
| |
| ///@endcond |
| |
| //! The class template allocator_traits supplies a uniform interface to all allocator types. |
| //! This class is a C++03-compatible implementation of std::allocator_traits |
| template <typename Alloc> |
| struct allocator_traits |
| { |
| //allocator_type |
| typedef Alloc allocator_type; |
| //value_type |
| typedef typename Alloc::value_type value_type; |
| |
| #if defined(BOOST_CONTAINER_DOXYGEN_INVOKED) |
| //! Alloc::pointer if such a type exists; otherwise, value_type* |
| //! |
| typedef unspecified pointer; |
| //! Alloc::const_pointer if such a type exists ; otherwise, pointer_traits<pointer>::rebind<const |
| //! |
| typedef see_documentation const_pointer; |
| //! Non-standard extension |
| //! Alloc::reference if such a type exists; otherwise, value_type& |
| typedef see_documentation reference; |
| //! Non-standard extension |
| //! Alloc::const_reference if such a type exists ; otherwise, const value_type& |
| typedef see_documentation const_reference; |
| //! Alloc::void_pointer if such a type exists ; otherwise, pointer_traits<pointer>::rebind<void>. |
| //! |
| typedef see_documentation void_pointer; |
| //! Alloc::const_void_pointer if such a type exists ; otherwis e, pointer_traits<pointer>::rebind<const |
| //! |
| typedef see_documentation const_void_pointer; |
| //! Alloc::difference_type if such a type exists ; otherwise, pointer_traits<pointer>::difference_type. |
| //! |
| typedef see_documentation difference_type; |
| //! Alloc::size_type if such a type exists ; otherwise, make_unsigned<difference_type>::type |
| //! |
| typedef see_documentation size_type; |
| //! Alloc::propagate_on_container_copy_assignment if such a type exists, otherwise an integral_constant |
| //! type with internal constant static member `value` == false. |
| typedef see_documentation propagate_on_container_copy_assignment; |
| //! Alloc::propagate_on_container_move_assignment if such a type exists, otherwise an integral_constant |
| //! type with internal constant static member `value` == false. |
| typedef see_documentation propagate_on_container_move_assignment; |
| //! Alloc::propagate_on_container_swap if such a type exists, otherwise an integral_constant |
| //! type with internal constant static member `value` == false. |
| typedef see_documentation propagate_on_container_swap; |
| //! Defines an allocator: Alloc::rebind<T>::other if such a type exists; otherwise, Alloc<T, Args> |
| //! if Alloc is a class template instantiation of the form Alloc<U, Args>, where Args is zero or |
| //! more type arguments ; otherwise, the instantiation of rebind_alloc is ill-formed. |
| //! |
| //! In C++03 compilers `rebind_alloc` is a struct derived from an allocator |
| //! deduced by previously detailed rules. |
| template <class T> using rebind_alloc = see_documentation; |
| |
| //! In C++03 compilers `rebind_traits` is a struct derived from |
| //! `allocator_traits<OtherAlloc>`, where `OtherAlloc` is |
| //! the allocator deduced by rules explained in `rebind_alloc`. |
| template <class T> using rebind_traits = allocator_traits<rebind_alloc<T> >; |
| |
| //! Non-standard extension: Portable allocator rebind for C++03 and C++11 compilers. |
| //! `type` is an allocator related to Alloc deduced deduced by rules explained in `rebind_alloc`. |
| template <class T> |
| struct portable_rebind_alloc |
| { typedef see_documentation type; }; |
| #else |
| //pointer |
| typedef BOOST_INTRUSIVE_OBTAIN_TYPE_WITH_DEFAULT(ndnboost::container::container_detail::, Alloc, |
| pointer, value_type*) |
| pointer; |
| //const_pointer |
| typedef BOOST_INTRUSIVE_OBTAIN_TYPE_WITH_EVAL_DEFAULT(ndnboost::container::container_detail::, Alloc, |
| const_pointer, typename ndnboost::intrusive::pointer_traits<pointer>::template |
| rebind_pointer<const value_type>) |
| const_pointer; |
| //reference |
| typedef BOOST_INTRUSIVE_OBTAIN_TYPE_WITH_DEFAULT(ndnboost::container::container_detail::, Alloc, |
| reference, typename container_detail::unvoid<value_type>::type&) |
| reference; |
| //const_reference |
| typedef BOOST_INTRUSIVE_OBTAIN_TYPE_WITH_DEFAULT(ndnboost::container::container_detail::, Alloc, |
| const_reference, const typename container_detail::unvoid<value_type>::type&) |
| const_reference; |
| //void_pointer |
| typedef BOOST_INTRUSIVE_OBTAIN_TYPE_WITH_EVAL_DEFAULT(ndnboost::container::container_detail::, Alloc, |
| void_pointer, typename ndnboost::intrusive::pointer_traits<pointer>::template |
| rebind_pointer<void>) |
| void_pointer; |
| //const_void_pointer |
| typedef BOOST_INTRUSIVE_OBTAIN_TYPE_WITH_EVAL_DEFAULT(ndnboost::container::container_detail::, Alloc, |
| const_void_pointer, typename ndnboost::intrusive::pointer_traits<pointer>::template |
| rebind_pointer<const void>) |
| const_void_pointer; |
| //difference_type |
| typedef BOOST_INTRUSIVE_OBTAIN_TYPE_WITH_DEFAULT(ndnboost::container::container_detail::, Alloc, |
| difference_type, std::ptrdiff_t) |
| difference_type; |
| //size_type |
| typedef BOOST_INTRUSIVE_OBTAIN_TYPE_WITH_DEFAULT(ndnboost::container::container_detail::, Alloc, |
| size_type, std::size_t) |
| size_type; |
| //propagate_on_container_copy_assignment |
| typedef BOOST_INTRUSIVE_OBTAIN_TYPE_WITH_DEFAULT(ndnboost::container::container_detail::, Alloc, |
| propagate_on_container_copy_assignment, ndnboost::false_type) |
| propagate_on_container_copy_assignment; |
| //propagate_on_container_move_assignment |
| typedef BOOST_INTRUSIVE_OBTAIN_TYPE_WITH_DEFAULT(ndnboost::container::container_detail::, Alloc, |
| propagate_on_container_move_assignment, ndnboost::false_type) |
| propagate_on_container_move_assignment; |
| //propagate_on_container_swap |
| typedef BOOST_INTRUSIVE_OBTAIN_TYPE_WITH_DEFAULT(ndnboost::container::container_detail::, Alloc, |
| propagate_on_container_swap, ndnboost::false_type) |
| propagate_on_container_swap; |
| |
| #if !defined(BOOST_NO_CXX11_TEMPLATE_ALIASES) |
| //C++11 |
| template <typename T> using rebind_alloc = typename ndnboost::intrusive::detail::type_rebinder<Alloc, T>::type; |
| template <typename T> using rebind_traits = allocator_traits< rebind_alloc<T> >; |
| #else // #if !defined(BOOST_NO_CXX11_TEMPLATE_ALIASES) |
| //Some workaround for C++03 or C++11 compilers with no template aliases |
| template <typename T> |
| struct rebind_alloc : ndnboost::intrusive::detail::type_rebinder<Alloc,T>::type |
| { |
| typedef typename ndnboost::intrusive::detail::type_rebinder<Alloc,T>::type Base; |
| #if !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) |
| template <typename... Args> |
| rebind_alloc(BOOST_FWD_REF(Args)... args) |
| : Base(ndnboost::forward<Args>(args)...) |
| {} |
| #else // #if !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) |
| #define BOOST_PP_LOCAL_MACRO(n) \ |
| BOOST_PP_EXPR_IF(n, template<) BOOST_PP_ENUM_PARAMS(n, class P) BOOST_PP_EXPR_IF(n, >) \ |
| rebind_alloc(BOOST_PP_ENUM(n, BOOST_CONTAINER_PP_PARAM_LIST, _)) \ |
| : Base(BOOST_PP_ENUM(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_CXX11_VARIADIC_TEMPLATES) |
| }; |
| |
| template <typename T> |
| struct rebind_traits |
| : allocator_traits<typename ndnboost::intrusive::detail::type_rebinder<Alloc, T>::type> |
| {}; |
| #endif // #if !defined(BOOST_NO_CXX11_TEMPLATE_ALIASES) |
| template <class T> |
| struct portable_rebind_alloc |
| { typedef typename ndnboost::intrusive::detail::type_rebinder<Alloc, T>::type type; }; |
| #endif //BOOST_CONTAINER_DOXYGEN_INVOKED |
| |
| //! <b>Returns</b>: `a.allocate(n)` |
| //! |
| static pointer allocate(Alloc &a, size_type n) |
| { return a.allocate(n); } |
| |
| //! <b>Returns</b>: `a.deallocate(p, n)` |
| //! |
| //! <b>Throws</b>: Nothing |
| static void deallocate(Alloc &a, pointer p, size_type n) |
| { a.deallocate(p, n); } |
| |
| //! <b>Effects</b>: calls `a.allocate(n, p)` if that call is well-formed; |
| //! otherwise, invokes `a.allocate(n)` |
| static pointer allocate(Alloc &a, size_type n, const_void_pointer p) |
| { |
| const bool value = ndnboost::container::container_detail:: |
| has_member_function_callable_with_allocate |
| <Alloc, const size_type, const const_void_pointer>::value; |
| ::ndnboost::integral_constant<bool, value> flag; |
| return allocator_traits::priv_allocate(flag, a, n, p); |
| } |
| |
| //! <b>Effects</b>: calls `a.destroy(p)` if that call is well-formed; |
| //! otherwise, invokes `p->~T()`. |
| template<class T> |
| static void destroy(Alloc &a, T*p) |
| { |
| typedef T* destroy_pointer; |
| const bool value = ndnboost::container::container_detail:: |
| has_member_function_callable_with_destroy |
| <Alloc, const destroy_pointer>::value; |
| ::ndnboost::integral_constant<bool, value> flag; |
| allocator_traits::priv_destroy(flag, a, p); |
| } |
| |
| //! <b>Returns</b>: `a.max_size()` if that expression is well-formed; otherwise, |
| //! `numeric_limits<size_type>::max()`. |
| static size_type max_size(const Alloc &a) |
| { |
| const bool value = ndnboost::container::container_detail:: |
| has_member_function_callable_with_max_size |
| <const Alloc>::value; |
| ::ndnboost::integral_constant<bool, value> flag; |
| return allocator_traits::priv_max_size(flag, a); |
| } |
| |
| //! <b>Returns</b>: `a.select_on_container_copy_construction()` if that expression is well-formed; |
| //! otherwise, a. |
| static |
| #if !defined(BOOST_CONTAINER_DOXYGEN_INVOKED) |
| typename container_detail::if_c |
| < ndnboost::container::container_detail:: |
| has_member_function_callable_with_select_on_container_copy_construction |
| <const Alloc>::value |
| , Alloc |
| , const Alloc & |
| >::type |
| #else |
| Alloc |
| #endif |
| select_on_container_copy_construction(const Alloc &a) |
| { |
| const bool value = ndnboost::container::container_detail:: |
| has_member_function_callable_with_select_on_container_copy_construction |
| <const Alloc>::value; |
| ::ndnboost::integral_constant<bool, value> flag; |
| return allocator_traits::priv_select_on_container_copy_construction(flag, a); |
| } |
| |
| #if !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) || defined(BOOST_CONTAINER_DOXYGEN_INVOKED) |
| //! <b>Effects</b>: calls `a.construct(p, std::forward<Args>(args)...)` if that call is well-formed; |
| //! otherwise, invokes `::new (static_cast<void*>(p)) T(std::forward<Args>(args)...)` |
| template <class T, class ...Args> |
| static void construct(Alloc & a, T* p, BOOST_FWD_REF(Args)... args) |
| { |
| ::ndnboost::integral_constant<bool, container_detail::is_std_allocator<Alloc>::value> flag; |
| allocator_traits::priv_construct(flag, a, p, ::ndnboost::forward<Args>(args)...); |
| } |
| #endif |
| ///@cond |
| #if !defined(BOOST_CONTAINER_DOXYGEN_INVOKED) |
| private: |
| static pointer priv_allocate(ndnboost::true_type, Alloc &a, size_type n, const_void_pointer p) |
| { return a.allocate(n, p); } |
| |
| static pointer priv_allocate(ndnboost::false_type, Alloc &a, size_type n, const_void_pointer) |
| { return allocator_traits::allocate(a, n); } |
| |
| template<class T> |
| static void priv_destroy(ndnboost::true_type, Alloc &a, T* p) |
| { a.destroy(p); } |
| |
| template<class T> |
| static void priv_destroy(ndnboost::false_type, Alloc &, T* p) |
| { p->~T(); (void)p; } |
| |
| static size_type priv_max_size(ndnboost::true_type, const Alloc &a) |
| { return a.max_size(); } |
| |
| static size_type priv_max_size(ndnboost::false_type, const Alloc &) |
| { return (std::numeric_limits<size_type>::max)(); } |
| |
| static Alloc priv_select_on_container_copy_construction(ndnboost::true_type, const Alloc &a) |
| { return a.select_on_container_copy_construction(); } |
| |
| static const Alloc &priv_select_on_container_copy_construction(ndnboost::false_type, const Alloc &a) |
| { return a; } |
| |
| #if !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) |
| template<class T, class ...Args> |
| static void priv_construct(ndnboost::false_type, Alloc &a, T *p, BOOST_FWD_REF(Args) ...args) |
| { |
| const bool value = ndnboost::container::container_detail:: |
| has_member_function_callable_with_construct |
| < Alloc, T*, Args... >::value; |
| ::ndnboost::integral_constant<bool, value> flag; |
| priv_construct_dispatch2(flag, a, p, ::ndnboost::forward<Args>(args)...); |
| } |
| |
| template<class T, class ...Args> |
| static void priv_construct(ndnboost::true_type, Alloc &a, T *p, BOOST_FWD_REF(Args) ...args) |
| { |
| priv_construct_dispatch2(ndnboost::false_type(), a, p, ::ndnboost::forward<Args>(args)...); |
| } |
| |
| template<class T, class ...Args> |
| static void priv_construct_dispatch2(ndnboost::true_type, Alloc &a, T *p, BOOST_FWD_REF(Args) ...args) |
| { a.construct( p, ::ndnboost::forward<Args>(args)...); } |
| |
| template<class T, class ...Args> |
| static void priv_construct_dispatch2(ndnboost::false_type, Alloc &, T *p, BOOST_FWD_REF(Args) ...args) |
| { ::new((void*)p) T(::ndnboost::forward<Args>(args)...); } |
| #else // #if !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) |
| public: |
| #define BOOST_PP_LOCAL_MACRO(n) \ |
| template<class T BOOST_PP_ENUM_TRAILING_PARAMS(n, class P) > \ |
| static void construct(Alloc &a, T *p \ |
| BOOST_PP_ENUM_TRAILING(n, BOOST_CONTAINER_PP_PARAM_LIST, _)) \ |
| { \ |
| ::ndnboost::integral_constant<bool, container_detail::is_std_allocator<Alloc>::value> flag; \ |
| allocator_traits::priv_construct(flag, a, 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() |
| |
| private: |
| #define BOOST_PP_LOCAL_MACRO(n) \ |
| template<class T BOOST_PP_ENUM_TRAILING_PARAMS(n, class P) > \ |
| static void priv_construct(ndnboost::false_type, Alloc &a, T *p \ |
| BOOST_PP_ENUM_TRAILING(n, BOOST_CONTAINER_PP_PARAM_LIST,_)) \ |
| { \ |
| const bool value = \ |
| ndnboost::container::container_detail::has_member_function_callable_with_construct \ |
| < Alloc, T* BOOST_PP_ENUM_TRAILING(n, BOOST_CONTAINER_PP_FWD_TYPE, _) >::value; \ |
| ::ndnboost::integral_constant<bool, value> flag; \ |
| priv_construct_dispatch2(flag, a, p \ |
| BOOST_PP_ENUM_TRAILING(n, BOOST_CONTAINER_PP_PARAM_FORWARD, _) ); \ |
| } \ |
| \ |
| template<class T BOOST_PP_ENUM_TRAILING_PARAMS(n, class P) > \ |
| static void priv_construct(ndnboost::true_type, Alloc &a, T *p \ |
| BOOST_PP_ENUM_TRAILING(n, BOOST_CONTAINER_PP_PARAM_LIST,_)) \ |
| { \ |
| priv_construct_dispatch2(ndnboost::false_type(), a, p \ |
| BOOST_PP_ENUM_TRAILING(n, BOOST_CONTAINER_PP_PARAM_FORWARD, _) ); \ |
| } \ |
| \ |
| template<class T BOOST_PP_ENUM_TRAILING_PARAMS(n, class P) > \ |
| static void priv_construct_dispatch2(ndnboost::true_type, Alloc &a, T *p \ |
| BOOST_PP_ENUM_TRAILING(n, BOOST_CONTAINER_PP_PARAM_LIST,_)) \ |
| { a.construct( p BOOST_PP_ENUM_TRAILING(n, BOOST_CONTAINER_PP_PARAM_FORWARD, _) ); } \ |
| \ |
| template<class T BOOST_PP_ENUM_TRAILING_PARAMS(n, class P) > \ |
| static void priv_construct_dispatch2(ndnboost::false_type, Alloc &, T *p \ |
| BOOST_PP_ENUM_TRAILING(n, BOOST_CONTAINER_PP_PARAM_LIST, _) ) \ |
| { ::new((void*)p) T(BOOST_PP_ENUM(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_CXX11_VARIADIC_TEMPLATES) |
| #endif //#if defined(BOOST_CONTAINER_DOXYGEN_INVOKED) |
| |
| ///@endcond |
| }; |
| |
| } //namespace container { |
| } //namespace ndnboost { |
| |
| #include <ndnboost/container/detail/config_end.hpp> |
| |
| #endif // ! defined(BOOST_CONTAINER_ALLOCATOR_ALLOCATOR_TRAITS_HPP) |