188 lines
4.7 KiB
C++
188 lines
4.7 KiB
C++
|
/* Copyright 2003-2013 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 Boost website at http://www.boost.org/
|
||
|
*/
|
||
|
|
||
|
#ifndef BOOST_DETAIL_ALLOCATOR_UTILITIES_HPP
|
||
|
#define BOOST_DETAIL_ALLOCATOR_UTILITIES_HPP
|
||
|
|
||
|
#include <boost/config.hpp> /* keep it first to prevent nasty warns in MSVC */
|
||
|
#include <boost/detail/workaround.hpp>
|
||
|
#include <boost/mpl/eval_if.hpp>
|
||
|
#include <boost/type_traits/is_same.hpp>
|
||
|
#include <cstddef>
|
||
|
#include <memory>
|
||
|
#include <new>
|
||
|
|
||
|
namespace boost{
|
||
|
|
||
|
namespace detail{
|
||
|
|
||
|
/* Allocator adaption layer. Some stdlibs provide allocators without rebind
|
||
|
* and template ctors. These facilities are simulated with the external
|
||
|
* template class rebind_to and the aid of partial_std_allocator_wrapper.
|
||
|
*/
|
||
|
|
||
|
namespace allocator{
|
||
|
|
||
|
/* partial_std_allocator_wrapper inherits the functionality of a std
|
||
|
* allocator while providing a templatized ctor and other bits missing
|
||
|
* in some stdlib implementation or another.
|
||
|
*/
|
||
|
|
||
|
template<typename Type>
|
||
|
class partial_std_allocator_wrapper:public std::allocator<Type>
|
||
|
{
|
||
|
public:
|
||
|
/* Oddly enough, STLport does not define std::allocator<void>::value_type
|
||
|
* when configured to work without partial template specialization.
|
||
|
* No harm in supplying the definition here unconditionally.
|
||
|
*/
|
||
|
|
||
|
typedef Type value_type;
|
||
|
|
||
|
partial_std_allocator_wrapper(){};
|
||
|
|
||
|
template<typename Other>
|
||
|
partial_std_allocator_wrapper(const partial_std_allocator_wrapper<Other>&){}
|
||
|
|
||
|
partial_std_allocator_wrapper(const std::allocator<Type>& x):
|
||
|
std::allocator<Type>(x)
|
||
|
{
|
||
|
};
|
||
|
|
||
|
#if defined(BOOST_DINKUMWARE_STDLIB)
|
||
|
/* Dinkumware guys didn't provide a means to call allocate() without
|
||
|
* supplying a hint, in disagreement with the standard.
|
||
|
*/
|
||
|
|
||
|
Type* allocate(std::size_t n,const void* hint=0)
|
||
|
{
|
||
|
std::allocator<Type>& a=*this;
|
||
|
return a.allocate(n,hint);
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
};
|
||
|
|
||
|
/* Detects whether a given allocator belongs to a defective stdlib not
|
||
|
* having the required member templates.
|
||
|
* Note that it does not suffice to check the Boost.Config stdlib
|
||
|
* macros, as the user might have passed a custom, compliant allocator.
|
||
|
* The checks also considers partial_std_allocator_wrapper to be
|
||
|
* a standard defective allocator.
|
||
|
*/
|
||
|
|
||
|
#if defined(BOOST_NO_STD_ALLOCATOR)&&\
|
||
|
(defined(BOOST_HAS_PARTIAL_STD_ALLOCATOR)||defined(BOOST_DINKUMWARE_STDLIB))
|
||
|
|
||
|
template<typename Allocator>
|
||
|
struct is_partial_std_allocator
|
||
|
{
|
||
|
BOOST_STATIC_CONSTANT(bool,
|
||
|
value=
|
||
|
(is_same<
|
||
|
std::allocator<BOOST_DEDUCED_TYPENAME Allocator::value_type>,
|
||
|
Allocator
|
||
|
>::value)||
|
||
|
(is_same<
|
||
|
partial_std_allocator_wrapper<
|
||
|
BOOST_DEDUCED_TYPENAME Allocator::value_type>,
|
||
|
Allocator
|
||
|
>::value));
|
||
|
};
|
||
|
|
||
|
#else
|
||
|
|
||
|
template<typename Allocator>
|
||
|
struct is_partial_std_allocator
|
||
|
{
|
||
|
BOOST_STATIC_CONSTANT(bool,value=false);
|
||
|
};
|
||
|
|
||
|
#endif
|
||
|
|
||
|
/* rebind operations for defective std allocators */
|
||
|
|
||
|
template<typename Allocator,typename Type>
|
||
|
struct partial_std_allocator_rebind_to
|
||
|
{
|
||
|
typedef partial_std_allocator_wrapper<Type> type;
|
||
|
};
|
||
|
|
||
|
/* rebind operation in all other cases */
|
||
|
|
||
|
template<typename Allocator>
|
||
|
struct rebinder
|
||
|
{
|
||
|
template<typename Type>
|
||
|
struct result
|
||
|
{
|
||
|
typedef typename Allocator::BOOST_NESTED_TEMPLATE
|
||
|
rebind<Type>::other other;
|
||
|
};
|
||
|
};
|
||
|
|
||
|
template<typename Allocator,typename Type>
|
||
|
struct compliant_allocator_rebind_to
|
||
|
{
|
||
|
typedef typename rebinder<Allocator>::
|
||
|
BOOST_NESTED_TEMPLATE result<Type>::other type;
|
||
|
};
|
||
|
|
||
|
/* rebind front-end */
|
||
|
|
||
|
template<typename Allocator,typename Type>
|
||
|
struct rebind_to:
|
||
|
mpl::eval_if_c<
|
||
|
is_partial_std_allocator<Allocator>::value,
|
||
|
partial_std_allocator_rebind_to<Allocator,Type>,
|
||
|
compliant_allocator_rebind_to<Allocator,Type>
|
||
|
>
|
||
|
{
|
||
|
};
|
||
|
|
||
|
/* allocator-independent versions of construct and destroy */
|
||
|
|
||
|
template<typename Type>
|
||
|
void construct(void* p,const Type& t)
|
||
|
{
|
||
|
new (p) Type(t);
|
||
|
}
|
||
|
|
||
|
#if BOOST_WORKAROUND(BOOST_MSVC,BOOST_TESTED_AT(1500))
|
||
|
/* MSVC++ issues spurious warnings about unreferencend formal parameters
|
||
|
* in destroy<Type> when Type is a class with trivial dtor.
|
||
|
*/
|
||
|
|
||
|
#pragma warning(push)
|
||
|
#pragma warning(disable:4100)
|
||
|
#endif
|
||
|
|
||
|
template<typename Type>
|
||
|
void destroy(const Type* p)
|
||
|
{
|
||
|
|
||
|
#if BOOST_WORKAROUND(__SUNPRO_CC,BOOST_TESTED_AT(0x590))
|
||
|
const_cast<Type*>(p)->~Type();
|
||
|
#else
|
||
|
p->~Type();
|
||
|
#endif
|
||
|
|
||
|
}
|
||
|
|
||
|
#if BOOST_WORKAROUND(BOOST_MSVC,BOOST_TESTED_AT(1500))
|
||
|
#pragma warning(pop)
|
||
|
#endif
|
||
|
|
||
|
} /* namespace boost::detail::allocator */
|
||
|
|
||
|
} /* namespace boost::detail */
|
||
|
|
||
|
} /* namespace boost */
|
||
|
|
||
|
#endif
|