forked from boostorg/unordered
Merge pull request #56 from LeonineKing1199/feature/allocator-traits
Replace internal implementation of `allocation_traits` with Core's
This commit is contained in:
@ -13,6 +13,7 @@
|
||||
#endif
|
||||
|
||||
#include <boost/assert.hpp>
|
||||
#include <boost/core/allocator_traits.hpp>
|
||||
#include <boost/core/no_exceptions_support.hpp>
|
||||
#include <boost/core/pointer_traits.hpp>
|
||||
#include <boost/detail/select_type.hpp>
|
||||
@ -1055,468 +1056,24 @@ namespace boost {
|
||||
//
|
||||
// Allocator traits
|
||||
//
|
||||
// First our implementation, then later light wrappers around the alternatives
|
||||
|
||||
#if BOOST_UNORDERED_USE_ALLOCATOR_TRAITS == 0
|
||||
|
||||
#include <boost/limits.hpp>
|
||||
#include <boost/pointer_to_other.hpp>
|
||||
#include <boost/utility/enable_if.hpp>
|
||||
|
||||
namespace boost {
|
||||
namespace unordered {
|
||||
namespace detail {
|
||||
|
||||
template <typename Alloc, typename T> struct rebind_alloc;
|
||||
|
||||
#if !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES)
|
||||
|
||||
template <template <typename, typename...> class Alloc, typename U,
|
||||
typename T, typename... Args>
|
||||
struct rebind_alloc<Alloc<U, Args...>, T>
|
||||
{
|
||||
typedef Alloc<T, Args...> type;
|
||||
};
|
||||
|
||||
#else
|
||||
|
||||
template <template <typename> class Alloc, typename U, typename T>
|
||||
struct rebind_alloc<Alloc<U>, T>
|
||||
{
|
||||
typedef Alloc<T> type;
|
||||
};
|
||||
|
||||
template <template <typename, typename> class Alloc, typename U,
|
||||
typename T, typename A0>
|
||||
struct rebind_alloc<Alloc<U, A0>, T>
|
||||
{
|
||||
typedef Alloc<T, A0> type;
|
||||
};
|
||||
|
||||
template <template <typename, typename, typename> class Alloc, typename U,
|
||||
typename T, typename A0, typename A1>
|
||||
struct rebind_alloc<Alloc<U, A0, A1>, T>
|
||||
{
|
||||
typedef Alloc<T, A0, A1> type;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
template <typename Alloc, typename T> struct rebind_wrap
|
||||
{
|
||||
template <typename X>
|
||||
static choice1::type test(
|
||||
choice1, typename X::BOOST_NESTED_TEMPLATE rebind<T>::other* = 0);
|
||||
template <typename X> static choice2::type test(choice2, void* = 0);
|
||||
|
||||
enum
|
||||
{
|
||||
value = (1 == sizeof(test<Alloc>(choose())))
|
||||
};
|
||||
|
||||
struct fallback
|
||||
{
|
||||
template <typename U> struct rebind
|
||||
{
|
||||
typedef typename rebind_alloc<Alloc, T>::type other;
|
||||
};
|
||||
};
|
||||
|
||||
typedef
|
||||
typename boost::detail::if_true<value>::BOOST_NESTED_TEMPLATE then<
|
||||
Alloc, fallback>::type::BOOST_NESTED_TEMPLATE rebind<T>::other type;
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
namespace boost {
|
||||
namespace unordered {
|
||||
namespace detail {
|
||||
BOOST_UNORDERED_DEFAULT_TYPE_TMPLT(pointer);
|
||||
BOOST_UNORDERED_DEFAULT_TYPE_TMPLT(const_pointer);
|
||||
BOOST_UNORDERED_DEFAULT_TYPE_TMPLT(void_pointer);
|
||||
BOOST_UNORDERED_DEFAULT_TYPE_TMPLT(const_void_pointer);
|
||||
BOOST_UNORDERED_DEFAULT_TYPE_TMPLT(difference_type);
|
||||
BOOST_UNORDERED_DEFAULT_TYPE_TMPLT(size_type);
|
||||
BOOST_UNORDERED_DEFAULT_TYPE_TMPLT(
|
||||
propagate_on_container_copy_assignment);
|
||||
BOOST_UNORDERED_DEFAULT_TYPE_TMPLT(
|
||||
propagate_on_container_move_assignment);
|
||||
BOOST_UNORDERED_DEFAULT_TYPE_TMPLT(propagate_on_container_swap);
|
||||
BOOST_UNORDERED_DEFAULT_TYPE_TMPLT(is_always_equal);
|
||||
|
||||
#if !defined(BOOST_NO_SFINAE_EXPR)
|
||||
|
||||
template <typename T>
|
||||
BOOST_UNORDERED_HAS_FUNCTION(
|
||||
select_on_container_copy_construction, U const, (), 0);
|
||||
|
||||
template <typename T>
|
||||
BOOST_UNORDERED_HAS_FUNCTION(max_size, U const, (), 0);
|
||||
|
||||
#if !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES)
|
||||
|
||||
template <typename T, typename ValueType, typename... Args>
|
||||
BOOST_UNORDERED_HAS_FUNCTION(construct, U,
|
||||
(boost::unordered::detail::make<ValueType*>(),
|
||||
std::declval<Args>()...),
|
||||
2);
|
||||
|
||||
#else
|
||||
|
||||
template <typename T, typename ValueType>
|
||||
BOOST_UNORDERED_HAS_FUNCTION(construct, U,
|
||||
(boost::unordered::detail::make<ValueType*>(),
|
||||
boost::unordered::detail::make<ValueType const>()),
|
||||
2);
|
||||
|
||||
#endif
|
||||
|
||||
template <typename T, typename ValueType>
|
||||
BOOST_UNORDERED_HAS_FUNCTION(
|
||||
destroy, U, (boost::unordered::detail::make<ValueType*>()), 1);
|
||||
|
||||
#else
|
||||
|
||||
template <typename T>
|
||||
BOOST_UNORDERED_HAS_MEMBER(select_on_container_copy_construction);
|
||||
|
||||
template <typename T> BOOST_UNORDERED_HAS_MEMBER(max_size);
|
||||
|
||||
template <typename T, typename ValueType>
|
||||
BOOST_UNORDERED_HAS_MEMBER(construct);
|
||||
|
||||
template <typename T, typename ValueType>
|
||||
BOOST_UNORDERED_HAS_MEMBER(destroy);
|
||||
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
namespace boost {
|
||||
namespace unordered {
|
||||
namespace detail {
|
||||
namespace func {
|
||||
|
||||
template <typename Alloc>
|
||||
inline typename boost::enable_if<
|
||||
boost::unordered::detail::has_select_on_container_copy_construction<
|
||||
Alloc>,
|
||||
Alloc>::type
|
||||
call_select_on_container_copy_construction(const Alloc& rhs)
|
||||
{
|
||||
return rhs.select_on_container_copy_construction();
|
||||
}
|
||||
|
||||
template <typename Alloc>
|
||||
inline typename boost::disable_if<
|
||||
boost::unordered::detail::has_select_on_container_copy_construction<
|
||||
Alloc>,
|
||||
Alloc>::type
|
||||
call_select_on_container_copy_construction(const Alloc& rhs)
|
||||
{
|
||||
return rhs;
|
||||
}
|
||||
|
||||
template <typename SizeType, typename Alloc>
|
||||
inline typename boost::enable_if<
|
||||
boost::unordered::detail::has_max_size<Alloc>, SizeType>::type
|
||||
call_max_size(const Alloc& a)
|
||||
{
|
||||
return a.max_size();
|
||||
}
|
||||
|
||||
template <typename SizeType, typename Alloc>
|
||||
inline typename boost::disable_if<
|
||||
boost::unordered::detail::has_max_size<Alloc>, SizeType>::type
|
||||
call_max_size(const Alloc&)
|
||||
{
|
||||
return (std::numeric_limits<SizeType>::max)();
|
||||
}
|
||||
} // namespace func.
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
namespace boost {
|
||||
namespace unordered {
|
||||
namespace detail {
|
||||
template <typename Alloc> struct allocator_traits
|
||||
{
|
||||
typedef Alloc allocator_type;
|
||||
typedef typename Alloc::value_type value_type;
|
||||
|
||||
typedef BOOST_UNORDERED_DEFAULT_TYPE(
|
||||
Alloc, pointer, value_type*) pointer;
|
||||
|
||||
template <typename T>
|
||||
struct pointer_to_other : boost::pointer_to_other<pointer, T>
|
||||
{
|
||||
};
|
||||
|
||||
typedef BOOST_UNORDERED_DEFAULT_TYPE(Alloc, const_pointer,
|
||||
typename pointer_to_other<const value_type>::type) const_pointer;
|
||||
|
||||
// typedef BOOST_UNORDERED_DEFAULT_TYPE(Alloc, void_pointer,
|
||||
// typename pointer_to_other<void>::type)
|
||||
// void_pointer;
|
||||
//
|
||||
// typedef BOOST_UNORDERED_DEFAULT_TYPE(Alloc, const_void_pointer,
|
||||
// typename pointer_to_other<const void>::type)
|
||||
// const_void_pointer;
|
||||
|
||||
typedef BOOST_UNORDERED_DEFAULT_TYPE(
|
||||
Alloc, difference_type, std::ptrdiff_t) difference_type;
|
||||
|
||||
typedef BOOST_UNORDERED_DEFAULT_TYPE(
|
||||
Alloc, size_type, std::size_t) size_type;
|
||||
|
||||
#if !defined(BOOST_NO_CXX11_TEMPLATE_ALIASES)
|
||||
template <typename T>
|
||||
using rebind_alloc = typename rebind_wrap<Alloc, T>::type;
|
||||
|
||||
template <typename T>
|
||||
using rebind_traits =
|
||||
boost::unordered::detail::allocator_traits<rebind_alloc<T> >;
|
||||
#endif
|
||||
|
||||
static pointer allocate(Alloc& a, size_type n) { return a.allocate(n); }
|
||||
|
||||
// I never use this, so I'll just comment it out for now.
|
||||
//
|
||||
// static pointer allocate(Alloc& a, size_type n,
|
||||
// const_void_pointer hint)
|
||||
// { return DEFAULT_FUNC(allocate, pointer)(a, n, hint); }
|
||||
|
||||
static void deallocate(Alloc& a, pointer p, size_type n)
|
||||
{
|
||||
a.deallocate(p, n);
|
||||
}
|
||||
|
||||
public:
|
||||
#if BOOST_UNORDERED_CXX11_CONSTRUCTION
|
||||
|
||||
template <typename T, typename... Args>
|
||||
static
|
||||
typename boost::enable_if_c<boost::unordered::detail::has_construct<
|
||||
Alloc, T, Args...>::value>::type
|
||||
construct(Alloc& a, T* p, BOOST_FWD_REF(Args)... x)
|
||||
{
|
||||
a.construct(p, boost::forward<Args>(x)...);
|
||||
}
|
||||
|
||||
template <typename T, typename... Args>
|
||||
static
|
||||
typename boost::disable_if_c<boost::unordered::detail::has_construct<
|
||||
Alloc, T, Args...>::value>::type
|
||||
construct(Alloc&, T* p, BOOST_FWD_REF(Args)... x)
|
||||
{
|
||||
new (static_cast<void*>(p)) T(boost::forward<Args>(x)...);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
static typename boost::enable_if_c<
|
||||
boost::unordered::detail::has_destroy<Alloc, T>::value>::type
|
||||
destroy(Alloc& a, T* p)
|
||||
{
|
||||
a.destroy(p);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
static typename boost::disable_if_c<
|
||||
boost::unordered::detail::has_destroy<Alloc, T>::value>::type
|
||||
destroy(Alloc&, T* p)
|
||||
{
|
||||
boost::unordered::detail::func::destroy(p);
|
||||
}
|
||||
|
||||
#elif !defined(BOOST_NO_SFINAE_EXPR)
|
||||
|
||||
template <typename T>
|
||||
static typename boost::enable_if_c<
|
||||
boost::unordered::detail::has_construct<Alloc, T>::value>::type
|
||||
construct(Alloc& a, T* p, T const& x)
|
||||
{
|
||||
a.construct(p, x);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
static typename boost::disable_if_c<
|
||||
boost::unordered::detail::has_construct<Alloc, T>::value>::type
|
||||
construct(Alloc&, T* p, T const& x)
|
||||
{
|
||||
new (static_cast<void*>(p)) T(x);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
static typename boost::enable_if_c<
|
||||
boost::unordered::detail::has_destroy<Alloc, T>::value>::type
|
||||
destroy(Alloc& a, T* p)
|
||||
{
|
||||
a.destroy(p);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
static typename boost::disable_if_c<
|
||||
boost::unordered::detail::has_destroy<Alloc, T>::value>::type
|
||||
destroy(Alloc&, T* p)
|
||||
{
|
||||
boost::unordered::detail::func::destroy(p);
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
// If we don't have SFINAE expressions, only call construct for the
|
||||
// copy constructor for the allocator's value_type - as that's
|
||||
// the only construct method that old fashioned allocators support.
|
||||
|
||||
template <typename T>
|
||||
static typename boost::enable_if_c<
|
||||
boost::unordered::detail::has_construct<Alloc, T>::value &&
|
||||
boost::is_same<T, value_type>::value,
|
||||
void>::type
|
||||
construct(Alloc& a, T* p, T const& x)
|
||||
{
|
||||
a.construct(p, x);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
static typename boost::disable_if_c<
|
||||
boost::unordered::detail::has_construct<Alloc, T>::value &&
|
||||
boost::is_same<T, value_type>::value,
|
||||
void>::type
|
||||
construct(Alloc&, T* p, T const& x)
|
||||
{
|
||||
new (static_cast<void*>(p)) T(x);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
static typename boost::enable_if_c<
|
||||
boost::unordered::detail::has_destroy<Alloc, T>::value &&
|
||||
boost::is_same<T, value_type>::value,
|
||||
void>::type
|
||||
destroy(Alloc& a, T* p)
|
||||
{
|
||||
a.destroy(p);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
static typename boost::disable_if_c<
|
||||
boost::unordered::detail::has_destroy<Alloc, T>::value &&
|
||||
boost::is_same<T, value_type>::value,
|
||||
void>::type
|
||||
destroy(Alloc&, T* p)
|
||||
{
|
||||
boost::unordered::detail::func::destroy(p);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
static size_type max_size(const Alloc& a)
|
||||
{
|
||||
return boost::unordered::detail::func::call_max_size<size_type>(a);
|
||||
}
|
||||
|
||||
// Allocator propagation on construction
|
||||
|
||||
static Alloc select_on_container_copy_construction(Alloc const& rhs)
|
||||
{
|
||||
return boost::unordered::detail::func::
|
||||
call_select_on_container_copy_construction(rhs);
|
||||
}
|
||||
|
||||
// Allocator propagation on assignment and swap.
|
||||
// Return true if lhs is modified.
|
||||
typedef BOOST_UNORDERED_DEFAULT_TYPE(Alloc,
|
||||
propagate_on_container_copy_assignment,
|
||||
false_type) propagate_on_container_copy_assignment;
|
||||
typedef BOOST_UNORDERED_DEFAULT_TYPE(Alloc,
|
||||
propagate_on_container_move_assignment,
|
||||
false_type) propagate_on_container_move_assignment;
|
||||
typedef BOOST_UNORDERED_DEFAULT_TYPE(Alloc, propagate_on_container_swap,
|
||||
false_type) propagate_on_container_swap;
|
||||
|
||||
typedef BOOST_UNORDERED_DEFAULT_TYPE(Alloc, is_always_equal,
|
||||
typename boost::is_empty<Alloc>::type) is_always_equal;
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#undef BOOST_UNORDERED_DEFAULT_TYPE_TMPLT
|
||||
#undef BOOST_UNORDERED_DEFAULT_TYPE
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// std::allocator_traits
|
||||
|
||||
#elif BOOST_UNORDERED_USE_ALLOCATOR_TRAITS == 1
|
||||
|
||||
#include <memory>
|
||||
|
||||
namespace boost {
|
||||
namespace unordered {
|
||||
namespace detail {
|
||||
|
||||
BOOST_UNORDERED_DEFAULT_TYPE_TMPLT(is_always_equal);
|
||||
|
||||
template <typename Alloc>
|
||||
struct allocator_traits : std::allocator_traits<Alloc>
|
||||
{
|
||||
// As is_always_equal was introduced in C++17, std::allocator_traits
|
||||
// doesn't always have it. So use it when available, implement it
|
||||
// ourselves when not. Would be simpler not to bother with
|
||||
// std::allocator_traits, but I feel like I should try to use
|
||||
// it where possible.
|
||||
typedef BOOST_UNORDERED_DEFAULT_TYPE(std::allocator_traits<Alloc>,
|
||||
is_always_equal,
|
||||
BOOST_UNORDERED_DEFAULT_TYPE(Alloc, is_always_equal,
|
||||
typename boost::is_empty<Alloc>::type)) is_always_equal;
|
||||
};
|
||||
|
||||
template <typename Alloc, typename T> struct rebind_wrap
|
||||
{
|
||||
typedef typename std::allocator_traits<Alloc>::template rebind_alloc<T>
|
||||
type;
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// boost::container::allocator_traits
|
||||
|
||||
#elif BOOST_UNORDERED_USE_ALLOCATOR_TRAITS == 2
|
||||
|
||||
#include <boost/container/allocator_traits.hpp>
|
||||
|
||||
namespace boost {
|
||||
namespace unordered {
|
||||
namespace detail {
|
||||
|
||||
template <typename Alloc>
|
||||
struct allocator_traits : boost::container::allocator_traits<Alloc>
|
||||
struct allocator_traits : boost::allocator_traits<Alloc>
|
||||
{
|
||||
};
|
||||
|
||||
template <typename Alloc, typename T>
|
||||
struct rebind_wrap : boost::container::allocator_traits<
|
||||
Alloc>::template portable_rebind_alloc<T>
|
||||
struct rebind_wrap : boost::allocator_rebind<Alloc, T>
|
||||
{
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
#error "Invalid BOOST_UNORDERED_USE_ALLOCATOR_TRAITS value."
|
||||
|
||||
#endif
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
// Functions used to construct nodes. Emulates variadic construction,
|
||||
// piecewise construction etc.
|
||||
|
@ -213,7 +213,15 @@ void test_allocator2()
|
||||
BOOST_TEST(!traits::propagate_on_container_move_assignment::value);
|
||||
BOOST_TEST(!traits::propagate_on_container_swap::value);
|
||||
BOOST_TEST(!traits::is_always_equal::value);
|
||||
|
||||
#if !defined(BOOST_NO_CXX11_ALLOCATOR)
|
||||
// conditionally compile this assertion as all C++03 emulations of expression
|
||||
// SFINAE are broken one way or another and the benefits of using Core's
|
||||
// `allocator_traits` outweigh the costs of breaking this kind of code (i.e.
|
||||
// inheriting SOCCC via a base)
|
||||
//
|
||||
BOOST_TEST(call_select<allocator>() == 1);
|
||||
#endif
|
||||
}
|
||||
|
||||
// allocator 3
|
||||
|
Reference in New Issue
Block a user