test_instance_tracker.h 8.7 KB

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