// 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