1 //////////////////////////////////////////////////////////////////////////////
3 // (C) Copyright Pablo Halpern 2009. Distributed under the Boost
4 // Software License, Version 1.0. (See accompanying file
5 // LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
7 //////////////////////////////////////////////////////////////////////////////
9 // (C) Copyright Ion Gaztanaga 2011-2013. Distributed under the Boost
10 // Software License, Version 1.0. (See accompanying file
11 // LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
13 // See http://www.boost.org/libs/container for documentation.
15 //////////////////////////////////////////////////////////////////////////////
17 #ifndef BOOST_CONTAINER_ALLOCATOR_ALLOCATOR_TRAITS_HPP
18 #define BOOST_CONTAINER_ALLOCATOR_ALLOCATOR_TRAITS_HPP
24 #include <boost/container/detail/config_begin.hpp>
25 #include <boost/container/detail/workaround.hpp>
26 #include <boost/container/container_fwd.hpp>
27 #include <boost/intrusive/pointer_traits.hpp>
28 #include <boost/intrusive/detail/memory_util.hpp>
29 #include <boost/container/detail/memory_util.hpp>
30 #include <boost/container/detail/mpl.hpp>
31 #include <boost/container/detail/placement_new.hpp>
32 #include <boost/move/utility_core.hpp>
34 #if defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES)
35 #include <boost/container/detail/preprocessor.hpp>
42 namespace allocator_traits_detail {
46 #ifndef BOOST_CONTAINER_DOXYGEN_INVOKED
48 namespace container_detail {
50 //workaround needed for C++03 compilers with no construct()
51 //supporting rvalue references
53 struct is_std_allocator
54 { static const bool value = false; };
57 struct is_std_allocator< std::allocator<T> >
58 { static const bool value = true; };
60 } //namespace container_detail {
62 #endif //#ifndef BOOST_CONTAINER_DOXYGEN_INVOKED
64 //! The class template allocator_traits supplies a uniform interface to all allocator types.
65 //! This class is a C++03-compatible implementation of std::allocator_traits
66 template <typename Alloc>
67 struct allocator_traits
70 typedef Alloc allocator_type;
72 typedef typename Alloc::value_type value_type;
74 #if defined(BOOST_CONTAINER_DOXYGEN_INVOKED)
75 //! Alloc::pointer if such a type exists; otherwise, value_type*
77 typedef unspecified pointer;
78 //! Alloc::const_pointer if such a type exists ; otherwise, pointer_traits<pointer>::rebind<const
80 typedef see_documentation const_pointer;
81 //! Non-standard extension
82 //! Alloc::reference if such a type exists; otherwise, value_type&
83 typedef see_documentation reference;
84 //! Non-standard extension
85 //! Alloc::const_reference if such a type exists ; otherwise, const value_type&
86 typedef see_documentation const_reference;
87 //! Alloc::void_pointer if such a type exists ; otherwise, pointer_traits<pointer>::rebind<void>.
89 typedef see_documentation void_pointer;
90 //! Alloc::const_void_pointer if such a type exists ; otherwis e, pointer_traits<pointer>::rebind<const
92 typedef see_documentation const_void_pointer;
93 //! Alloc::difference_type if such a type exists ; otherwise, pointer_traits<pointer>::difference_type.
95 typedef see_documentation difference_type;
96 //! Alloc::size_type if such a type exists ; otherwise, make_unsigned<difference_type>::type
98 typedef see_documentation size_type;
99 //! Alloc::propagate_on_container_copy_assignment if such a type exists, otherwise an integral_constant
100 //! type with internal constant static member <code>value</code> == false.
101 typedef see_documentation propagate_on_container_copy_assignment;
102 //! Alloc::propagate_on_container_move_assignment if such a type exists, otherwise an integral_constant
103 //! type with internal constant static member <code>value</code> == false.
104 typedef see_documentation propagate_on_container_move_assignment;
105 //! Alloc::propagate_on_container_swap if such a type exists, otherwise an integral_constant
106 //! type with internal constant static member <code>value</code> == false.
107 typedef see_documentation propagate_on_container_swap;
108 //! Defines an allocator: Alloc::rebind<T>::other if such a type exists; otherwise, Alloc<T, Args>
109 //! if Alloc is a class template instantiation of the form Alloc<U, Args>, where Args is zero or
110 //! more type arguments ; otherwise, the instantiation of rebind_alloc is ill-formed.
112 //! In C++03 compilers <code>rebind_alloc</code> is a struct derived from an allocator
113 //! deduced by previously detailed rules.
114 template <class T> using rebind_alloc = see_documentation;
116 //! In C++03 compilers <code>rebind_traits</code> is a struct derived from
117 //! <code>allocator_traits<OtherAlloc></code>, where <code>OtherAlloc</code> is
118 //! the allocator deduced by rules explained in <code>rebind_alloc</code>.
119 template <class T> using rebind_traits = allocator_traits<rebind_alloc<T> >;
121 //! Non-standard extension: Portable allocator rebind for C++03 and C++11 compilers.
122 //! <code>type</code> is an allocator related to Alloc deduced deduced by rules explained in <code>rebind_alloc</code>.
124 struct portable_rebind_alloc
125 { typedef see_documentation type; };
128 typedef BOOST_INTRUSIVE_OBTAIN_TYPE_WITH_DEFAULT(boost::container::container_detail::, Alloc,
129 pointer, value_type*)
132 typedef BOOST_INTRUSIVE_OBTAIN_TYPE_WITH_EVAL_DEFAULT(boost::container::container_detail::, Alloc,
133 const_pointer, typename boost::intrusive::pointer_traits<pointer>::template
134 rebind_pointer<const value_type>)
137 typedef BOOST_INTRUSIVE_OBTAIN_TYPE_WITH_DEFAULT(boost::container::container_detail::, Alloc,
138 reference, typename container_detail::unvoid<value_type>::type&)
141 typedef BOOST_INTRUSIVE_OBTAIN_TYPE_WITH_DEFAULT(boost::container::container_detail::, Alloc,
142 const_reference, const typename container_detail::unvoid<value_type>::type&)
145 typedef BOOST_INTRUSIVE_OBTAIN_TYPE_WITH_EVAL_DEFAULT(boost::container::container_detail::, Alloc,
146 void_pointer, typename boost::intrusive::pointer_traits<pointer>::template
147 rebind_pointer<void>)
150 typedef BOOST_INTRUSIVE_OBTAIN_TYPE_WITH_EVAL_DEFAULT(boost::container::container_detail::, Alloc,
151 const_void_pointer, typename boost::intrusive::pointer_traits<pointer>::template
152 rebind_pointer<const void>)
155 typedef BOOST_INTRUSIVE_OBTAIN_TYPE_WITH_DEFAULT(boost::container::container_detail::, Alloc,
156 difference_type, std::ptrdiff_t)
159 typedef BOOST_INTRUSIVE_OBTAIN_TYPE_WITH_DEFAULT(boost::container::container_detail::, Alloc,
160 size_type, std::size_t)
162 //propagate_on_container_copy_assignment
163 typedef BOOST_INTRUSIVE_OBTAIN_TYPE_WITH_DEFAULT(boost::container::container_detail::, Alloc,
164 propagate_on_container_copy_assignment, container_detail::false_type)
165 propagate_on_container_copy_assignment;
166 //propagate_on_container_move_assignment
167 typedef BOOST_INTRUSIVE_OBTAIN_TYPE_WITH_DEFAULT(boost::container::container_detail::, Alloc,
168 propagate_on_container_move_assignment, container_detail::false_type)
169 propagate_on_container_move_assignment;
170 //propagate_on_container_swap
171 typedef BOOST_INTRUSIVE_OBTAIN_TYPE_WITH_DEFAULT(boost::container::container_detail::, Alloc,
172 propagate_on_container_swap, container_detail::false_type)
173 propagate_on_container_swap;
175 #if !defined(BOOST_NO_CXX11_TEMPLATE_ALIASES)
177 template <typename T> using rebind_alloc = typename boost::intrusive::pointer_rebind<Alloc, T>::type;
178 template <typename T> using rebind_traits = allocator_traits< rebind_alloc<T> >;
179 #else // #if !defined(BOOST_NO_CXX11_TEMPLATE_ALIASES)
180 //Some workaround for C++03 or C++11 compilers with no template aliases
181 template <typename T>
182 struct rebind_alloc : boost::intrusive::pointer_rebind<Alloc,T>::type
184 typedef typename boost::intrusive::pointer_rebind<Alloc,T>::type Base;
185 #if !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES)
186 template <typename... Args>
187 rebind_alloc(BOOST_FWD_REF(Args)... args)
188 : Base(boost::forward<Args>(args)...)
190 #else // #if !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES)
191 #define BOOST_PP_LOCAL_MACRO(n) \
192 BOOST_PP_EXPR_IF(n, template<) BOOST_PP_ENUM_PARAMS(n, class P) BOOST_PP_EXPR_IF(n, >) \
193 rebind_alloc(BOOST_PP_ENUM(n, BOOST_CONTAINER_PP_PARAM_LIST, _)) \
194 : Base(BOOST_PP_ENUM(n, BOOST_CONTAINER_PP_PARAM_FORWARD, _)) \
197 #define BOOST_PP_LOCAL_LIMITS (0, BOOST_CONTAINER_MAX_CONSTRUCTOR_PARAMETERS)
198 #include BOOST_PP_LOCAL_ITERATE()
199 #endif // #if !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES)
202 template <typename T>
204 : allocator_traits<typename boost::intrusive::pointer_rebind<Alloc, T>::type>
206 #endif // #if !defined(BOOST_NO_CXX11_TEMPLATE_ALIASES)
208 struct portable_rebind_alloc
209 { typedef typename boost::intrusive::pointer_rebind<Alloc, T>::type type; };
210 #endif //BOOST_CONTAINER_DOXYGEN_INVOKED
212 //! <b>Returns</b>: <code>a.allocate(n)</code>
214 static pointer allocate(Alloc &a, size_type n)
215 { return a.allocate(n); }
217 //! <b>Returns</b>: <code>a.deallocate(p, n)</code>
219 //! <b>Throws</b>: Nothing
220 static void deallocate(Alloc &a, pointer p, size_type n)
221 { a.deallocate(p, n); }
223 //! <b>Effects</b>: calls <code>a.allocate(n, p)</code> if that call is well-formed;
224 //! otherwise, invokes <code>a.allocate(n)</code>
225 static pointer allocate(Alloc &a, size_type n, const_void_pointer p)
227 const bool value = boost::container::container_detail::
228 has_member_function_callable_with_allocate
229 <Alloc, const size_type, const const_void_pointer>::value;
230 container_detail::bool_<value> flag;
231 return allocator_traits::priv_allocate(flag, a, n, p);
234 //! <b>Effects</b>: calls <code>a.destroy(p)</code> if that call is well-formed;
235 //! otherwise, invokes <code>p->~T()</code>.
237 static void destroy(Alloc &a, T*p) BOOST_CONTAINER_NOEXCEPT
239 typedef T* destroy_pointer;
240 const bool value = boost::container::container_detail::
241 has_member_function_callable_with_destroy
242 <Alloc, const destroy_pointer>::value;
243 container_detail::bool_<value> flag;
244 allocator_traits::priv_destroy(flag, a, p);
247 //! <b>Returns</b>: <code>a.max_size()</code> if that expression is well-formed; otherwise,
248 //! <code>numeric_limits<size_type>::max()</code>.
249 static size_type max_size(const Alloc &a) BOOST_CONTAINER_NOEXCEPT
251 const bool value = boost::container::container_detail::
252 has_member_function_callable_with_max_size
253 <const Alloc>::value;
254 container_detail::bool_<value> flag;
255 return allocator_traits::priv_max_size(flag, a);
258 //! <b>Returns</b>: <code>a.select_on_container_copy_construction()</code> if that expression is well-formed;
261 #if !defined(BOOST_CONTAINER_DOXYGEN_INVOKED)
262 typename container_detail::if_c
263 < boost::container::container_detail::
264 has_member_function_callable_with_select_on_container_copy_construction
272 select_on_container_copy_construction(const Alloc &a)
274 const bool value = boost::container::container_detail::
275 has_member_function_callable_with_select_on_container_copy_construction
276 <const Alloc>::value;
277 container_detail::bool_<value> flag;
278 return allocator_traits::priv_select_on_container_copy_construction(flag, a);
281 #if !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) || defined(BOOST_CONTAINER_DOXYGEN_INVOKED)
282 //! <b>Effects</b>: calls <code>a.construct(p, std::forward<Args>(args)...)</code> if that call is well-formed;
283 //! otherwise, invokes <code>::new (static_cast<void*>(p)) T(std::forward<Args>(args)...)</code>
284 template <class T, class ...Args>
285 static void construct(Alloc & a, T* p, BOOST_FWD_REF(Args)... args)
287 container_detail::bool_<container_detail::is_std_allocator<Alloc>::value> flag;
288 allocator_traits::priv_construct(flag, a, p, ::boost::forward<Args>(args)...);
291 #ifndef BOOST_CONTAINER_DOXYGEN_INVOKED
292 #if !defined(BOOST_CONTAINER_DOXYGEN_INVOKED)
294 static pointer priv_allocate(container_detail::true_type, Alloc &a, size_type n, const_void_pointer p)
295 { return a.allocate(n, p); }
297 static pointer priv_allocate(container_detail::false_type, Alloc &a, size_type n, const_void_pointer)
298 { return allocator_traits::allocate(a, n); }
301 static void priv_destroy(container_detail::true_type, Alloc &a, T* p) BOOST_CONTAINER_NOEXCEPT
305 static void priv_destroy(container_detail::false_type, Alloc &, T* p) BOOST_CONTAINER_NOEXCEPT
306 { p->~T(); (void)p; }
308 static size_type priv_max_size(container_detail::true_type, const Alloc &a) BOOST_CONTAINER_NOEXCEPT
309 { return a.max_size(); }
311 static size_type priv_max_size(container_detail::false_type, const Alloc &) BOOST_CONTAINER_NOEXCEPT
312 { return size_type(-1); }
314 static Alloc priv_select_on_container_copy_construction(container_detail::true_type, const Alloc &a)
315 { return a.select_on_container_copy_construction(); }
317 static const Alloc &priv_select_on_container_copy_construction(container_detail::false_type, const Alloc &a) BOOST_CONTAINER_NOEXCEPT
320 #if !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES)
321 template<class T, class ...Args>
322 static void priv_construct(container_detail::false_type, Alloc &a, T *p, BOOST_FWD_REF(Args) ...args)
324 const bool value = boost::container::container_detail::
325 has_member_function_callable_with_construct
326 < Alloc, T*, Args... >::value;
327 container_detail::bool_<value> flag;
328 priv_construct_dispatch2(flag, a, p, ::boost::forward<Args>(args)...);
331 template<class T, class ...Args>
332 static void priv_construct(container_detail::true_type, Alloc &a, T *p, BOOST_FWD_REF(Args) ...args)
334 priv_construct_dispatch2(container_detail::false_type(), a, p, ::boost::forward<Args>(args)...);
337 template<class T, class ...Args>
338 static void priv_construct_dispatch2(container_detail::true_type, Alloc &a, T *p, BOOST_FWD_REF(Args) ...args)
339 { a.construct( p, ::boost::forward<Args>(args)...); }
341 template<class T, class ...Args>
342 static void priv_construct_dispatch2(container_detail::false_type, Alloc &, T *p, BOOST_FWD_REF(Args) ...args)
343 { ::new((void*)p, boost_container_new_t()) T(::boost::forward<Args>(args)...); }
344 #else // #if !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES)
346 #define BOOST_PP_LOCAL_MACRO(n) \
347 template<class T BOOST_PP_ENUM_TRAILING_PARAMS(n, class P) > \
348 static void construct(Alloc &a, T *p \
349 BOOST_PP_ENUM_TRAILING(n, BOOST_CONTAINER_PP_PARAM_LIST, _)) \
351 container_detail::bool_ \
352 <container_detail::is_std_allocator<Alloc>::value> flag; \
353 allocator_traits::priv_construct(flag, a, p \
354 BOOST_PP_ENUM_TRAILING(n, BOOST_CONTAINER_PP_PARAM_FORWARD, _)); \
357 #define BOOST_PP_LOCAL_LIMITS (0, BOOST_CONTAINER_MAX_CONSTRUCTOR_PARAMETERS)
358 #include BOOST_PP_LOCAL_ITERATE()
361 #define BOOST_PP_LOCAL_MACRO(n) \
362 template<class T BOOST_PP_ENUM_TRAILING_PARAMS(n, class P) > \
363 static void priv_construct(container_detail::false_type, Alloc &a, T *p \
364 BOOST_PP_ENUM_TRAILING(n, BOOST_CONTAINER_PP_PARAM_LIST,_)) \
367 boost::container::container_detail::has_member_function_callable_with_construct \
368 < Alloc, T* BOOST_PP_ENUM_TRAILING(n, BOOST_CONTAINER_PP_FWD_TYPE, _) >::value; \
369 container_detail::bool_<value> flag; \
370 priv_construct_dispatch2(flag, a, p \
371 BOOST_PP_ENUM_TRAILING(n, BOOST_CONTAINER_PP_PARAM_FORWARD, _) ); \
374 template<class T BOOST_PP_ENUM_TRAILING_PARAMS(n, class P) > \
375 static void priv_construct(container_detail::true_type, Alloc &a, T *p \
376 BOOST_PP_ENUM_TRAILING(n, BOOST_CONTAINER_PP_PARAM_LIST,_)) \
378 priv_construct_dispatch2(container_detail::false_type(), a, p \
379 BOOST_PP_ENUM_TRAILING(n, BOOST_CONTAINER_PP_PARAM_FORWARD, _) ); \
382 template<class T BOOST_PP_ENUM_TRAILING_PARAMS(n, class P) > \
383 static void priv_construct_dispatch2(container_detail::true_type, Alloc &a, T *p \
384 BOOST_PP_ENUM_TRAILING(n, BOOST_CONTAINER_PP_PARAM_LIST,_)) \
385 { a.construct( p BOOST_PP_ENUM_TRAILING(n, BOOST_CONTAINER_PP_PARAM_FORWARD, _) ); } \
387 template<class T BOOST_PP_ENUM_TRAILING_PARAMS(n, class P) > \
388 static void priv_construct_dispatch2(container_detail::false_type, Alloc &, T *p \
389 BOOST_PP_ENUM_TRAILING(n, BOOST_CONTAINER_PP_PARAM_LIST, _) ) \
390 { ::new((void*)p, boost_container_new_t()) T(BOOST_PP_ENUM(n, BOOST_CONTAINER_PP_PARAM_FORWARD, _)); }\
392 #define BOOST_PP_LOCAL_LIMITS (0, BOOST_CONTAINER_MAX_CONSTRUCTOR_PARAMETERS)
393 #include BOOST_PP_LOCAL_ITERATE()
394 #endif // #if !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES)
397 static void priv_construct_dispatch2(container_detail::false_type, Alloc &, T *p, ::boost::container::default_init_t)
398 { ::new((void*)p) T; }
399 #endif //#if defined(BOOST_CONTAINER_DOXYGEN_INVOKED)
401 #endif //#ifndef BOOST_CONTAINER_DOXYGEN_INVOKED
404 } //namespace container {
405 } //namespace boost {
407 #include <boost/container/detail/config_end.hpp>
409 #endif // ! defined(BOOST_CONTAINER_ALLOCATOR_ALLOCATOR_TRAITS_HPP)