1
2// Copyright 2006-2009 Daniel James.
3// Copyright 2022 Christian Mazakas
4// Copyright 2023 Joaquin M Lopez Munoz
5// Distributed under the Boost Software License, Version 1.0. (See accompanying
6// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
7
8#if !defined(BOOST_UNORDERED_TEST_OBJECTS_HEADER)
9#define BOOST_UNORDERED_TEST_OBJECTS_HEADER
10
11#include "../helpers/count.hpp"
12#include "../helpers/fwd.hpp"
13#include "../helpers/memory.hpp"
14#include <boost/config.hpp>
15#include <boost/core/serialization.hpp>
16#include <boost/limits.hpp>
17#include <cstddef>
18
19template <class T> struct allocator1;
20template <class T> struct allocator2;
21
22namespace test {
23 // Note that the default hash function will work for any equal_to (but not
24 // very well).
25 class object;
26 class movable;
27 class implicitly_convertible;
28 class hash;
29 class less;
30 class equal_to;
31 template <class T> class allocator1;
32 template <class T> class allocator2;
33 object generate(object const*, random_generator);
34 movable generate(movable const*, random_generator);
35 implicitly_convertible generate(
36 implicitly_convertible const*, random_generator);
37
38 inline void ignore_variable(void const*) {}
39
40 class object : private counted_object
41 {
42 friend class hash;
43 friend class equal_to;
44 friend class less;
45 int tag1_, tag2_;
46
47 public:
48 explicit object(int t1 = 0, int t2 = 0) : tag1_(t1), tag2_(t2) {}
49
50 ~object()
51 {
52 tag1_ = -1;
53 tag2_ = -1;
54 }
55
56 friend bool operator==(object const& x1, object const& x2)
57 {
58 return x1.tag1_ == x2.tag1_ && x1.tag2_ == x2.tag2_;
59 }
60
61 friend bool operator!=(object const& x1, object const& x2)
62 {
63 return x1.tag1_ != x2.tag1_ || x1.tag2_ != x2.tag2_;
64 }
65
66 friend bool operator<(object const& x1, object const& x2)
67 {
68 return x1.tag1_ < x2.tag1_ ||
69 (x1.tag1_ == x2.tag1_ && x1.tag2_ < x2.tag2_);
70 }
71
72 friend object generate(object const*, random_generator g)
73 {
74 int* x = 0;
75 return object(generate(x, g), generate(x, g));
76 }
77
78 friend std::ostream& operator<<(std::ostream& out, object const& o)
79 {
80 return out << "(" << o.tag1_ << "," << o.tag2_ << ")";
81 }
82
83
84 template<typename Archive>
85 void serialize(Archive& ar,unsigned int)
86 {
87 ar & boost::core::make_nvp(n: "tag1", v&: tag1_);
88 ar & boost::core::make_nvp(n: "tag2", v&: tag2_);
89 }
90 };
91
92 class movable : private counted_object
93 {
94 friend class hash;
95 friend class equal_to;
96 friend class less;
97 int tag1_, tag2_;
98
99 public:
100 explicit movable(int t1 = 0, int t2 = 0) : tag1_(t1), tag2_(t2) {}
101
102 movable(movable const& x)
103 : counted_object(x), tag1_(x.tag1_), tag2_(x.tag2_)
104 {
105 BOOST_TEST(x.tag1_ != -1);
106 }
107
108 movable(movable&& x)
109 : counted_object(x), tag1_(x.tag1_), tag2_(x.tag2_)
110 {
111 BOOST_TEST(x.tag1_ != -1);
112 x.tag1_ = -1;
113 x.tag2_ = -1;
114 }
115
116 movable& operator=(movable const& x) // Copy assignment
117 {
118 BOOST_TEST(x.tag1_ != -1);
119 tag1_ = x.tag1_;
120 tag2_ = x.tag2_;
121 return *this;
122 }
123
124 movable& operator=(movable&& x) // Move assignment
125 {
126 BOOST_TEST(x.tag1_ != -1);
127 tag1_ = x.tag1_;
128 tag2_ = x.tag2_;
129 x.tag1_ = -1;
130 x.tag2_ = -1;
131 return *this;
132 }
133
134 ~movable()
135 {
136 tag1_ = -1;
137 tag2_ = -1;
138 }
139
140 friend bool operator==(movable const& x1, movable const& x2)
141 {
142 BOOST_TEST(x1.tag1_ != -1 && x2.tag1_ != -1);
143 return x1.tag1_ == x2.tag1_ && x1.tag2_ == x2.tag2_;
144 }
145
146 friend bool operator!=(movable const& x1, movable const& x2)
147 {
148 BOOST_TEST(x1.tag1_ != -1 && x2.tag1_ != -1);
149 return x1.tag1_ != x2.tag1_ || x1.tag2_ != x2.tag2_;
150 }
151
152 friend bool operator<(movable const& x1, movable const& x2)
153 {
154 BOOST_TEST(x1.tag1_ != -1 && x2.tag1_ != -1);
155 return x1.tag1_ < x2.tag1_ ||
156 (x1.tag1_ == x2.tag1_ && x1.tag2_ < x2.tag2_);
157 }
158
159 friend movable generate(movable const*, random_generator g)
160 {
161 int* x = 0;
162 return movable(generate(x, g), generate(x, g));
163 }
164
165 friend std::ostream& operator<<(std::ostream& out, movable const& o)
166 {
167 return out << "(" << o.tag1_ << "," << o.tag2_ << ")";
168 }
169 };
170
171 class implicitly_convertible : private counted_object
172 {
173 int tag1_, tag2_;
174
175 public:
176 explicit implicitly_convertible(int t1 = 0, int t2 = 0)
177 : tag1_(t1), tag2_(t2)
178 {
179 }
180
181 operator object() const { return object(tag1_, tag2_); }
182
183 operator movable() const { return movable(tag1_, tag2_); }
184
185 friend implicitly_convertible generate(
186 implicitly_convertible const*, random_generator g)
187 {
188 int* x = 0;
189 return implicitly_convertible(generate(x, g), generate(x, g));
190 }
191
192 friend std::ostream& operator<<(
193 std::ostream& out, implicitly_convertible const& o)
194 {
195 return out << "(" << o.tag1_ << "," << o.tag2_ << ")";
196 }
197 };
198
199 // Note: This is a deliberately bad hash function.
200 class hash BOOST_FINAL
201 {
202 int type_;
203
204 public:
205 hash() : type_(0) {}
206
207 explicit hash(int t) : type_(t) {}
208
209 std::size_t operator()(object const& x) const
210 {
211 unsigned result;
212 switch (type_) {
213 case 1:
214 result = static_cast<unsigned>(x.tag1_);
215 break;
216 case 2:
217 result = static_cast<unsigned>(x.tag2_);
218 break;
219 default:
220 result =
221 static_cast<unsigned>(x.tag1_) + static_cast<unsigned>(x.tag2_);
222 }
223 return result;
224 }
225
226 std::size_t operator()(movable const& x) const
227 {
228 unsigned result;
229 switch (type_) {
230 case 1:
231 result = static_cast<unsigned>(x.tag1_);
232 break;
233 case 2:
234 result = static_cast<unsigned>(x.tag2_);
235 break;
236 default:
237 result =
238 static_cast<unsigned>(x.tag1_) + static_cast<unsigned>(x.tag2_);
239 }
240 return result;
241 }
242
243 std::size_t operator()(int x) const
244 {
245 unsigned result;
246 switch (type_) {
247 case 1:
248 result = static_cast<unsigned>(x);
249 break;
250 case 2:
251 result = static_cast<unsigned>(x) * 7;
252 break;
253 default:
254 result = static_cast<unsigned>(x) * 256;
255 }
256 return result;
257 }
258
259 friend bool operator==(hash const& x1, hash const& x2)
260 {
261 return x1.type_ == x2.type_;
262 }
263
264 friend bool operator!=(hash const& x1, hash const& x2)
265 {
266 return x1.type_ != x2.type_;
267 }
268 };
269
270 std::size_t hash_value(test::object const& x) { return hash()(x); }
271
272 std::size_t hash_value(test::movable const& x) { return hash()(x); }
273
274 class less
275 {
276 int type_;
277
278 public:
279 explicit less(int t = 0) : type_(t) {}
280
281 bool operator()(object const& x1, object const& x2) const
282 {
283 switch (type_) {
284 case 1:
285 return x1.tag1_ < x2.tag1_;
286 case 2:
287 return x1.tag2_ < x2.tag2_;
288 default:
289 return x1 < x2;
290 }
291 }
292
293 bool operator()(movable const& x1, movable const& x2) const
294 {
295 switch (type_) {
296 case 1:
297 return x1.tag1_ < x2.tag1_;
298 case 2:
299 return x1.tag2_ < x2.tag2_;
300 default:
301 return x1 < x2;
302 }
303 }
304
305 bool operator()(int x1, int x2) const { return x1 < x2; }
306
307 friend bool operator==(less const& x1, less const& x2)
308 {
309 return x1.type_ == x2.type_;
310 }
311 };
312
313 class equal_to BOOST_FINAL
314 {
315 int type_;
316
317 public:
318 equal_to() : type_(0) {}
319
320 explicit equal_to(int t) : type_(t) {}
321
322 bool operator()(object const& x1, object const& x2) const
323 {
324 switch (type_) {
325 case 1:
326 return x1.tag1_ == x2.tag1_;
327 case 2:
328 return x1.tag2_ == x2.tag2_;
329 default:
330 return x1 == x2;
331 }
332 }
333
334 bool operator()(movable const& x1, movable const& x2) const
335 {
336 switch (type_) {
337 case 1:
338 return x1.tag1_ == x2.tag1_;
339 case 2:
340 return x1.tag2_ == x2.tag2_;
341 default:
342 return x1 == x2;
343 }
344 }
345
346 bool operator()(int x1, int x2) const { return x1 == x2; }
347
348 friend bool operator==(equal_to const& x1, equal_to const& x2)
349 {
350 return x1.type_ == x2.type_;
351 }
352
353 friend bool operator!=(equal_to const& x1, equal_to const& x2)
354 {
355 return x1.type_ != x2.type_;
356 }
357
358 friend less create_compare(equal_to x) { return less(x.type_); }
359 };
360
361 // allocator1 only has the old fashioned 'construct' method and has
362 // a few less typedefs. allocator2 uses a custom pointer class.
363
364 template <class T> class allocator1
365 {
366 public:
367 int tag_;
368
369 typedef T value_type;
370
371 template <class U> struct rebind
372 {
373 typedef allocator1<U> other;
374 };
375
376 allocator1() : tag_(0) { detail::tracker.allocator_ref(); }
377
378 explicit allocator1(int t) : tag_(t) { detail::tracker.allocator_ref(); }
379
380 template <class Y> allocator1(allocator1<Y> const& x) : tag_(x.tag_)
381 {
382 detail::tracker.allocator_ref();
383 }
384
385 allocator1(allocator1 const& x) : tag_(x.tag_)
386 {
387 detail::tracker.allocator_ref();
388 }
389
390 ~allocator1() { detail::tracker.allocator_unref(); }
391
392 T* allocate(std::size_t n)
393 {
394 T* ptr(static_cast<T*>(::operator new(n * sizeof(T))));
395 detail::tracker.track_allocate(ptr: (void*)ptr, n, size: sizeof(T), tag: tag_);
396 return ptr;
397 }
398
399 T* allocate(std::size_t n, void const*)
400 {
401 T* ptr(static_cast<T*>(::operator new(n * sizeof(T))));
402 detail::tracker.track_allocate(ptr: (void*)ptr, n, size: sizeof(T), tag: tag_);
403 return ptr;
404 }
405
406 void deallocate(T* p, std::size_t n)
407 {
408 detail::tracker.track_deallocate(ptr: (void*)p, n, size: sizeof(T), tag: tag_);
409 ::operator delete((void*)p);
410 }
411
412 template <typename U, typename... Args> void construct(U* p, Args&&... args)
413 {
414 detail::tracker.track_construct((void*)p, sizeof(U), tag_);
415 new (p) U(std::forward<Args>(args)...);
416 }
417
418 template <typename U> void destroy(U* p)
419 {
420 detail::tracker.track_destroy((void*)p, sizeof(U), tag_);
421 p->~U();
422
423 // Work around MSVC buggy unused parameter warning.
424 ignore_variable(&p);
425 }
426
427 bool operator==(allocator1 const& x) const { return tag_ == x.tag_; }
428
429 bool operator!=(allocator1 const& x) const { return tag_ != x.tag_; }
430
431 enum
432 {
433 is_select_on_copy = false,
434 is_propagate_on_swap = false,
435 is_propagate_on_assign = false,
436 is_propagate_on_move = false
437 };
438 };
439
440 template <class T> class ptr;
441 template <class T> class const_ptr;
442
443 struct void_ptr
444 {
445#if !defined(BOOST_NO_MEMBER_TEMPLATE_FRIENDS)
446 template <typename T> friend class ptr;
447
448 private:
449#endif
450
451 void* ptr_;
452
453 public:
454 void_ptr() : ptr_(0) {}
455
456 template <typename T> explicit void_ptr(ptr<T> const& x) : ptr_(x.ptr_) {}
457
458 // I'm not using the safe bool idiom because the containers should be
459 // able to cope with bool conversions.
460 operator bool() const { return !!ptr_; }
461
462 bool operator==(void_ptr const& x) const { return ptr_ == x.ptr_; }
463 bool operator!=(void_ptr const& x) const { return ptr_ != x.ptr_; }
464 };
465
466 class void_const_ptr
467 {
468#if !defined(BOOST_NO_MEMBER_TEMPLATE_FRIENDS)
469 template <typename T> friend class const_ptr;
470
471 private:
472#endif
473
474 void* ptr_;
475
476 public:
477 void_const_ptr() : ptr_(0) {}
478
479 template <typename T>
480 explicit void_const_ptr(const_ptr<T> const& x) : ptr_(x.ptr_)
481 {
482 }
483
484 // I'm not using the safe bool idiom because the containers should be
485 // able to cope with bool conversions.
486 operator bool() const { return !!ptr_; }
487
488 bool operator==(void_const_ptr const& x) const { return ptr_ == x.ptr_; }
489 bool operator!=(void_const_ptr const& x) const { return ptr_ != x.ptr_; }
490 };
491
492 template <class T> class ptr
493 {
494 friend struct ::allocator1<T>;
495 friend struct ::allocator2<T>;
496 friend class allocator2<T>;
497 friend class const_ptr<T>;
498 friend struct void_ptr;
499
500 T* ptr_;
501 ptr(T* x) : ptr_(x) {}
502
503 public:
504 ptr() : ptr_(0) {}
505 ptr(std::nullptr_t) : ptr_(nullptr) {}
506 explicit ptr(void_ptr const& x) : ptr_((T*)x.ptr_) {}
507
508 T& operator*() const { return *ptr_; }
509 T* operator->() const { return ptr_; }
510 ptr& operator++()
511 {
512 ++ptr_;
513 return *this;
514 }
515 ptr operator++(int)
516 {
517 ptr tmp(*this);
518 ++ptr_;
519 return tmp;
520 }
521
522 ptr operator+(std::ptrdiff_t s) const { return ptr<T>(ptr_ + s); }
523 friend ptr operator+(std::ptrdiff_t s, ptr p) { return ptr<T>(s + p.ptr_); }
524
525 std::ptrdiff_t operator-(ptr p) const { return ptr_ - p.ptr_; }
526 ptr operator-(std::ptrdiff_t s) const { return ptr(ptr_ - s); }
527
528 ptr& operator+=(std::ptrdiff_t s) { ptr_ += s; return *this; }
529 ptr& operator-=(std::ptrdiff_t s) { ptr_ -= s; return *this; }
530
531 T& operator[](std::ptrdiff_t s) const { return ptr_[s]; }
532 bool operator!() const { return !ptr_; }
533
534 static ptr pointer_to(T& p) {
535 return ptr(&p);
536 }
537
538 // I'm not using the safe bool idiom because the containers should be
539 // able to cope with bool conversions.
540 operator bool() const { return !!ptr_; }
541
542 bool operator==(ptr const& x) const { return ptr_ == x.ptr_; }
543 bool operator!=(ptr const& x) const { return ptr_ != x.ptr_; }
544 bool operator<(ptr const& x) const { return ptr_ < x.ptr_; }
545 bool operator>(ptr const& x) const { return ptr_ > x.ptr_; }
546 bool operator<=(ptr const& x) const { return ptr_ <= x.ptr_; }
547 bool operator>=(ptr const& x) const { return ptr_ >= x.ptr_; }
548 };
549
550 template <class T> class const_ptr
551 {
552 friend class allocator2<T>;
553 friend struct const_void_ptr;
554
555 T const* ptr_;
556
557 const_ptr(T const* ptr) : ptr_(ptr) {}
558
559 public:
560 const_ptr() : ptr_(0) {}
561 const_ptr(ptr<T> const& x) : ptr_(x.ptr_) {}
562 explicit const_ptr(void_const_ptr const& x) : ptr_((T const*)x.ptr_) {}
563
564 T const& operator*() const { return *ptr_; }
565 T const* operator->() const { return ptr_; }
566 const_ptr& operator++()
567 {
568 ++ptr_;
569 return *this;
570 }
571 const_ptr operator++(int)
572 {
573 const_ptr tmp(*this);
574 ++ptr_;
575 return tmp;
576 }
577 const_ptr operator+(std::ptrdiff_t s) const { return const_ptr(ptr_ + s); }
578 friend const_ptr operator+(std::ptrdiff_t s, const_ptr p)
579 {
580 return ptr<T>(s + p.ptr_);
581 }
582 T const& operator[](int s) const { return ptr_[s]; }
583 bool operator!() const { return !ptr_; }
584 operator bool() const { return !!ptr_; }
585
586 bool operator==(const_ptr const& x) const { return ptr_ == x.ptr_; }
587 bool operator!=(const_ptr const& x) const { return ptr_ != x.ptr_; }
588 bool operator<(const_ptr const& x) const { return ptr_ < x.ptr_; }
589 bool operator>(const_ptr const& x) const { return ptr_ > x.ptr_; }
590 bool operator<=(const_ptr const& x) const { return ptr_ <= x.ptr_; }
591 bool operator>=(const_ptr const& x) const { return ptr_ >= x.ptr_; }
592 };
593
594 template <class T> class allocator2
595 {
596#ifdef BOOST_NO_MEMBER_TEMPLATE_FRIENDS
597 public:
598#else
599 template <class> friend class allocator2;
600#endif
601 int tag_;
602
603 public:
604 typedef std::size_t size_type;
605 typedef std::ptrdiff_t difference_type;
606 typedef void_ptr void_pointer;
607 typedef void_const_ptr const_void_pointer;
608 typedef ptr<T> pointer;
609 typedef const_ptr<T> const_pointer;
610 typedef T& reference;
611 typedef T const& const_reference;
612 typedef T value_type;
613
614 template <class U> struct rebind
615 {
616 typedef allocator2<U> other;
617 };
618
619 allocator2() : tag_(0) { detail::tracker.allocator_ref(); }
620
621 explicit allocator2(int t) : tag_(t) { detail::tracker.allocator_ref(); }
622
623 template <class Y> allocator2(allocator2<Y> const& x) : tag_(x.tag_)
624 {
625 detail::tracker.allocator_ref();
626 }
627
628 allocator2(allocator2 const& x) : tag_(x.tag_)
629 {
630 detail::tracker.allocator_ref();
631 }
632
633 ~allocator2() { detail::tracker.allocator_unref(); }
634
635 pointer address(reference r) { return pointer(&r); }
636
637 const_pointer address(const_reference r) { return const_pointer(&r); }
638
639 pointer allocate(size_type n)
640 {
641 pointer p(static_cast<T*>(::operator new(n * sizeof(T))));
642 detail::tracker.track_allocate(ptr: (void*)p.ptr_, n, size: sizeof(T), tag: tag_);
643 return p;
644 }
645
646 pointer allocate(size_type n, void const*)
647 {
648 pointer ptr(static_cast<T*>(::operator new(n * sizeof(T))));
649 detail::tracker.track_allocate(ptr: (void*)ptr, n, size: sizeof(T), tag: tag_);
650 return ptr;
651 }
652
653 void deallocate(pointer p, size_type n)
654 {
655 detail::tracker.track_deallocate(ptr: (void*)p.ptr_, n, size: sizeof(T), tag: tag_);
656 ::operator delete((void*)p.ptr_);
657 }
658
659 template <class U, class... Args>
660 void construct(U* p, Args&&... args)
661 {
662 detail::tracker.track_construct((void*)p, sizeof(U), tag_);
663 new (p) U(std::forward<Args>(args)...);
664 }
665
666 template <class U> void destroy(U* p)
667 {
668 detail::tracker.track_destroy((void*)p, sizeof(U), tag_);
669 p->~U();
670 }
671
672 size_type max_size() const
673 {
674 return (std::numeric_limits<size_type>::max)();
675 }
676
677 bool operator==(allocator2 const& x) const { return tag_ == x.tag_; }
678
679 bool operator!=(allocator2 const& x) const { return tag_ != x.tag_; }
680
681 enum
682 {
683 is_select_on_copy = false,
684 is_propagate_on_swap = false,
685 is_propagate_on_assign = false,
686 is_propagate_on_move = false
687 };
688 };
689
690 template <class T>
691 bool equivalent_impl(
692 allocator1<T> const& x, allocator1<T> const& y, test::derived_type)
693 {
694 return x == y;
695 }
696
697 template <class T>
698 bool equivalent_impl(
699 allocator2<T> const& x, allocator2<T> const& y, test::derived_type)
700 {
701 return x == y;
702 }
703}
704
705namespace boost {
706 template <> struct pointer_traits< ::test::void_ptr>
707 {
708 template <class U> struct rebind_to
709 {
710 typedef ::test::ptr<U> type;
711 };
712
713 template<class U>
714 using rebind=typename rebind_to<U>::type;
715 };
716} // namespace boost
717
718#endif
719

source code of boost/libs/unordered/test/objects/test.hpp