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