1// Copyright 2022-2023 Christian Mazakas.
2// Distributed under the Boost Software License, Version 1.0. (See accompanying
3// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
4
5#include "../helpers/test.hpp"
6#include "../helpers/unordered.hpp"
7#include "../objects/test.hpp"
8
9#include <memory>
10
11struct hash1
12{
13 template <class Key> std::size_t operator()(Key const&) const { return 1337; }
14};
15
16struct hash2
17{
18 template <class Key> std::size_t operator()(Key const&) const { return 7331; }
19};
20
21struct equal1
22{
23 template <class T> bool operator==(T const&) const { return true; }
24};
25
26struct equal2
27{
28 template <class T> bool operator==(T const&) const { return true; }
29};
30
31///////////////////////////////////////////////////////////////////////////////
32// we define two duplicated allocators here, each one having the same smart
33// pointer type
34// we want to prove in our test that different allocators with the same pointers
35// (either fancy or raw) work equally well for our SCARY iterators
36//
37template <class T> struct allocator1
38{
39#ifdef BOOST_NO_MEMBER_TEMPLATE_FRIENDS
40public:
41#else
42 template <class> friend struct allocator1;
43#endif
44
45public:
46 typedef std::size_t size_type;
47 typedef std::ptrdiff_t difference_type;
48 typedef test::void_ptr void_pointer;
49 typedef test::void_const_ptr const_void_pointer;
50 typedef test::ptr<T> pointer;
51 typedef test::const_ptr<T> const_pointer;
52 typedef T& reference;
53 typedef T const& const_reference;
54 typedef T value_type;
55
56 template <class U> struct rebind
57 {
58 typedef allocator1<U> other;
59 };
60
61 allocator1() {}
62
63 template <class Y> allocator1(allocator1<Y> const&) {}
64
65 allocator1(allocator1 const&) {}
66
67 ~allocator1() {}
68
69 pointer address(reference r) { return pointer(&r); }
70
71 const_pointer address(const_reference r) { return const_pointer(&r); }
72
73 pointer allocate(size_type n)
74 {
75 pointer p(static_cast<T*>(::operator new(n * sizeof(T))));
76 return p;
77 }
78
79 pointer allocate(size_type n, void const*)
80 {
81 pointer ptr(static_cast<T*>(::operator new(n * sizeof(T))));
82 return ptr;
83 }
84
85 void deallocate(pointer p, size_type)
86 {
87 ::operator delete((void*)p.operator->());
88 }
89
90 template <class U, class... Args>
91 void construct(U* p, Args&&... args)
92 {
93 new (p) U(std::forward<Args>(args)...);
94 }
95
96 // msvc-12.0 and msvc-14.0 seem to eliminate the destructor call as we're only
97 // ever using it with an int with has a trivial destructor so it eliminates
98 // the code and generates a warning about an unused variable
99 //
100 template <class U> void destroy(U* p)
101 {
102 (void)p;
103 p->~U();
104 }
105
106 size_type max_size() const { return (std::numeric_limits<size_type>::max)(); }
107
108 bool operator==(allocator1 const&) const { return true; }
109 bool operator!=(allocator1 const&) const { return false; }
110
111 enum
112 {
113 is_select_on_copy = false,
114 is_propagate_on_swap = false,
115 is_propagate_on_assign = false,
116 is_propagate_on_move = false
117 };
118};
119
120template <class T> struct allocator2
121{
122#ifdef BOOST_NO_MEMBER_TEMPLATE_FRIENDS
123public:
124#else
125 template <class> friend struct allocator2;
126#endif
127
128public:
129 typedef std::size_t size_type;
130 typedef std::ptrdiff_t difference_type;
131 typedef test::void_ptr void_pointer;
132 typedef test::void_const_ptr const_void_pointer;
133 typedef test::ptr<T> pointer;
134 typedef test::const_ptr<T> const_pointer;
135 typedef T& reference;
136 typedef T const& const_reference;
137 typedef T value_type;
138
139 template <class U> struct rebind
140 {
141 typedef allocator2<U> other;
142 };
143
144 allocator2() {}
145
146 template <class Y> allocator2(allocator2<Y> const&) {}
147
148 allocator2(allocator2 const&) {}
149
150 ~allocator2() {}
151
152 pointer address(reference r) { return pointer(&r); }
153
154 const_pointer address(const_reference r) { return const_pointer(&r); }
155
156 pointer allocate(size_type n)
157 {
158 pointer p(static_cast<T*>(::operator new(n * sizeof(T))));
159 return p;
160 }
161
162 pointer allocate(size_type n, void const*)
163 {
164 pointer ptr(static_cast<T*>(::operator new(n * sizeof(T))));
165 return ptr;
166 }
167
168 void deallocate(pointer p, size_type) { ::operator delete((void*)p.ptr_); }
169
170 template <class U, class... Args>
171 void construct(U* p, Args&&... args)
172 {
173 new (p) U(std::forward<Args>(args)...);
174 }
175
176 // msvc-12.0 and msvc-14.0 seem to eliminate the destructor call as we're only
177 // ever using it with an int with has a trivial destructor so it eliminates
178 // the code and generates a warning about an unused variable
179 //
180 template <class U> void destroy(U* p)
181 {
182 (void)p;
183 p->~U();
184 }
185
186 size_type max_size() const { return (std::numeric_limits<size_type>::max)(); }
187
188 bool operator==(allocator2 const&) const { return true; }
189 bool operator!=(allocator2 const&) const { return false; }
190
191 enum
192 {
193 is_select_on_copy = false,
194 is_propagate_on_swap = false,
195 is_propagate_on_assign = false,
196 is_propagate_on_move = false
197 };
198};
199
200template <class C1, class C2> void scary_test()
201{
202 C1 x;
203 C2 y;
204
205 typename C2::iterator begin(x.begin());
206 BOOST_TEST(begin == x.end());
207
208 typename C2::const_iterator cbegin(x.cbegin());
209 BOOST_TEST(cbegin == x.cend());
210
211#ifndef BOOST_UNORDERED_FOA_TESTS
212 typename C2::local_iterator lbegin(x.begin(0));
213 BOOST_TEST(lbegin == x.end(0));
214
215 typename C2::const_local_iterator clbegin(x.cbegin(0));
216 BOOST_TEST(clbegin == x.cend(0));
217#endif
218}
219
220template <
221 template <class Key, class T, class Hash, class KeyEqual, class Allocator>
222 class Map>
223void map_scary_test()
224{
225 typedef std::pair<int const, int> value_type;
226 typedef std::allocator<value_type> std_allocator_type;
227
228 typedef Map<int, int, hash1, std::equal_to<int>, std_allocator_type>
229 hash1_unordered_map;
230 typedef Map<int, int, hash2, std::equal_to<int>, std_allocator_type>
231 hash2_unordered_map;
232
233 typedef Map<int, int, boost::hash<int>, equal1, std_allocator_type>
234 equal1_unordered_map;
235 typedef Map<int, int, boost::hash<int>, equal2, std_allocator_type>
236 equal2_unordered_map;
237
238 // test allocators with a raw pointer as their `::pointer` type
239 //
240 typedef Map<int, int, boost::hash<int>, std::equal_to<int>,
241 test::allocator1<value_type> >
242 alloc1_unordered_map;
243 typedef Map<int, int, boost::hash<int>, std::equal_to<int>,
244 std_allocator_type>
245 std_alloc_unordered_map;
246
247 // test allocators with a fancy pointer as their `::pointer` type
248 //
249 typedef Map<int, int, boost::hash<int>, std::equal_to<int>,
250 allocator1<value_type> >
251 fancy1_unordered_map;
252 typedef Map<int, int, boost::hash<int>, std::equal_to<int>,
253 allocator2<value_type> >
254 fancy2_unordered_map;
255
256 scary_test<alloc1_unordered_map, std_alloc_unordered_map>();
257 scary_test<hash1_unordered_map, hash2_unordered_map>();
258 scary_test<equal1_unordered_map, equal2_unordered_map>();
259 scary_test<fancy1_unordered_map, fancy2_unordered_map>();
260}
261
262template <template <class Key, class Hash, class KeyEqual, class Allocator>
263 class Set>
264void set_scary_test()
265{
266 typedef int value_type;
267 typedef std::allocator<value_type> std_allocator_type;
268
269 typedef Set<int, hash1, std::equal_to<int>, std_allocator_type>
270 hash1_unordered_set;
271 typedef Set<int, hash2, std::equal_to<int>, std_allocator_type>
272 hash2_unordered_set;
273
274 typedef Set<int, boost::hash<int>, equal1, std_allocator_type>
275 equal1_unordered_set;
276 typedef Set<int, boost::hash<int>, equal2, std_allocator_type>
277 equal2_unordered_set;
278
279 // test allocators with a raw pointer as their `::pointer` type
280 //
281 typedef Set<int, boost::hash<int>, std::equal_to<int>,
282 test::allocator1<value_type> >
283 alloc1_unordered_set;
284 typedef Set<int, boost::hash<int>, std::equal_to<int>, std_allocator_type>
285 std_alloc_unordered_set;
286
287 // test allocators with a fancy pointer as their `::pointer` type
288 //
289 typedef Set<int, boost::hash<int>, std::equal_to<int>,
290 allocator1<value_type> >
291 fancy1_unordered_set;
292 typedef Set<int, boost::hash<int>, std::equal_to<int>,
293 allocator2<value_type> >
294 fancy2_unordered_set;
295
296 scary_test<alloc1_unordered_set, std_alloc_unordered_set>();
297 scary_test<hash1_unordered_set, hash2_unordered_set>();
298 scary_test<equal1_unordered_set, equal2_unordered_set>();
299 scary_test<fancy1_unordered_set, fancy2_unordered_set>();
300}
301
302UNORDERED_AUTO_TEST (scary_tests) {
303#ifdef BOOST_UNORDERED_FOA_TESTS
304 map_scary_test<boost::unordered_flat_map>();
305 map_scary_test<boost::unordered_node_map>();
306
307 set_scary_test<boost::unordered_flat_set>();
308 set_scary_test<boost::unordered_node_set>();
309#else
310 map_scary_test<boost::unordered_map>();
311 map_scary_test<boost::unordered_multimap>();
312
313 set_scary_test<boost::unordered_set>();
314 set_scary_test<boost::unordered_multiset>();
315#endif
316}
317
318RUN_TESTS()
319

source code of boost/libs/unordered/test/unordered/scary_tests.cpp