Unordered: Support optional allocator methods.

Only for compilers with SFINAE expressions and recent versions of Visual
C++. Also fix Visual C++ 8, and use BOOST_UNORDERED_ prefix for all
macros.

[SVN r74106]
This commit is contained in:
Daniel James
2011-08-28 15:36:58 +00:00
parent 6bc99ac0c2
commit 4bf3b1bfc5
3 changed files with 217 additions and 45 deletions

View File

@@ -19,6 +19,7 @@
#include <boost/detail/select_type.hpp>
#include <boost/utility/enable_if.hpp>
#include <boost/preprocessor/cat.hpp>
#include <boost/limits.hpp>
#if (defined(BOOST_NO_STD_ALLOCATOR) || defined(BOOST_DINKUMWARE_STDLIB)) \
&& !defined(__BORLANDC__)
@@ -93,17 +94,29 @@ namespace boost { namespace unordered { namespace detail {
struct choice2 : choice3 { typedef char (&type)[2]; };
struct choice1 : choice2 { typedef char (&type)[1]; };
choice1 choose();
#if !defined(__IBMCPP__)
#define BOOST_UNORDERED_MEMBER_CHECK(tname) BOOST_DEDUCED_TYPENAME X::tname*
#else
template <typename T> struct wrap { typedef void* type; };
#define BOOST_DEFAULT_TYPE_TMPLT(tname) \
#define BOOST_UNORDERED_MEMBER_CHECK(tname) \
BOOST_DEDUCED_TYPENAME wrap< \
BOOST_DEDUCED_TYPENAME X::tname \
>::type
#endif
#define BOOST_UNORDERED_DEFAULT_TYPE_TMPLT(tname) \
template <typename Tp, typename Default> \
struct default_type_ ## tname { \
\
template <typename X> \
static choice1::type test(choice1, \
BOOST_DEDUCED_TYPENAME wrap< \
BOOST_DEDUCED_TYPENAME X::tname \
>::type = 0); \
BOOST_UNORDERED_MEMBER_CHECK(tname) = 0); \
\
template <typename X> \
static choice2::type test(choice2, void* = 0); \
@@ -118,18 +131,18 @@ namespace boost { namespace unordered { namespace detail {
::type::tname type; \
}
#define BOOST_DEFAULT_TYPE(T,tname, arg) \
#define BOOST_UNORDERED_DEFAULT_TYPE(T,tname, arg) \
BOOST_DEDUCED_TYPENAME default_type_ ## tname<T, arg>::type
BOOST_DEFAULT_TYPE_TMPLT(pointer);
BOOST_DEFAULT_TYPE_TMPLT(const_pointer);
BOOST_DEFAULT_TYPE_TMPLT(void_pointer);
BOOST_DEFAULT_TYPE_TMPLT(const_void_pointer);
BOOST_DEFAULT_TYPE_TMPLT(difference_type);
BOOST_DEFAULT_TYPE_TMPLT(size_type);
BOOST_DEFAULT_TYPE_TMPLT(propagate_on_container_copy_assignment);
BOOST_DEFAULT_TYPE_TMPLT(propagate_on_container_move_assignment);
BOOST_DEFAULT_TYPE_TMPLT(propagate_on_container_swap);
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);
#if !defined(BOOST_NO_SFINAE_EXPR) || BOOST_WORKAROUND(BOOST_MSVC, >= 1500)
@@ -149,14 +162,40 @@ namespace boost { namespace unordered { namespace detail {
static BOOST_PP_CAT(choice, result)::type test( \
BOOST_PP_CAT(choice, count))
#define BOOST_UNORDERED_HAS_EXPRESSION(name, expression) \
struct BOOST_PP_CAT(has_, name) \
{ \
BOOST_UNORDERED_CHECK_EXPRESSION(1, 1, expression); \
BOOST_UNORDERED_DEFAULT_EXPRESSION(2, 2); \
\
enum { value = sizeof(test<T>(choose())) == sizeof(choice1::type) };\
}
template <typename T>
struct has_select_on_container_copy_construction
{
BOOST_UNORDERED_CHECK_EXPRESSION(1, 1, make<U const>().select_on_container_copy_construction());
BOOST_UNORDERED_DEFAULT_EXPRESSION(2, 2);
enum { value = sizeof(test<T>(choose())) == sizeof(choice1::type) };
};
BOOST_UNORDERED_HAS_EXPRESSION(
select_on_container_copy_construction,
make<U const>().select_on_container_copy_construction()
);
// Only supporting the basic copy constructor for now.
template <typename T, typename ValueType>
BOOST_UNORDERED_HAS_EXPRESSION(
construct,
make<U>().construct(make<ValueType*>(), make<ValueType const>())
);
template <typename T, typename ValueType>
BOOST_UNORDERED_HAS_EXPRESSION(
destroy,
make<U>().destroy(make<ValueType*>())
);
template <typename T>
BOOST_UNORDERED_HAS_EXPRESSION(
max_size,
make<U const>().max_size()
);
#else
@@ -184,12 +223,24 @@ namespace boost { namespace unordered { namespace detail {
template <typename T>
struct has_select_on_container_copy_construction
{
BOOST_UNORDERED_CHECK_MEMBER(1, 1, select_on_container_copy_construction, T (T::*)() const);
BOOST_UNORDERED_CHECK_MEMBER(1, 1,
select_on_container_copy_construction,
T (T::*)() const);
BOOST_UNORDERED_DEFAULT_MEMBER(2, 2);
enum { value = sizeof(test<T>(choose())) == sizeof(choice1::type) };
};
// Detection isn't reliable enough, so just assume that we have these
// functions.
template <typename Alloc, typename value_type>
struct has_construct : true_type {};
template <typename Alloc, typename value_type>
struct has_destroy : true_type {};
template <typename Alloc>
struct has_max_size : true_type {};
#endif
template <typename Alloc>
@@ -208,41 +259,55 @@ namespace boost { namespace unordered { namespace detail {
return rhs;
}
template <typename SizeType, typename Alloc>
SizeType call_max_size(const Alloc& a,
typename boost::enable_if<has_max_size<Alloc>, void*>::type = 0)
{
return a.max_size();
}
template <typename SizeType, typename Alloc>
SizeType call_max_size(const Alloc&,
typename boost::disable_if<has_max_size<Alloc>, void*>::type = 0)
{
return std::numeric_limits<SizeType>::max();
}
template <typename Alloc>
struct allocator_traits
{
typedef Alloc allocator_type;
typedef typename Alloc::value_type value_type;
typedef BOOST_DEFAULT_TYPE(Alloc, pointer, value_type*)
typedef BOOST_UNORDERED_DEFAULT_TYPE(Alloc, pointer, value_type*)
pointer;
// For now always use the allocator's const_pointer.
//typedef BOOST_DEFAULT_TYPE(Alloc, const_pointer,
//typedef BOOST_UNORDERED_DEFAULT_TYPE(Alloc, const_pointer,
// BOOST_DEDUCED_TYPENAME pointer_traits<pointer>::
// BOOST_NESTED_TEMPLATE rebind<const value_type>::other)
// const_pointer;
typedef BOOST_DEFAULT_TYPE(Alloc, const_pointer, value_type const*)
const_pointer;
typedef BOOST_UNORDERED_DEFAULT_TYPE(Alloc, const_pointer,
value_type const*) const_pointer;
// I'm not using void pointers for now.
//typedef BOOST_DEFAULT_TYPE(Alloc, void_pointer,
//typedef BOOST_UNORDERED_DEFAULT_TYPE(Alloc, void_pointer,
// BOOST_NESTED_TEMPLATE pointer_traits<pointer>::
// BOOST_NESTED_TEMPLATE rebind<void>::other)
// void_pointer;
//typedef BOOST_DEFAULT_TYPE(Alloc, const_void_pointer,
//typedef BOOST_UNORDERED_DEFAULT_TYPE(Alloc, const_void_pointer,
// BOOST_DEDUCED_TYPENAME pointer_traits<pointer>::
// BOOST_NESTED_TEMPLATE rebind<const void>::other)
// const_void_pointer;
typedef BOOST_DEFAULT_TYPE(Alloc, difference_type, std::ptrdiff_t)
difference_type;
typedef BOOST_UNORDERED_DEFAULT_TYPE(Alloc, difference_type,
std::ptrdiff_t) difference_type;
typedef BOOST_DEFAULT_TYPE(Alloc, size_type, std::size_t)
typedef BOOST_UNORDERED_DEFAULT_TYPE(Alloc, size_type, std::size_t)
size_type;
// TODO: rebind_alloc and rebind_traits
@@ -252,32 +317,49 @@ namespace boost { namespace unordered { namespace detail {
// 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)
//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); }
// Only support the basic copy constructor
public:
// template <typename T, typename... Args>
// static void construct(Alloc& a, T* p, Args&&... args) {
// DEFAULT_FUNC(construct,void)(a, p, std::forward<Args>(args)...);
// }
// Only supporting the basic copy constructor for now.
template <typename T>
static void construct(Alloc& a, T* p, T const& x) {
static void construct(Alloc& a, T* p, T const& x, typename
boost::enable_if<has_construct<Alloc, T>, void*>::type = 0)
{
a.construct(p, x);
}
template <typename T>
static void destroy(Alloc& a, T* p) {
// DEFAULT_FUNC(destroy,void)(a, p);
static void construct(Alloc&, T* p, T const& x, typename
boost::disable_if<has_construct<Alloc, T>, void*>::type = 0)
{
new ((void*) p) T(x);
}
template <typename T>
static void destroy(Alloc& a, T* p, typename
boost::enable_if<has_destroy<Alloc, T>, void*>::type = 0)
{
a.destroy(p);
}
template <typename T>
static void destroy(Alloc&, T* p, typename
boost::disable_if<has_destroy<Alloc, T>, void*>::type = 0)
{
p->~T();
}
static size_type max_size(const Alloc& a)
{ return a.max_size(); }
{
return boost::unordered::detail::call_max_size<size_type>(a);
}
// Allocator propagation on construction
@@ -289,13 +371,13 @@ namespace boost { namespace unordered { namespace detail {
// Allocator propagation on assignment and swap.
// Return true if lhs is modified.
typedef BOOST_DEFAULT_TYPE(
typedef BOOST_UNORDERED_DEFAULT_TYPE(
Alloc, propagate_on_container_copy_assignment, false_type)
propagate_on_container_copy_assignment;
typedef BOOST_DEFAULT_TYPE(
typedef BOOST_UNORDERED_DEFAULT_TYPE(
Alloc,propagate_on_container_move_assignment, false_type)
propagate_on_container_move_assignment;
typedef BOOST_DEFAULT_TYPE(
typedef BOOST_UNORDERED_DEFAULT_TYPE(
Alloc,propagate_on_container_swap,false_type)
propagate_on_container_swap;
};