williamr@2: /* Copyright 2003-2005 Joaquín M López Muñoz.
williamr@2:  * Distributed under the Boost Software License, Version 1.0.
williamr@2:  * (See accompanying file LICENSE_1_0.txt or copy at
williamr@2:  * http://www.boost.org/LICENSE_1_0.txt)
williamr@2:  *
williamr@2:  * See Boost website at http://www.boost.org/
williamr@2:  */
williamr@2: 
williamr@2: #ifndef BOOST_DETAIL_ALLOCATOR_UTILITIES_HPP
williamr@2: #define BOOST_DETAIL_ALLOCATOR_UTILITIES_HPP
williamr@2: 
williamr@2: #include <boost/config.hpp> /* keep it first to prevent nasty warns in MSVC */
williamr@2: #include <boost/detail/workaround.hpp>
williamr@2: #include <boost/mpl/aux_/msvc_never_true.hpp>
williamr@2: #include <boost/mpl/eval_if.hpp>
williamr@2: #include <boost/type_traits/is_same.hpp>
williamr@2: #include <cstddef>
williamr@2: #include <memory>
williamr@2: #include <new>
williamr@2: 
williamr@2: namespace boost{
williamr@2: 
williamr@2: namespace detail{
williamr@2: 
williamr@2: /* Allocator adaption layer. Some stdlibs provide allocators without rebind
williamr@2:  * and template ctors. These facilities are simulated with the external
williamr@2:  * template class rebind_to and the aid of partial_std_allocator_wrapper.
williamr@2:  */
williamr@2: 
williamr@2: namespace allocator{
williamr@2: 
williamr@2: /* partial_std_allocator_wrapper inherits the functionality of a std
williamr@2:  * allocator while providing a templatized ctor.
williamr@2:  */
williamr@2: 
williamr@2: template<typename Type>
williamr@2: class partial_std_allocator_wrapper:public std::allocator<Type>
williamr@2: {
williamr@2: public:
williamr@2:   partial_std_allocator_wrapper(){};
williamr@2: 
williamr@2:   template<typename Other>
williamr@2:   partial_std_allocator_wrapper(const partial_std_allocator_wrapper<Other>&){}
williamr@2: 
williamr@2:   partial_std_allocator_wrapper(const std::allocator<Type>& x):
williamr@2:     std::allocator<Type>(x)
williamr@2:   {
williamr@2:   };
williamr@2: 
williamr@2: #if defined(BOOST_DINKUMWARE_STDLIB)
williamr@2:   /* Dinkumware guys didn't provide a means to call allocate() without
williamr@2:    * supplying a hint, in disagreement with the standard.
williamr@2:    */
williamr@2: 
williamr@2:   Type* allocate(std::size_t n,const void* hint=0)
williamr@2:   {
williamr@2:     std::allocator<Type>& a=*this;
williamr@2:     return a.allocate(n,hint);
williamr@2:   }
williamr@2: #endif
williamr@2: 
williamr@2: };
williamr@2: 
williamr@2: /* Detects whether a given allocator belongs to a defective stdlib not
williamr@2:  * having the required member templates.
williamr@2:  * Note that it does not suffice to check the Boost.Config stdlib
williamr@2:  * macros, as the user might have passed a custom, compliant allocator.
williamr@2:  * The checks also considers partial_std_allocator_wrapper to be
williamr@2:  * a standard defective allocator.
williamr@2:  */
williamr@2: 
williamr@2: #if defined(BOOST_NO_STD_ALLOCATOR)&&\
williamr@2:   (defined(BOOST_HAS_PARTIAL_STD_ALLOCATOR)||defined(BOOST_DINKUMWARE_STDLIB))
williamr@2: 
williamr@2: template<typename Allocator>
williamr@2: struct is_partial_std_allocator
williamr@2: {
williamr@2:   BOOST_STATIC_CONSTANT(bool,
williamr@2:     value=
williamr@2:       (is_same<
williamr@2:         std::allocator<BOOST_DEDUCED_TYPENAME Allocator::value_type>,
williamr@2:         Allocator
williamr@2:       >::value)||
williamr@2:       (is_same<
williamr@2:         partial_std_allocator_wrapper<
williamr@2:           BOOST_DEDUCED_TYPENAME Allocator::value_type>,
williamr@2:         Allocator
williamr@2:       >::value));
williamr@2: };
williamr@2: 
williamr@2: #else
williamr@2: 
williamr@2: template<typename Allocator>
williamr@2: struct is_partial_std_allocator
williamr@2: {
williamr@2:   BOOST_STATIC_CONSTANT(bool,value=false);
williamr@2: };
williamr@2: 
williamr@2: #endif
williamr@2: 
williamr@2: /* rebind operations for defective std allocators */
williamr@2: 
williamr@2: template<typename Allocator,typename Type>
williamr@2: struct partial_std_allocator_rebind_to
williamr@2: {
williamr@2:   typedef partial_std_allocator_wrapper<Type> type;
williamr@2: };
williamr@2: 
williamr@2: /* rebind operation in all other cases */
williamr@2: 
williamr@2: #if BOOST_WORKAROUND(BOOST_MSVC,<1300)
williamr@2: /* Workaround for a problem in MSVC with dependent template typedefs
williamr@2:  * when doing rebinding of allocators.
williamr@2:  * Modeled after <boost/mpl/aux_/msvc_dtw.hpp> (thanks, Aleksey!)
williamr@2:  */
williamr@2: 
williamr@2: template<typename Allocator>
williamr@2: struct rebinder
williamr@2: {
williamr@2:   template<bool> struct fake_allocator:Allocator{};
williamr@2:   template<> struct fake_allocator<true>
williamr@2:   {
williamr@2:     template<typename Type> struct rebind{};
williamr@2:   };
williamr@2: 
williamr@2:   template<typename Type>
williamr@2:   struct result:
williamr@2:     fake_allocator<mpl::aux::msvc_never_true<Allocator>::value>::
williamr@2:       template rebind<Type>
williamr@2:   {
williamr@2:   };
williamr@2: };
williamr@2: #else
williamr@2: template<typename Allocator>
williamr@2: struct rebinder
williamr@2: {
williamr@2:   template<typename Type>
williamr@2:   struct result
williamr@2:   {
williamr@2:       typedef typename Allocator::BOOST_NESTED_TEMPLATE 
williamr@2:           rebind<Type>::other other;
williamr@2:   };
williamr@2: };
williamr@2: #endif
williamr@2: 
williamr@2: template<typename Allocator,typename Type>
williamr@2: struct compliant_allocator_rebind_to
williamr@2: {
williamr@2:   typedef typename rebinder<Allocator>::
williamr@2:       BOOST_NESTED_TEMPLATE result<Type>::other type;
williamr@2: };
williamr@2: 
williamr@2: /* rebind front-end */
williamr@2: 
williamr@2: template<typename Allocator,typename Type>
williamr@2: struct rebind_to:
williamr@2:   mpl::eval_if_c<
williamr@2:     is_partial_std_allocator<Allocator>::value,
williamr@2:     partial_std_allocator_rebind_to<Allocator,Type>,
williamr@2:     compliant_allocator_rebind_to<Allocator,Type>
williamr@2:   >
williamr@2: {
williamr@2: };
williamr@2: 
williamr@2: /* allocator-independent versions of construct and destroy */
williamr@2: 
williamr@2: template<typename Type>
williamr@2: void construct(void* p,const Type& t)
williamr@2: {
williamr@2:   new (p) Type(t);
williamr@2: }
williamr@2: 
williamr@2: template<typename Type>
williamr@2: void destroy(const Type* p)
williamr@2: {
williamr@2:   p->~Type();
williamr@2: }
williamr@2: 
williamr@2: } /* namespace boost::detail::allocator */
williamr@2: 
williamr@2: } /* namespace boost::detail */
williamr@2: 
williamr@2: } /* namespace boost */
williamr@2: 
williamr@2: #endif