// 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 #include #include #include #include // Boilerplate #define ALLOCATOR_METHODS(name) \ template struct rebind \ { \ typedef name other; \ }; \ \ name() {} \ template name(name const&) {} \ T* address(T& r) { return &r; } \ T const* address(T const& r) { return &r; } \ T* allocate(std::size_t n) \ { \ return static_cast(::operator new(n * sizeof(T))); \ } \ T* allocate(std::size_t n, void const*) \ { \ return static_cast(::operator new(n * sizeof(T))); \ } \ void deallocate(T* p, std::size_t) { ::operator delete((void*)p); } \ void construct(T* p, T const& t) { new (p) T(t); } \ void destroy(T* p) { p->~T(); } \ std::size_t max_size() const \ { \ return (std::numeric_limits::max)(); \ } \ bool operator==(name const&) const { return true; } \ bool operator!=(name const&) const { return false; } \ /**/ #define ALLOCATOR_METHODS_TYPEDEFS(name) \ template struct rebind \ { \ typedef name other; \ }; \ \ name() {} \ template name(name const&) {} \ pointer address(T& r) { return &r; } \ const_pointer address(T const& r) { return &r; } \ pointer allocate(std::size_t n) \ { \ return pointer(::operator new(n * sizeof(T))); \ } \ pointer allocate(std::size_t n, void const*) \ { \ return pointer(::operator new(n * sizeof(T))); \ } \ void deallocate(pointer p, std::size_t) { ::operator delete((void*)p); } \ void construct(T* p, T const& t) { new (p) T(t); } \ void destroy(T* p) { p->~T(); } \ size_type max_size() const \ { \ return (std::numeric_limits::max)(); \ } \ bool operator==(name const&) { return true; } \ bool operator!=(name const&) { return false; } \ /**/ struct yes_type { enum { value = true }; }; struct no_type { enum { value = false }; }; // For tracking calls... static int selected; void reset() { selected = 0; } template int call_select() { typedef boost::unordered::detail::allocator_traits traits; Allocator a; reset(); BOOST_TEST(traits::select_on_container_copy_construction(a) == a); return selected; } // Empty allocator test template struct empty_allocator { typedef T value_type; ALLOCATOR_METHODS(empty_allocator) }; void test_empty_allocator() { typedef empty_allocator allocator; typedef boost::unordered::detail::allocator_traits traits; #if BOOST_UNORDERED_USE_ALLOCATOR_TRAITS == 1 BOOST_STATIC_ASSERT((boost::is_same::type>::value)); #else BOOST_STATIC_ASSERT((boost::is_same::value)); #endif BOOST_STATIC_ASSERT( (boost::is_same::value)); BOOST_STATIC_ASSERT((boost::is_same::value)); BOOST_STATIC_ASSERT( (boost::is_same::value)); BOOST_STATIC_ASSERT((boost::is_same::value)); 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); BOOST_TEST(traits::is_always_equal::value); BOOST_TEST(call_select() == 0); } // allocator 1 template struct allocator1 { typedef T value_type; ALLOCATOR_METHODS(allocator1) typedef yes_type propagate_on_container_copy_assignment; typedef yes_type propagate_on_container_move_assignment; typedef yes_type propagate_on_container_swap; typedef yes_type is_always_equal; allocator1 select_on_container_copy_construction() const { ++selected; return allocator1(); } }; void test_allocator1() { typedef allocator1 allocator; typedef boost::unordered::detail::allocator_traits traits; #if BOOST_UNORDERED_USE_ALLOCATOR_TRAITS == 1 BOOST_STATIC_ASSERT((boost::is_same::type>::value)); #else BOOST_STATIC_ASSERT((boost::is_same::value)); #endif BOOST_STATIC_ASSERT( (boost::is_same::value)); BOOST_STATIC_ASSERT((boost::is_same::value)); BOOST_STATIC_ASSERT( (boost::is_same::value)); BOOST_STATIC_ASSERT((boost::is_same::value)); 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); BOOST_TEST(traits::is_always_equal::value); BOOST_TEST(call_select() == 1); } // allocator 2 template struct allocator2_base { Alloc select_on_container_copy_construction() const { ++selected; return Alloc(); } }; template struct allocator2 : allocator2_base > { typedef T value_type; typedef T* pointer; typedef T const* const_pointer; typedef std::size_t size_type; ALLOCATOR_METHODS(allocator2) typedef no_type propagate_on_container_copy_assignment; typedef no_type propagate_on_container_move_assignment; typedef no_type propagate_on_container_swap; typedef no_type is_always_equal; }; void test_allocator2() { typedef allocator2 allocator; typedef boost::unordered::detail::allocator_traits traits; BOOST_STATIC_ASSERT((boost::is_same::value)); BOOST_STATIC_ASSERT( (boost::is_same::value)); BOOST_STATIC_ASSERT((boost::is_same::value)); BOOST_STATIC_ASSERT( (boost::is_same::value)); BOOST_STATIC_ASSERT((boost::is_same::value)); 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); BOOST_TEST(!traits::is_always_equal::value); BOOST_TEST(call_select() == 1); } // allocator 3 template struct ptr { T* value_; ptr(void* v) : value_((T*)v) {} T& operator*() const { return *value_; } }; template <> struct ptr { void* value_; ptr(void* v) : value_(v) {} }; template <> struct ptr { void const* value_; ptr(void const* v) : value_(v) {} }; template struct allocator3 { typedef T value_type; typedef ptr pointer; typedef ptr const_pointer; typedef unsigned short size_type; int x; // Just to make it non-empty, so that is_always_equal is false. ALLOCATOR_METHODS_TYPEDEFS(allocator3) typedef yes_type propagate_on_container_copy_assignment; typedef no_type propagate_on_container_move_assignment; allocator3 select_on_container_copy_construction() const { ++selected; return allocator3(); } }; void test_allocator3() { typedef allocator3 allocator; typedef boost::unordered::detail::allocator_traits traits; BOOST_STATIC_ASSERT( (boost::is_same::value)); BOOST_STATIC_ASSERT( (boost::is_same::value)); BOOST_STATIC_ASSERT((boost::is_same >::value)); BOOST_STATIC_ASSERT( (boost::is_same >::value)); BOOST_STATIC_ASSERT((boost::is_same::value)); 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); BOOST_TEST(!traits::is_always_equal::value); BOOST_TEST(call_select() == 1); } int main() { test_empty_allocator(); test_allocator1(); test_allocator2(); test_allocator3(); return boost::report_errors(); }