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