From e7d34a5ab1cb79b121584e83c417060d6d2f942a Mon Sep 17 00:00:00 2001 From: Christian Mazakas Date: Fri, 20 May 2022 13:53:40 -0700 Subject: [PATCH 01/13] Remove unsupported Windows image from GHA CI --- .github/workflows/ci.yml | 4 ---- 1 file changed, 4 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 67ac6a04..e58e8782 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -157,10 +157,6 @@ jobs: cxxstd: 14,latest addrmd: 32,64 os: windows-2019 - - toolset: msvc-14.1 - cxxstd: "14,17,latest" - addrmd: 32,64 - os: windows-2016 - toolset: msvc-14.2 cxxstd: "14,17,20,latest" addrmd: 32,64 From 0bcc79baab535e4bb78f046abe2c180537e9396b Mon Sep 17 00:00:00 2001 From: Christian Mazakas Date: Fri, 20 May 2022 14:07:44 -0700 Subject: [PATCH 02/13] Update test allocators to be C++11 compliant by making them templates on the pointer type --- test/objects/cxx11_allocator.hpp | 27 ++++++++------- test/objects/exception.hpp | 58 ++++++++++++++++++-------------- test/objects/minimal.hpp | 50 ++++++++++++++++----------- test/objects/test.hpp | 24 +++++++------ 4 files changed, 91 insertions(+), 68 deletions(-) diff --git a/test/objects/cxx11_allocator.hpp b/test/objects/cxx11_allocator.hpp index 8f3a7711..9e5749ce 100644 --- a/test/objects/cxx11_allocator.hpp +++ b/test/objects/cxx11_allocator.hpp @@ -1,5 +1,6 @@ // Copyright 2006-2011 Daniel James. +// Copyright 2022 Christian Mazakas // 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) @@ -213,25 +214,27 @@ namespace test ::operator delete((void*)p); } - void construct(T* p, T const& t) +#if defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) + template + void construct(U* p, V const& v) { - detail::tracker.track_construct((void*)p, sizeof(T), tag_); - new (p) T(t); + detail::tracker.track_construct((void*)p, sizeof(U), tag_); + new (p) U(v); } - -#if !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) - template - void construct(T* p, BOOST_FWD_REF(Args)... args) +#else + template + void construct(U* p, BOOST_FWD_REF(Args)... args) { - detail::tracker.track_construct((void*)p, sizeof(T), tag_); - new (p) T(boost::forward(args)...); + detail::tracker.track_construct((void*)p, sizeof(U), tag_); + new (p) U(boost::forward(args)...); } #endif - void destroy(T* p) + template + void destroy(U* p) { - detail::tracker.track_destroy((void*)p, sizeof(T), tag_); - p->~T(); + detail::tracker.track_destroy((void*)p, sizeof(U), tag_); + p->~U(); } size_type max_size() const diff --git a/test/objects/exception.hpp b/test/objects/exception.hpp index b684d686..b5570e1d 100644 --- a/test/objects/exception.hpp +++ b/test/objects/exception.hpp @@ -1,5 +1,6 @@ // Copyright 2006-2009 Daniel James. +// Copyright 2022 Christian Mazakas // 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) @@ -475,32 +476,34 @@ namespace test { } } - void construct(pointer p, T const& t) +#if defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) + template + void construct(U* p, Arg const& t) { - UNORDERED_SCOPE(allocator::construct(T*, T)) + UNORDERED_SCOPE(allocator::construct(U*, Arg)) { UNORDERED_EPOINT("Mock allocator construct function."); - new (p) T(t); + new (p) U(t); } - test::detail::tracker.track_construct((void*)p, sizeof(T), tag_); + test::detail::tracker.track_construct((void*)p, sizeof(U), tag_); } - -#if !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) - template void construct(T* p, BOOST_FWD_REF(Args)... args) +#else + template void construct(U* p, BOOST_FWD_REF(Args)... args) { - UNORDERED_SCOPE(allocator::construct(pointer, BOOST_FWD_REF(Args)...)) + UNORDERED_SCOPE(allocator::construct(U*, BOOST_FWD_REF(Args)...)) { UNORDERED_EPOINT("Mock allocator construct function."); - new (p) T(boost::forward(args)...); + new (p) U(boost::forward(args)...); } - test::detail::tracker.track_construct((void*)p, sizeof(T), tag_); + test::detail::tracker.track_construct((void*)p, sizeof(U), tag_); } #endif - void destroy(T* p) + template + void destroy(U* p) { - test::detail::tracker.track_destroy((void*)p, sizeof(T), tag_); - p->~T(); + test::detail::tracker.track_destroy((void*)p, sizeof(U), tag_); + p->~U(); } size_type max_size() const @@ -654,32 +657,35 @@ namespace test { } } - void construct(pointer p, T const& t) +#if defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) + template + void construct(U* p, V const& v) { - UNORDERED_SCOPE(allocator2::construct(T*, T)) + UNORDERED_SCOPE(allocator2::construct(U*, V)) { UNORDERED_EPOINT("Mock allocator2 construct function."); - new (p) T(t); + new (p) U(v); } - test::detail::tracker.track_construct((void*)p, sizeof(T), tag_); + test::detail::tracker.track_construct((void*)p, sizeof(U), tag_); } - -#if !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) - template void construct(T* p, BOOST_FWD_REF(Args)... args) +#else + template + void construct(U* p, BOOST_FWD_REF(Args)... args) { - UNORDERED_SCOPE(allocator2::construct(pointer, BOOST_FWD_REF(Args)...)) + UNORDERED_SCOPE(allocator2::construct(U*, BOOST_FWD_REF(Args)...)) { UNORDERED_EPOINT("Mock allocator2 construct function."); - new (p) T(boost::forward(args)...); + new (p) U(boost::forward(args)...); } - test::detail::tracker.track_construct((void*)p, sizeof(T), tag_); + test::detail::tracker.track_construct((void*)p, sizeof(U), tag_); } #endif - void destroy(T* p) + template + void destroy(U* p) { - test::detail::tracker.track_destroy((void*)p, sizeof(T), tag_); - p->~T(); + test::detail::tracker.track_destroy((void*)p, sizeof(U), tag_); + p->~U(); } size_type max_size() const diff --git a/test/objects/minimal.hpp b/test/objects/minimal.hpp index b89e0af8..0b6ebf4a 100644 --- a/test/objects/minimal.hpp +++ b/test/objects/minimal.hpp @@ -1,5 +1,6 @@ // Copyright 2006-2009 Daniel James. +// Copyright 2022 Christian Mazakas // 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) @@ -428,16 +429,20 @@ namespace test { ::operator delete((void*)p.ptr_); } - void construct(T* p, T const& t) { new ((void*)p) T(t); } - -#if !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) - template void construct(T* p, BOOST_FWD_REF(Args)... args) +#if defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) + template void construct(U* p, V const& v) { - new ((void*)p) T(boost::forward(args)...); + new ((void*)p) U(v); + } +#else + template + void construct(U* p, BOOST_FWD_REF(Args)... args) + { + new ((void*)p) U(boost::forward(args)...); } #endif - void destroy(T* p) { p->~T(); } + template void destroy(U* p) { p->~U(); } size_type max_size() const { return 1000; } @@ -498,17 +503,20 @@ namespace test { ::operator delete((void*)p.ptr_); } - void construct(T const* p, T const& t) { new ((void*)p) T(t); } - -#if !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) - template - void construct(T const* p, BOOST_FWD_REF(Args)... args) +#if defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) + template void construct(U* p, U const& t) { - new ((void*)p) T(boost::forward(args)...); + new (p) U(t); + } +#else + template + void construct(U* p, BOOST_FWD_REF(Args)... args) + { + new (p) U(boost::forward(args)...); } #endif - void destroy(T const* p) { p->~T(); } + template void destroy(U* p) { p->~U(); } size_type max_size() const { return 1000; } @@ -573,16 +581,20 @@ namespace test { void deallocate(T* p, std::size_t) { ::operator delete((void*)p); } - void construct(T* p, T const& t) { new ((void*)p) T(t); } - -#if !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) - template void construct(T* p, BOOST_FWD_REF(Args)... args) +#if defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) + template void construct(U* p, V const& v) { - new ((void*)p) T(boost::forward(args)...); + new ((void*)p) U(v); + } +#else + template + void construct(U* p, BOOST_FWD_REF(Args)... args) + { + new ((void*)p) U(boost::forward(args)...); } #endif - void destroy(T* p) { p->~T(); } + template void destroy(U* p) { p->~U(); } std::size_t max_size() const { return 1000u; } }; diff --git a/test/objects/test.hpp b/test/objects/test.hpp index 137c01c8..53569d30 100644 --- a/test/objects/test.hpp +++ b/test/objects/test.hpp @@ -1,5 +1,6 @@ // Copyright 2006-2009 Daniel James. +// Copyright 2022 Christian Mazakas // 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) @@ -646,24 +647,25 @@ namespace test { ::operator delete((void*)p.ptr_); } - void construct(T* p, T const& t) +#if defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) + template void construct(U* p, V const& v) { - detail::tracker.track_construct((void*)p, sizeof(T), tag_); - new (p) T(t); + detail::tracker.track_construct((void*)p, sizeof(U), tag_); + new (p) U(v); } - -#if !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) - template void construct(T* p, BOOST_FWD_REF(Args)... args) +#else + template + void construct(U* p, BOOST_FWD_REF(Args)... args) { - detail::tracker.track_construct((void*)p, sizeof(T), tag_); - new (p) T(boost::forward(args)...); + detail::tracker.track_construct((void*)p, sizeof(U), tag_); + new (p) U(boost::forward(args)...); } #endif - void destroy(T* p) + template void destroy(U* p) { - detail::tracker.track_destroy((void*)p, sizeof(T), tag_); - p->~T(); + detail::tracker.track_destroy((void*)p, sizeof(U), tag_); + p->~U(); } size_type max_size() const From 4f43bc5ec7112c7c7d64e75f1a7129818c5cb10a Mon Sep 17 00:00:00 2001 From: Christian Mazakas Date: Fri, 20 May 2022 14:08:35 -0700 Subject: [PATCH 03/13] Add missing #include for usage of BOOST_TEST macro --- test/objects/minimal.hpp | 1 + 1 file changed, 1 insertion(+) diff --git a/test/objects/minimal.hpp b/test/objects/minimal.hpp index 0b6ebf4a..de723260 100644 --- a/test/objects/minimal.hpp +++ b/test/objects/minimal.hpp @@ -11,6 +11,7 @@ #if !defined(BOOST_UNORDERED_OBJECTS_MINIMAL_HEADER) #define BOOST_UNORDERED_OBJECTS_MINIMAL_HEADER +#include #include #include #include From 954db4e2460a57e9efadf0f0857312fdbafbc6f8 Mon Sep 17 00:00:00 2001 From: Christian Mazakas Date: Fri, 20 May 2022 14:14:01 -0700 Subject: [PATCH 04/13] Extend fancy pointer types used by test allocators to support a wider array of semantic operations --- test/objects/minimal.hpp | 23 +++++++++++++++++++---- test/objects/test.hpp | 21 +++++++++++++++++++++ 2 files changed, 40 insertions(+), 4 deletions(-) diff --git a/test/objects/minimal.hpp b/test/objects/minimal.hpp index de723260..f5298265 100644 --- a/test/objects/minimal.hpp +++ b/test/objects/minimal.hpp @@ -12,6 +12,7 @@ #define BOOST_UNORDERED_OBJECTS_MINIMAL_HEADER #include +#include #include #include #include @@ -311,13 +312,17 @@ namespace test { return tmp; } ptr operator+(std::ptrdiff_t s) const { return ptr(ptr_ + s); } - friend ptr operator+(std::ptrdiff_t s, ptr p) - { - return ptr(s + p.ptr_); - } + friend ptr operator+(std::ptrdiff_t s, ptr p) { return ptr(s + p.ptr_); } + + std::ptrdiff_t operator-(ptr p) const { return ptr_ - p.ptr_; } + ptr operator-(std::ptrdiff_t s) const { return ptr(ptr_ - s); } T& operator[](std::ptrdiff_t s) const { return ptr_[s]; } bool operator!() const { return !ptr_; } + static ptr pointer_to(T& p) { + return ptr(&p); + } + // I'm not using the safe bool idiom because the containers should be // able to cope with bool conversions. operator bool() const { return !!ptr_; } @@ -637,4 +642,14 @@ namespace test { #pragma warning(pop) #endif +namespace boost { + template <> struct pointer_traits< ::test::minimal::void_ptr> + { + template struct rebind_to + { + typedef ::test::minimal::ptr type; + }; + }; +} + #endif diff --git a/test/objects/test.hpp b/test/objects/test.hpp index 53569d30..b3d9c2e8 100644 --- a/test/objects/test.hpp +++ b/test/objects/test.hpp @@ -521,11 +521,22 @@ namespace test { ++ptr_; return tmp; } + ptr operator+(std::ptrdiff_t s) const { return ptr(ptr_ + s); } friend ptr operator+(std::ptrdiff_t s, ptr p) { return ptr(s + p.ptr_); } + + std::ptrdiff_t operator-(ptr p) const { return ptr_ - p.ptr_; } + ptr operator-(std::ptrdiff_t s) const { return ptr(ptr_ - s); } + + ptr& operator+=(std::ptrdiff_t s) { ptr_ += s; return *this; } + T& operator[](std::ptrdiff_t s) const { return ptr_[s]; } bool operator!() const { return !ptr_; } + static ptr pointer_to(T& p) { + return ptr(&p); + } + // I'm not using the safe bool idiom because the containers should be // able to cope with bool conversions. operator bool() const { return !!ptr_; } @@ -701,4 +712,14 @@ namespace test { } } +namespace boost { + template <> struct pointer_traits< ::test::void_ptr> + { + template struct rebind_to + { + typedef ::test::ptr type; + }; + }; +} // namespace boost + #endif From 8473d8120f64de6d829b22a3333a20797183578d Mon Sep 17 00:00:00 2001 From: Christian Mazakas Date: Fri, 20 May 2022 14:14:48 -0700 Subject: [PATCH 05/13] Mark test Hasher and KeyEqual as `final` to extend test coverage --- test/objects/test.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/objects/test.hpp b/test/objects/test.hpp index b3d9c2e8..3b80d6c0 100644 --- a/test/objects/test.hpp +++ b/test/objects/test.hpp @@ -185,7 +185,7 @@ namespace test { }; // Note: This is a deliberately bad hash function. - class hash + class hash BOOST_FINAL { int type_; @@ -298,7 +298,7 @@ namespace test { } }; - class equal_to + class equal_to BOOST_FINAL { int type_; From 641c9fba9ca21bbf6d7112d6c6dfb95aae2bee8e Mon Sep 17 00:00:00 2001 From: Christian Mazakas Date: Fri, 20 May 2022 14:15:38 -0700 Subject: [PATCH 06/13] Update `operator()` implementations for predicate classes to properly return a bool --- test/objects/test.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/objects/test.hpp b/test/objects/test.hpp index 3b80d6c0..1479b5ab 100644 --- a/test/objects/test.hpp +++ b/test/objects/test.hpp @@ -290,7 +290,7 @@ namespace test { } } - std::size_t operator()(int x1, int x2) const { return x1 < x2; } + bool operator()(int x1, int x2) const { return x1 < x2; } friend bool operator==(less const& x1, less const& x2) { @@ -331,7 +331,7 @@ namespace test { } } - std::size_t operator()(int x1, int x2) const { return x1 == x2; } + bool operator()(int x1, int x2) const { return x1 == x2; } friend bool operator==(equal_to const& x1, equal_to const& x2) { From 2ae686c36631f75a6dec4dc374f964891b092448 Mon Sep 17 00:00:00 2001 From: Christian Mazakas Date: Fri, 20 May 2022 14:17:43 -0700 Subject: [PATCH 07/13] Add tests for testing the SCARY-ness of iterators --- test/Jamfile.v2 | 2 + test/objects/test.hpp | 6 +- test/unordered/scary_tests.cpp | 326 +++++++++++++++++++++++++++++++++ 3 files changed, 330 insertions(+), 4 deletions(-) create mode 100644 test/unordered/scary_tests.cpp diff --git a/test/Jamfile.v2 b/test/Jamfile.v2 index 698dff92..5d28e3a2 100644 --- a/test/Jamfile.v2 +++ b/test/Jamfile.v2 @@ -1,5 +1,6 @@ # Copyright 2006-2008 Daniel James. +# Copyright 2022 Christian Mazakas # 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) @@ -77,6 +78,7 @@ test-suite unordered [ run unordered/contains_tests.cpp ] [ run unordered/mix_policy.cpp ] [ run unordered/erase_if.cpp ] + [ run unordered/scary_tests.cpp ] [ run unordered/compile_set.cpp : : : BOOST_UNORDERED_USE_MOVE diff --git a/test/objects/test.hpp b/test/objects/test.hpp index 1479b5ab..0bcf78e8 100644 --- a/test/objects/test.hpp +++ b/test/objects/test.hpp @@ -500,11 +500,9 @@ namespace test { friend class const_ptr; friend struct void_ptr; - T* ptr_; - - ptr(T* x) : ptr_(x) {} - public: + T* ptr_; + ptr(T* x) : ptr_(x) {} ptr() : ptr_(0) {} explicit ptr(void_ptr const& x) : ptr_((T*)x.ptr_) {} diff --git a/test/unordered/scary_tests.cpp b/test/unordered/scary_tests.cpp new file mode 100644 index 00000000..f671f68e --- /dev/null +++ b/test/unordered/scary_tests.cpp @@ -0,0 +1,326 @@ +// Copyright 2022 Christian Mazakas. +// 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) + +// clang-format off +#include "../helpers/prefix.hpp" +#include +#include +#include "../helpers/postfix.hpp" +// clang-format on + +#include "../helpers/test.hpp" +#include "../objects/test.hpp" + +#include + +struct hash1 +{ + template std::size_t operator()(Key const&) const { return 1337; } +}; + +struct hash2 +{ + template std::size_t operator()(Key const&) const { return 7331; } +}; + +struct equal1 +{ + template bool operator==(T const&) const { return true; } +}; + +struct equal2 +{ + template bool operator==(T const&) const { return true; } +}; + +/////////////////////////////////////////////////////////////////////////////// +// we define two duplicated allocators here, each one having the same smart +// pointer type +// we want to prove in our test that different allocators with the same pointers +// (either fancy or raw) work equally well for our SCARY iterators +// +template struct allocator1 +{ +#ifdef BOOST_NO_MEMBER_TEMPLATE_FRIENDS +public: +#else + template friend struct allocator1; +#endif + +public: + typedef std::size_t size_type; + typedef std::ptrdiff_t difference_type; + typedef test::void_ptr void_pointer; + typedef test::void_const_ptr const_void_pointer; + typedef test::ptr pointer; + typedef test::const_ptr const_pointer; + typedef T& reference; + typedef T const& const_reference; + typedef T value_type; + + template struct rebind + { + typedef allocator1 other; + }; + + allocator1() {} + + template allocator1(allocator1 const&) {} + + allocator1(allocator1 const&) {} + + ~allocator1() {} + + pointer address(reference r) { return pointer(&r); } + + const_pointer address(const_reference r) { return const_pointer(&r); } + + pointer allocate(size_type n) + { + pointer p(static_cast(::operator new(n * sizeof(T)))); + return p; + } + + pointer allocate(size_type n, void const*) + { + pointer ptr(static_cast(::operator new(n * sizeof(T)))); + return ptr; + } + + void deallocate(pointer p, size_type) + { + ::operator delete((void*)p.operator->()); + } + +#if defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) + template void construct(U* p, V const& v) { new (p) U(v); } +#else + template + void construct(U* p, BOOST_FWD_REF(Args)... args) + { + new (p) U(boost::forward(args)...); + } +#endif + + // msvc-12.0 and msvc-14.0 seem to eliminate the destructor call as we're only + // ever using it with an int with has a trivial destructor so it eliminates + // the code and generates a warning about an unused variable + // + template + void destroy(U* p) + { + (void)p; + p->~U(); + } + + size_type max_size() const { return (std::numeric_limits::max)(); } + + bool operator==(allocator1 const&) const { return true; } + bool operator!=(allocator1 const&) const { return false; } + + enum + { + is_select_on_copy = false, + is_propagate_on_swap = false, + is_propagate_on_assign = false, + is_propagate_on_move = false + }; +}; + +template struct allocator2 +{ +#ifdef BOOST_NO_MEMBER_TEMPLATE_FRIENDS +public: +#else + template friend struct allocator2; +#endif + +public: + typedef std::size_t size_type; + typedef std::ptrdiff_t difference_type; + typedef test::void_ptr void_pointer; + typedef test::void_const_ptr const_void_pointer; + typedef test::ptr pointer; + typedef test::const_ptr const_pointer; + typedef T& reference; + typedef T const& const_reference; + typedef T value_type; + + template struct rebind + { + typedef allocator2 other; + }; + + allocator2() {} + + template allocator2(allocator2 const&) {} + + allocator2(allocator2 const&) {} + + ~allocator2() {} + + pointer address(reference r) { return pointer(&r); } + + const_pointer address(const_reference r) { return const_pointer(&r); } + + pointer allocate(size_type n) + { + pointer p(static_cast(::operator new(n * sizeof(T)))); + return p; + } + + pointer allocate(size_type n, void const*) + { + pointer ptr(static_cast(::operator new(n * sizeof(T)))); + return ptr; + } + + void deallocate(pointer p, size_type) { ::operator delete((void*)p.ptr_); } + +#if defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) + template void construct(U* p, V const& v) { new (p) U(v); } +#else + template + void construct(U* p, BOOST_FWD_REF(Args)... args) + { + new (p) U(boost::forward(args)...); + } +#endif + + // msvc-12.0 and msvc-14.0 seem to eliminate the destructor call as we're only + // ever using it with an int with has a trivial destructor so it eliminates + // the code and generates a warning about an unused variable + // + template + void destroy(U* p) + { + (void)p; + p->~U(); + } + + size_type max_size() const { return (std::numeric_limits::max)(); } + + bool operator==(allocator2 const&) const { return true; } + bool operator!=(allocator2 const&) const { return false; } + + enum + { + is_select_on_copy = false, + is_propagate_on_swap = false, + is_propagate_on_assign = false, + is_propagate_on_move = false + }; +}; + +template void scary_test() +{ + C1 x; + C2 y; + + typename C2::iterator begin(x.begin()); + BOOST_TEST(begin == x.end()); + + typename C2::const_iterator cbegin(x.cbegin()); + BOOST_TEST(cbegin == x.cend()); + + BOOST_ASSERT(x.bucket_count() > 0); + + typename C2::local_iterator lbegin(x.begin(0)); + BOOST_TEST(lbegin == x.end(0)); + + typename C2::const_local_iterator clbegin(x.cbegin(0)); + BOOST_TEST(clbegin == x.cend(0)); +} + +template < + template + class Map> +void map_scary_test() +{ + typedef std::pair value_type; + typedef std::allocator std_allocator_type; + + typedef Map, std_allocator_type> + hash1_unordered_map; + typedef Map, std_allocator_type> + hash2_unordered_map; + + typedef Map, equal1, std_allocator_type> + equal1_unordered_map; + typedef Map, equal2, std_allocator_type> + equal2_unordered_map; + + // test allocators with a raw pointer as their `::pointer` type + // + typedef Map, std::equal_to, + test::allocator1 > + alloc1_unordered_map; + typedef Map, std::equal_to, + std_allocator_type> + std_alloc_unordered_map; + + // test allocators with a fancy pointer as their `::pointer` type + // + typedef Map, std::equal_to, + allocator1 > + fancy1_unordered_map; + typedef Map, std::equal_to, + allocator2 > + fancy2_unordered_map; + + scary_test(); + scary_test(); + scary_test(); + scary_test(); +} + +template