1
2// Copyright 2008-2009 Daniel James.
3// Copyright 2024 Braden Ganetsky.
4// Distributed under the Boost Software License, Version 1.0. (See accompanying
5// file LICENSE_1_0.txt or move at http://www.boost.org/LICENSE_1_0.txt)
6
7#if !defined(BOOST_UNORDERED_TEST_HELPERS_COUNT_HEAD)
8#define BOOST_UNORDERED_TEST_HELPERS_COUNT_HEAD
9
10#include <boost/core/lightweight_test.hpp>
11#include <boost/container_hash/hash.hpp>
12
13namespace test {
14 struct object_count
15 {
16 int instances;
17 int constructions;
18
19 object_count() : instances(0), constructions(0) {}
20 void reset() { *this = object_count(); }
21
22 void construct()
23 {
24 ++instances;
25 ++constructions;
26 }
27
28 void destruct()
29 {
30 if (instances == 0) {
31 BOOST_ERROR("Unbalanced constructions.");
32 } else {
33 --instances;
34 }
35 }
36
37 bool operator==(object_count const& x) const
38 {
39 return instances == x.instances && constructions == x.constructions;
40 }
41
42 bool operator!=(object_count const& x) const { return !(*this == x); }
43
44 friend std::ostream& operator<<(std::ostream& out, object_count const& c)
45 {
46 out << "[instances: " << c.instances
47 << ", constructions: " << c.constructions << "]";
48 return out;
49 }
50 };
51
52 // This won't be a problem as I'm only using a single compile unit
53 // in each test (this is actually require by the minimal test
54 // framework).
55 //
56 // boostinspect:nounnamed
57 namespace {
58 object_count global_object_count;
59 }
60
61 struct counted_object
62 {
63 counted_object() { global_object_count.construct(); }
64 counted_object(counted_object const&) { global_object_count.construct(); }
65 ~counted_object() { global_object_count.destruct(); }
66 };
67
68 struct check_instances
69 {
70 int instances_;
71 int constructions_;
72
73 check_instances()
74 : instances_(global_object_count.instances),
75 constructions_(global_object_count.constructions)
76 {
77 }
78 ~check_instances()
79 {
80 BOOST_TEST(global_object_count.instances == instances_);
81 }
82
83 int instances() const { return global_object_count.instances - instances_; }
84 int constructions() const
85 {
86 return global_object_count.constructions - constructions_;
87 }
88 };
89
90 struct smf_count
91 {
92 int default_constructions = 0;
93 int copy_constructions = 0;
94 int move_constructions = 0;
95 int copy_assignments = 0;
96 int move_assignments = 0;
97 int destructions = 0;
98
99#if (BOOST_CXX_VERSION < 201402L) || (defined(_MSC_VER) && _MSC_VER < 1910)
100 smf_count() = default;
101
102 smf_count(int default_constructions_, int copy_constructions_,
103 int move_constructions_, int copy_assignments_, int move_assignments_,
104 int destructions_)
105 : default_constructions(default_constructions_),
106 copy_constructions(copy_constructions_),
107 move_constructions(move_constructions_),
108 copy_assignments(copy_assignments_),
109 move_assignments(move_assignments_), destructions(destructions_)
110 {
111 }
112#endif
113
114 void reset() { *this = smf_count(); }
115
116 void default_construct() { ++default_constructions; }
117 void copy_construct() { ++copy_constructions; }
118 void move_construct() { ++move_constructions; }
119 void copy_assign() { ++copy_assignments; }
120 void move_assign() { ++move_assignments; }
121 void destruct() { ++destructions; }
122
123 friend bool operator==(smf_count const& lhs, smf_count const& rhs)
124 {
125 return lhs.default_constructions == rhs.default_constructions &&
126 lhs.copy_constructions == rhs.copy_constructions &&
127 lhs.move_constructions == rhs.move_constructions &&
128 lhs.copy_assignments == rhs.copy_assignments &&
129 lhs.move_assignments == rhs.move_assignments &&
130 lhs.destructions == rhs.destructions;
131 }
132
133 friend std::ostream& operator<<(std::ostream& out, smf_count const& c)
134 {
135 out << "[default_constructions: " << c.default_constructions
136 << ", copy_constructions: " << c.copy_constructions
137 << ", move_constructions: " << c.move_constructions
138 << ", copy_assignments: " << c.copy_assignments
139 << ", move_assignments: " << c.move_assignments
140 << ", destructions: " << c.destructions << "]";
141 return out;
142 }
143 };
144
145 template <class Tag> class smf_counted_object
146 {
147 public:
148 static smf_count count;
149 static void reset_count() { count.reset(); }
150
151 smf_counted_object(int index) : smf_counted_object() { index_ = index; }
152
153 smf_counted_object() : index_(++running_index)
154 {
155 count.default_construct();
156 }
157 smf_counted_object(smf_counted_object const& rhs) : index_(rhs.index_)
158 {
159 count.copy_construct();
160 }
161 smf_counted_object(smf_counted_object&& rhs) noexcept : index_(rhs.index_)
162 {
163 count.move_construct();
164 }
165 smf_counted_object& operator=(smf_counted_object const& rhs)
166 {
167 count.copy_assign();
168 index_ = rhs.index_;
169 return *this;
170 }
171 smf_counted_object& operator=(smf_counted_object&& rhs) noexcept
172 {
173 count.move_assign();
174 index_ = rhs.index_;
175 return *this;
176 }
177 ~smf_counted_object() { count.destruct(); }
178
179 friend bool operator==(
180 smf_counted_object const& lhs, smf_counted_object const& rhs)
181 {
182 return lhs.index_ == rhs.index_;
183 }
184
185 friend std::size_t hash_value(smf_counted_object const& x)
186 {
187 return boost::hash<int>()(x.index_);
188 }
189
190 int index_;
191
192 private:
193 static int running_index;
194 };
195 template <class Tag> smf_count smf_counted_object<Tag>::count = {};
196 template <class Tag> int smf_counted_object<Tag>::running_index = 0;
197} // namespace test
198
199#endif
200

source code of boost/libs/unordered/test/helpers/count.hpp