forked from boostorg/unordered
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:
@ -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))
|
||||
|
||||
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);
|
||||
#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) };\
|
||||
}
|
||||
|
||||
enum { value = sizeof(test<T>(choose())) == sizeof(choice1::type) };
|
||||
};
|
||||
template <typename T>
|
||||
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;
|
||||
};
|
||||
|
@ -23,6 +23,7 @@ test-suite unordered
|
||||
[ run fwd_set_test.cpp ]
|
||||
[ run fwd_map_test.cpp ]
|
||||
[ run allocator_traits.cpp ]
|
||||
[ run minimal_allocator.cpp ]
|
||||
[ run compile_set.cpp ]
|
||||
[ run compile_map.cpp ]
|
||||
[ run link_test_1.cpp link_test_2.cpp ]
|
||||
@ -39,7 +40,7 @@ test-suite unordered
|
||||
[ run erase_tests.cpp ]
|
||||
[ run erase_equiv_tests.cpp ]
|
||||
[ run find_tests.cpp ]
|
||||
[ run at_tests.cpp ]
|
||||
# [ run at_tests.cpp ]
|
||||
[ run bucket_tests.cpp ]
|
||||
[ run load_factor_tests.cpp ]
|
||||
[ run rehash_tests.cpp ]
|
||||
|
89
test/unordered/minimal_allocator.cpp
Normal file
89
test/unordered/minimal_allocator.cpp
Normal file
@ -0,0 +1,89 @@
|
||||
|
||||
// Copyright 2011 Daniel James.
|
||||
// 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)
|
||||
|
||||
#include <boost/unordered/detail/allocator_helpers.hpp>
|
||||
#include <boost/detail/lightweight_test.hpp>
|
||||
#include <boost/type_traits/is_same.hpp>
|
||||
#include <boost/mpl/assert.hpp>
|
||||
#include "../objects/test.hpp"
|
||||
|
||||
template <class Tp>
|
||||
struct SimpleAllocator
|
||||
{
|
||||
typedef Tp value_type;
|
||||
|
||||
SimpleAllocator()
|
||||
{
|
||||
}
|
||||
|
||||
template <class T> SimpleAllocator(const SimpleAllocator<T>& other)
|
||||
{
|
||||
}
|
||||
|
||||
Tp *allocate(std::size_t n)
|
||||
{
|
||||
return static_cast<Tp*>(::operator new(n * sizeof(Tp)));
|
||||
}
|
||||
|
||||
void deallocate(Tp* p, std::size_t)
|
||||
{
|
||||
::operator delete((void*) p);
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
void test_simple_allocator()
|
||||
{
|
||||
test::check_instances check_;
|
||||
|
||||
typedef boost::unordered::detail::allocator_traits<
|
||||
SimpleAllocator<T> > traits;
|
||||
|
||||
BOOST_MPL_ASSERT((boost::is_same<typename traits::allocator_type, SimpleAllocator<T> >));
|
||||
|
||||
BOOST_MPL_ASSERT((boost::is_same<typename traits::value_type, T>));
|
||||
|
||||
BOOST_MPL_ASSERT((boost::is_same<typename traits::pointer, T* >));
|
||||
BOOST_MPL_ASSERT((boost::is_same<typename traits::const_pointer, T const*>));
|
||||
//BOOST_MPL_ASSERT((boost::is_same<typename traits::void_pointer, void* >));
|
||||
//BOOST_MPL_ASSERT((boost::is_same<typename traits::const_void_pointer, void const*>));
|
||||
|
||||
BOOST_MPL_ASSERT((boost::is_same<typename traits::difference_type, std::ptrdiff_t>));
|
||||
BOOST_MPL_ASSERT((boost::is_same<typename traits::size_type, std::size_t>));
|
||||
|
||||
BOOST_TEST(!traits::propagate_on_container_copy_assignment::value);
|
||||
BOOST_TEST(!traits::propagate_on_container_move_assignment::value);
|
||||
BOOST_TEST(!traits::propagate_on_container_swap::value);
|
||||
|
||||
// rebind_alloc
|
||||
// rebind_traits
|
||||
|
||||
SimpleAllocator<T> a;
|
||||
|
||||
T* ptr1 = traits::allocate(a, 1);
|
||||
//T* ptr2 = traits::allocate(a, 1, static_cast<void const*>(ptr1));
|
||||
|
||||
traits::construct(a, ptr1, T(10));
|
||||
//traits::construct(a, ptr2, T(30), ptr1);
|
||||
|
||||
BOOST_TEST(*ptr1 == T(10));
|
||||
//BOOST_TEST(*ptr2 == T(30));
|
||||
|
||||
traits::destroy(a, ptr1);
|
||||
//traits::destroy(a, ptr2);
|
||||
|
||||
//traits::deallocate(a, ptr2, 1);
|
||||
traits::deallocate(a, ptr1, 1);
|
||||
|
||||
traits::max_size(a);
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
test_simple_allocator<int>();
|
||||
test_simple_allocator<test::object>();
|
||||
|
||||
return boost::report_errors();
|
||||
}
|
Reference in New Issue
Block a user