blob: c4731dbe3d1d8b35361dcc4db1f5ccc19c1dfc93 [file] [log] [blame]
Austin Schuh36244a12019-09-21 17:52:38 -07001// Copyright 2017 The Abseil Authors.
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7// https://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15#ifndef ABSL_CONTAINER_INTERNAL_TEST_INSTANCE_TRACKER_H_
16#define ABSL_CONTAINER_INTERNAL_TEST_INSTANCE_TRACKER_H_
17
18#include <cstdlib>
19#include <ostream>
20
21#include "absl/types/compare.h"
22
23namespace absl {
24namespace test_internal {
25
26// A type that counts number of occurrences of the type, the live occurrences of
27// the type, as well as the number of copies, moves, swaps, and comparisons that
28// have occurred on the type. This is used as a base class for the copyable,
29// copyable+movable, and movable types below that are used in actual tests. Use
30// InstanceTracker in tests to track the number of instances.
31class BaseCountedInstance {
32 public:
33 explicit BaseCountedInstance(int x) : value_(x) {
34 ++num_instances_;
35 ++num_live_instances_;
36 }
37 BaseCountedInstance(const BaseCountedInstance& x)
38 : value_(x.value_), is_live_(x.is_live_) {
39 ++num_instances_;
40 if (is_live_) ++num_live_instances_;
41 ++num_copies_;
42 }
43 BaseCountedInstance(BaseCountedInstance&& x)
44 : value_(x.value_), is_live_(x.is_live_) {
45 x.is_live_ = false;
46 ++num_instances_;
47 ++num_moves_;
48 }
49 ~BaseCountedInstance() {
50 --num_instances_;
51 if (is_live_) --num_live_instances_;
52 }
53
54 BaseCountedInstance& operator=(const BaseCountedInstance& x) {
55 value_ = x.value_;
56 if (is_live_) --num_live_instances_;
57 is_live_ = x.is_live_;
58 if (is_live_) ++num_live_instances_;
59 ++num_copies_;
60 return *this;
61 }
62 BaseCountedInstance& operator=(BaseCountedInstance&& x) {
63 value_ = x.value_;
64 if (is_live_) --num_live_instances_;
65 is_live_ = x.is_live_;
66 x.is_live_ = false;
67 ++num_moves_;
68 return *this;
69 }
70
71 bool operator==(const BaseCountedInstance& x) const {
72 ++num_comparisons_;
73 return value_ == x.value_;
74 }
75
76 bool operator!=(const BaseCountedInstance& x) const {
77 ++num_comparisons_;
78 return value_ != x.value_;
79 }
80
81 bool operator<(const BaseCountedInstance& x) const {
82 ++num_comparisons_;
83 return value_ < x.value_;
84 }
85
86 bool operator>(const BaseCountedInstance& x) const {
87 ++num_comparisons_;
88 return value_ > x.value_;
89 }
90
91 bool operator<=(const BaseCountedInstance& x) const {
92 ++num_comparisons_;
93 return value_ <= x.value_;
94 }
95
96 bool operator>=(const BaseCountedInstance& x) const {
97 ++num_comparisons_;
98 return value_ >= x.value_;
99 }
100
101 absl::weak_ordering compare(const BaseCountedInstance& x) const {
102 ++num_comparisons_;
103 return value_ < x.value_
104 ? absl::weak_ordering::less
105 : value_ == x.value_ ? absl::weak_ordering::equivalent
106 : absl::weak_ordering::greater;
107 }
108
109 int value() const {
110 if (!is_live_) std::abort();
111 return value_;
112 }
113
114 friend std::ostream& operator<<(std::ostream& o,
115 const BaseCountedInstance& v) {
116 return o << "[value:" << v.value() << "]";
117 }
118
119 // Implementation of efficient swap() that counts swaps.
120 static void SwapImpl(
121 BaseCountedInstance& lhs, // NOLINT(runtime/references)
122 BaseCountedInstance& rhs) { // NOLINT(runtime/references)
123 using std::swap;
124 swap(lhs.value_, rhs.value_);
125 swap(lhs.is_live_, rhs.is_live_);
126 ++BaseCountedInstance::num_swaps_;
127 }
128
129 private:
130 friend class InstanceTracker;
131
132 int value_;
133
134 // Indicates if the value is live, ie it hasn't been moved away from.
135 bool is_live_ = true;
136
137 // Number of instances.
138 static int num_instances_;
139
140 // Number of live instances (those that have not been moved away from.)
141 static int num_live_instances_;
142
143 // Number of times that BaseCountedInstance objects were moved.
144 static int num_moves_;
145
146 // Number of times that BaseCountedInstance objects were copied.
147 static int num_copies_;
148
149 // Number of times that BaseCountedInstance objects were swapped.
150 static int num_swaps_;
151
152 // Number of times that BaseCountedInstance objects were compared.
153 static int num_comparisons_;
154};
155
156// Helper to track the BaseCountedInstance instance counters. Expects that the
157// number of instances and live_instances are the same when it is constructed
158// and when it is destructed.
159class InstanceTracker {
160 public:
161 InstanceTracker()
162 : start_instances_(BaseCountedInstance::num_instances_),
163 start_live_instances_(BaseCountedInstance::num_live_instances_) {
164 ResetCopiesMovesSwaps();
165 }
166 ~InstanceTracker() {
167 if (instances() != 0) std::abort();
168 if (live_instances() != 0) std::abort();
169 }
170
171 // Returns the number of BaseCountedInstance instances both containing valid
172 // values and those moved away from compared to when the InstanceTracker was
173 // constructed
174 int instances() const {
175 return BaseCountedInstance::num_instances_ - start_instances_;
176 }
177
178 // Returns the number of live BaseCountedInstance instances compared to when
179 // the InstanceTracker was constructed
180 int live_instances() const {
181 return BaseCountedInstance::num_live_instances_ - start_live_instances_;
182 }
183
184 // Returns the number of moves on BaseCountedInstance objects since
185 // construction or since the last call to ResetCopiesMovesSwaps().
186 int moves() const { return BaseCountedInstance::num_moves_ - start_moves_; }
187
188 // Returns the number of copies on BaseCountedInstance objects since
189 // construction or the last call to ResetCopiesMovesSwaps().
190 int copies() const {
191 return BaseCountedInstance::num_copies_ - start_copies_;
192 }
193
194 // Returns the number of swaps on BaseCountedInstance objects since
195 // construction or the last call to ResetCopiesMovesSwaps().
196 int swaps() const { return BaseCountedInstance::num_swaps_ - start_swaps_; }
197
198 // Returns the number of comparisons on BaseCountedInstance objects since
199 // construction or the last call to ResetCopiesMovesSwaps().
200 int comparisons() const {
201 return BaseCountedInstance::num_comparisons_ - start_comparisons_;
202 }
203
204 // Resets the base values for moves, copies, comparisons, and swaps to the
205 // current values, so that subsequent Get*() calls for moves, copies,
206 // comparisons, and swaps will compare to the situation at the point of this
207 // call.
208 void ResetCopiesMovesSwaps() {
209 start_moves_ = BaseCountedInstance::num_moves_;
210 start_copies_ = BaseCountedInstance::num_copies_;
211 start_swaps_ = BaseCountedInstance::num_swaps_;
212 start_comparisons_ = BaseCountedInstance::num_comparisons_;
213 }
214
215 private:
216 int start_instances_;
217 int start_live_instances_;
218 int start_moves_;
219 int start_copies_;
220 int start_swaps_;
221 int start_comparisons_;
222};
223
224// Copyable, not movable.
225class CopyableOnlyInstance : public BaseCountedInstance {
226 public:
227 explicit CopyableOnlyInstance(int x) : BaseCountedInstance(x) {}
228 CopyableOnlyInstance(const CopyableOnlyInstance& rhs) = default;
229 CopyableOnlyInstance& operator=(const CopyableOnlyInstance& rhs) = default;
230
231 friend void swap(CopyableOnlyInstance& lhs, CopyableOnlyInstance& rhs) {
232 BaseCountedInstance::SwapImpl(lhs, rhs);
233 }
234
235 static bool supports_move() { return false; }
236};
237
238// Copyable and movable.
239class CopyableMovableInstance : public BaseCountedInstance {
240 public:
241 explicit CopyableMovableInstance(int x) : BaseCountedInstance(x) {}
242 CopyableMovableInstance(const CopyableMovableInstance& rhs) = default;
243 CopyableMovableInstance(CopyableMovableInstance&& rhs) = default;
244 CopyableMovableInstance& operator=(const CopyableMovableInstance& rhs) =
245 default;
246 CopyableMovableInstance& operator=(CopyableMovableInstance&& rhs) = default;
247
248 friend void swap(CopyableMovableInstance& lhs, CopyableMovableInstance& rhs) {
249 BaseCountedInstance::SwapImpl(lhs, rhs);
250 }
251
252 static bool supports_move() { return true; }
253};
254
255// Only movable, not default-constructible.
256class MovableOnlyInstance : public BaseCountedInstance {
257 public:
258 explicit MovableOnlyInstance(int x) : BaseCountedInstance(x) {}
259 MovableOnlyInstance(MovableOnlyInstance&& other) = default;
260 MovableOnlyInstance& operator=(MovableOnlyInstance&& other) = default;
261
262 friend void swap(MovableOnlyInstance& lhs, MovableOnlyInstance& rhs) {
263 BaseCountedInstance::SwapImpl(lhs, rhs);
264 }
265
266 static bool supports_move() { return true; }
267};
268
269} // namespace test_internal
270} // namespace absl
271
272#endif // ABSL_CONTAINER_INTERNAL_TEST_INSTANCE_TRACKER_H_