Move CountingAllocator into test_allocator.h and add some other allocators that can be shared between different container tests.

PiperOrigin-RevId: 565693736
Change-Id: I59af987e30da03a805ce59ff0fb7eeae3fc08293
diff --git a/CMake/AbseilDll.cmake b/CMake/AbseilDll.cmake
index cbd79d5..f29787b 100644
--- a/CMake/AbseilDll.cmake
+++ b/CMake/AbseilDll.cmake
@@ -75,7 +75,6 @@
   "container/internal/common_policy_traits.h"
   "container/internal/compressed_tuple.h"
   "container/internal/container_memory.h"
-  "container/internal/counting_allocator.h"
   "container/internal/hash_function_defaults.h"
   "container/internal/hash_policy_traits.h"
   "container/internal/hashtable_debug.h"
diff --git a/absl/container/BUILD.bazel b/absl/container/BUILD.bazel
index 5131837..5be58b1 100644
--- a/absl/container/BUILD.bazel
+++ b/absl/container/BUILD.bazel
@@ -73,8 +73,8 @@
     copts = ABSL_TEST_COPTS,
     linkopts = ABSL_DEFAULT_LINKOPTS,
     deps = [
-        ":counting_allocator",
         ":fixed_array",
+        ":test_allocator",
         "//absl/base:config",
         "//absl/base:exception_testing",
         "//absl/hash:hash_testing",
@@ -139,9 +139,9 @@
 )
 
 cc_library(
-    name = "counting_allocator",
+    name = "test_allocator",
     testonly = 1,
-    hdrs = ["internal/counting_allocator.h"],
+    hdrs = ["internal/test_allocator.h"],
     copts = ABSL_DEFAULT_COPTS,
     linkopts = ABSL_DEFAULT_LINKOPTS,
     visibility = ["//visibility:private"],
@@ -154,8 +154,8 @@
     copts = ABSL_TEST_COPTS,
     linkopts = ABSL_DEFAULT_LINKOPTS,
     deps = [
-        ":counting_allocator",
         ":inlined_vector",
+        ":test_allocator",
         ":test_instance_tracker",
         "//absl/base:config",
         "//absl/base:core_headers",
@@ -656,6 +656,7 @@
         ":hash_policy_testing",
         ":hashtable_debug",
         ":raw_hash_set",
+        ":test_allocator",
         "//absl/base",
         "//absl/base:config",
         "//absl/base:core_headers",
@@ -993,7 +994,7 @@
     deps = [
         ":btree",
         ":btree_test_common",
-        ":counting_allocator",
+        ":test_allocator",
         ":test_instance_tracker",
         "//absl/algorithm:container",
         "//absl/base:core_headers",
diff --git a/absl/container/CMakeLists.txt b/absl/container/CMakeLists.txt
index f5ef0dd..bfe0634 100644
--- a/absl/container/CMakeLists.txt
+++ b/absl/container/CMakeLists.txt
@@ -77,13 +77,13 @@
     absl::btree_test_common
     absl::compare
     absl::core_headers
-    absl::counting_allocator
     absl::flags
     absl::hash_testing
     absl::optional
     absl::random_random
     absl::raw_logging_internal
     absl::strings
+    absl::test_allocator
     absl::test_instance_tracker
     GTest::gmock_main
 )
@@ -145,11 +145,11 @@
     ${ABSL_TEST_COPTS}
   DEPS
     absl::fixed_array
-    absl::counting_allocator
     absl::config
     absl::exception_testing
     absl::hash_testing
     absl::memory
+    absl::test_allocator
     GTest::gmock_main
 )
 
@@ -204,9 +204,9 @@
 # Internal-only target, do not depend on directly.
 absl_cc_library(
   NAME
-    counting_allocator
+    test_allocator
   HDRS
-    "internal/counting_allocator.h"
+    "internal/test_allocator.h"
   COPTS
     ${ABSL_DEFAULT_COPTS}
   DEPS
@@ -224,12 +224,12 @@
     absl::check
     absl::config
     absl::core_headers
-    absl::counting_allocator
     absl::exception_testing
     absl::hash_testing
     absl::inlined_vector
     absl::memory
     absl::strings
+    absl::test_allocator
     absl::test_instance_tracker
     GTest::gmock_main
 )
@@ -747,6 +747,7 @@
     absl::prefetch
     absl::raw_hash_set
     absl::strings
+    absl::test_allocator
     GTest::gmock_main
 )
 
diff --git a/absl/container/btree_test.cc b/absl/container/btree_test.cc
index a204c6d..3e239c5 100644
--- a/absl/container/btree_test.cc
+++ b/absl/container/btree_test.cc
@@ -37,7 +37,7 @@
 #include "absl/base/macros.h"
 #include "absl/container/btree_map.h"
 #include "absl/container/btree_set.h"
-#include "absl/container/internal/counting_allocator.h"
+#include "absl/container/internal/test_allocator.h"
 #include "absl/container/internal/test_instance_tracker.h"
 #include "absl/flags/flag.h"
 #include "absl/hash/hash_testing.h"
@@ -667,25 +667,10 @@
   DoTest("identical: ", &container, identical_values);
 }
 
-template <typename T>
-struct PropagatingCountingAlloc : public CountingAllocator<T> {
-  using propagate_on_container_copy_assignment = std::true_type;
-  using propagate_on_container_move_assignment = std::true_type;
-  using propagate_on_container_swap = std::true_type;
-
-  using Base = CountingAllocator<T>;
-  using Base::Base;
-
-  template <typename U>
-  explicit PropagatingCountingAlloc(const PropagatingCountingAlloc<U> &other)
-      : Base(other.bytes_used_) {}
-
-  template <typename U>
-  struct rebind {
-    using other = PropagatingCountingAlloc<U>;
-  };
-};
-
+// TODO(ezb): get rid of BtreeAllocatorTest and replace with test cases using
+// specific propagating allocs (e.g. CopyAssignPropagatingCountingAlloc) and
+// also a test for MinimumAlignmentAlloc. Motivation is better test coverage and
+// faster compilation time.
 template <typename T>
 void BtreeAllocatorTest() {
   using value_type = typename T::value_type;
diff --git a/absl/container/fixed_array_test.cc b/absl/container/fixed_array_test.cc
index 9dbf2a8..2421b5f 100644
--- a/absl/container/fixed_array_test.cc
+++ b/absl/container/fixed_array_test.cc
@@ -30,7 +30,7 @@
 #include "absl/base/config.h"
 #include "absl/base/internal/exception_testing.h"
 #include "absl/base/options.h"
-#include "absl/container/internal/counting_allocator.h"
+#include "absl/container/internal/test_allocator.h"
 #include "absl/hash/hash_testing.h"
 #include "absl/memory/memory.h"
 
diff --git a/absl/container/inlined_vector_test.cc b/absl/container/inlined_vector_test.cc
index b9a79f5..241389a 100644
--- a/absl/container/inlined_vector_test.cc
+++ b/absl/container/inlined_vector_test.cc
@@ -33,7 +33,7 @@
 #include "absl/base/internal/exception_testing.h"
 #include "absl/base/macros.h"
 #include "absl/base/options.h"
-#include "absl/container/internal/counting_allocator.h"
+#include "absl/container/internal/test_allocator.h"
 #include "absl/container/internal/test_instance_tracker.h"
 #include "absl/hash/hash_testing.h"
 #include "absl/log/check.h"
diff --git a/absl/container/internal/counting_allocator.h b/absl/container/internal/counting_allocator.h
deleted file mode 100644
index 66068a5..0000000
--- a/absl/container/internal/counting_allocator.h
+++ /dev/null
@@ -1,122 +0,0 @@
-// Copyright 2018 The Abseil Authors.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//      https://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-#ifndef ABSL_CONTAINER_INTERNAL_COUNTING_ALLOCATOR_H_
-#define ABSL_CONTAINER_INTERNAL_COUNTING_ALLOCATOR_H_
-
-#include <cstdint>
-#include <memory>
-
-#include "absl/base/config.h"
-
-namespace absl {
-ABSL_NAMESPACE_BEGIN
-namespace container_internal {
-
-// This is a stateful allocator, but the state lives outside of the
-// allocator (in whatever test is using the allocator). This is odd
-// but helps in tests where the allocator is propagated into nested
-// containers - that chain of allocators uses the same state and is
-// thus easier to query for aggregate allocation information.
-template <typename T>
-class CountingAllocator {
- public:
-  using Allocator = std::allocator<T>;
-  using AllocatorTraits = std::allocator_traits<Allocator>;
-  using value_type = typename AllocatorTraits::value_type;
-  using pointer = typename AllocatorTraits::pointer;
-  using const_pointer = typename AllocatorTraits::const_pointer;
-  using size_type = typename AllocatorTraits::size_type;
-  using difference_type = typename AllocatorTraits::difference_type;
-
-  CountingAllocator() = default;
-  explicit CountingAllocator(int64_t* bytes_used) : bytes_used_(bytes_used) {}
-  CountingAllocator(int64_t* bytes_used, int64_t* instance_count)
-      : bytes_used_(bytes_used), instance_count_(instance_count) {}
-
-  template <typename U>
-  CountingAllocator(const CountingAllocator<U>& x)
-      : bytes_used_(x.bytes_used_), instance_count_(x.instance_count_) {}
-
-  pointer allocate(
-      size_type n,
-      typename AllocatorTraits::const_void_pointer hint = nullptr) {
-    Allocator allocator;
-    pointer ptr = AllocatorTraits::allocate(allocator, n, hint);
-    if (bytes_used_ != nullptr) {
-      *bytes_used_ += n * sizeof(T);
-    }
-    return ptr;
-  }
-
-  void deallocate(pointer p, size_type n) {
-    Allocator allocator;
-    AllocatorTraits::deallocate(allocator, p, n);
-    if (bytes_used_ != nullptr) {
-      *bytes_used_ -= n * sizeof(T);
-    }
-  }
-
-  template <typename U, typename... Args>
-  void construct(U* p, Args&&... args) {
-    Allocator allocator;
-    AllocatorTraits::construct(allocator, p, std::forward<Args>(args)...);
-    if (instance_count_ != nullptr) {
-      *instance_count_ += 1;
-    }
-  }
-
-  template <typename U>
-  void destroy(U* p) {
-    Allocator allocator;
-    // Ignore GCC warning bug.
-#if ABSL_INTERNAL_HAVE_MIN_GNUC_VERSION(12, 0)
-#pragma GCC diagnostic push
-#pragma GCC diagnostic ignored "-Wuse-after-free"
-#endif
-    AllocatorTraits::destroy(allocator, p);
-#if ABSL_INTERNAL_HAVE_MIN_GNUC_VERSION(12, 0)
-#pragma GCC diagnostic pop
-#endif
-    if (instance_count_ != nullptr) {
-      *instance_count_ -= 1;
-    }
-  }
-
-  template <typename U>
-  class rebind {
-   public:
-    using other = CountingAllocator<U>;
-  };
-
-  friend bool operator==(const CountingAllocator& a,
-                         const CountingAllocator& b) {
-    return a.bytes_used_ == b.bytes_used_ &&
-           a.instance_count_ == b.instance_count_;
-  }
-
-  friend bool operator!=(const CountingAllocator& a,
-                         const CountingAllocator& b) {
-    return !(a == b);
-  }
-
-  int64_t* bytes_used_ = nullptr;
-  int64_t* instance_count_ = nullptr;
-};
-
-}  // namespace container_internal
-ABSL_NAMESPACE_END
-}  // namespace absl
-
-#endif  // ABSL_CONTAINER_INTERNAL_COUNTING_ALLOCATOR_H_
diff --git a/absl/container/internal/raw_hash_set_test.cc b/absl/container/internal/raw_hash_set_test.cc
index 55c6f62..7588120 100644
--- a/absl/container/internal/raw_hash_set_test.cc
+++ b/absl/container/internal/raw_hash_set_test.cc
@@ -48,6 +48,7 @@
 #include "absl/container/internal/hash_function_defaults.h"
 #include "absl/container/internal/hash_policy_testing.h"
 #include "absl/container/internal/hashtable_debug.h"
+#include "absl/container/internal/test_allocator.h"
 #include "absl/log/log.h"
 #include "absl/strings/string_view.h"
 
@@ -441,34 +442,6 @@
   using Base::Base;
 };
 
-// Tries to allocate memory at the minimum alignment even when the default
-// allocator uses a higher alignment.
-template <typename T>
-struct MinimumAlignmentAlloc : std::allocator<T> {
-  MinimumAlignmentAlloc() = default;
-
-  template <typename U>
-  explicit MinimumAlignmentAlloc(const MinimumAlignmentAlloc<U>& /*other*/) {}
-
-  template <class U>
-  struct rebind {
-    using other = MinimumAlignmentAlloc<U>;
-  };
-
-  T* allocate(size_t n) {
-    T* ptr = std::allocator<T>::allocate(n + 1);
-    char* cptr = reinterpret_cast<char*>(ptr);
-    cptr += alignof(T);
-    return reinterpret_cast<T*>(cptr);
-  }
-
-  void deallocate(T* ptr, size_t n) {
-    char* cptr = reinterpret_cast<char*>(ptr);
-    cptr -= alignof(T);
-    std::allocator<T>::deallocate(reinterpret_cast<T*>(cptr), n + 1);
-  }
-};
-
 struct MinimumAlignmentUint8Table
     : raw_hash_set<Uint8Policy, container_internal::hash_default_hash<uint8_t>,
                    std::equal_to<uint8_t>, MinimumAlignmentAlloc<uint8_t>> {
diff --git a/absl/container/internal/test_allocator.h b/absl/container/internal/test_allocator.h
new file mode 100644
index 0000000..153da42
--- /dev/null
+++ b/absl/container/internal/test_allocator.h
@@ -0,0 +1,225 @@
+// Copyright 2018 The Abseil Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#ifndef ABSL_CONTAINER_INTERNAL_TEST_ALLOCATOR_H_
+#define ABSL_CONTAINER_INTERNAL_TEST_ALLOCATOR_H_
+
+#include <cstddef>
+#include <cstdint>
+#include <memory>
+#include <type_traits>
+
+#include "absl/base/config.h"
+
+namespace absl {
+ABSL_NAMESPACE_BEGIN
+namespace container_internal {
+
+// This is a stateful allocator, but the state lives outside of the
+// allocator (in whatever test is using the allocator). This is odd
+// but helps in tests where the allocator is propagated into nested
+// containers - that chain of allocators uses the same state and is
+// thus easier to query for aggregate allocation information.
+template <typename T>
+class CountingAllocator {
+ public:
+  using Allocator = std::allocator<T>;
+  using AllocatorTraits = std::allocator_traits<Allocator>;
+  using value_type = typename AllocatorTraits::value_type;
+  using pointer = typename AllocatorTraits::pointer;
+  using const_pointer = typename AllocatorTraits::const_pointer;
+  using size_type = typename AllocatorTraits::size_type;
+  using difference_type = typename AllocatorTraits::difference_type;
+
+  CountingAllocator() = default;
+  explicit CountingAllocator(int64_t* bytes_used) : bytes_used_(bytes_used) {}
+  CountingAllocator(int64_t* bytes_used, int64_t* instance_count)
+      : bytes_used_(bytes_used), instance_count_(instance_count) {}
+
+  template <typename U>
+  CountingAllocator(const CountingAllocator<U>& x)
+      : bytes_used_(x.bytes_used_), instance_count_(x.instance_count_) {}
+
+  pointer allocate(
+      size_type n,
+      typename AllocatorTraits::const_void_pointer hint = nullptr) {
+    Allocator allocator;
+    pointer ptr = AllocatorTraits::allocate(allocator, n, hint);
+    if (bytes_used_ != nullptr) {
+      *bytes_used_ += n * sizeof(T);
+    }
+    return ptr;
+  }
+
+  void deallocate(pointer p, size_type n) {
+    Allocator allocator;
+    AllocatorTraits::deallocate(allocator, p, n);
+    if (bytes_used_ != nullptr) {
+      *bytes_used_ -= n * sizeof(T);
+    }
+  }
+
+  template <typename U, typename... Args>
+  void construct(U* p, Args&&... args) {
+    Allocator allocator;
+    AllocatorTraits::construct(allocator, p, std::forward<Args>(args)...);
+    if (instance_count_ != nullptr) {
+      *instance_count_ += 1;
+    }
+  }
+
+  template <typename U>
+  void destroy(U* p) {
+    Allocator allocator;
+    // Ignore GCC warning bug.
+#if ABSL_INTERNAL_HAVE_MIN_GNUC_VERSION(12, 0)
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wuse-after-free"
+#endif
+    AllocatorTraits::destroy(allocator, p);
+#if ABSL_INTERNAL_HAVE_MIN_GNUC_VERSION(12, 0)
+#pragma GCC diagnostic pop
+#endif
+    if (instance_count_ != nullptr) {
+      *instance_count_ -= 1;
+    }
+  }
+
+  template <typename U>
+  class rebind {
+   public:
+    using other = CountingAllocator<U>;
+  };
+
+  friend bool operator==(const CountingAllocator& a,
+                         const CountingAllocator& b) {
+    return a.bytes_used_ == b.bytes_used_ &&
+           a.instance_count_ == b.instance_count_;
+  }
+
+  friend bool operator!=(const CountingAllocator& a,
+                         const CountingAllocator& b) {
+    return !(a == b);
+  }
+
+  int64_t* bytes_used_ = nullptr;
+  int64_t* instance_count_ = nullptr;
+};
+
+template <typename T>
+struct CopyAssignPropagatingCountingAlloc : public CountingAllocator<T> {
+  using propagate_on_container_copy_assignment = std::true_type;
+
+  using Base = CountingAllocator<T>;
+  using Base::Base;
+
+  template <typename U>
+  explicit CopyAssignPropagatingCountingAlloc(
+      const CopyAssignPropagatingCountingAlloc<U>& other)
+      : Base(other.bytes_used_, other.instance_count_) {}
+
+  template <typename U>
+  struct rebind {
+    using other = CopyAssignPropagatingCountingAlloc<U>;
+  };
+};
+
+template <typename T>
+struct MoveAssignPropagatingCountingAlloc : public CountingAllocator<T> {
+  using propagate_on_container_move_assignment = std::true_type;
+
+  using Base = CountingAllocator<T>;
+  using Base::Base;
+
+  template <typename U>
+  explicit MoveAssignPropagatingCountingAlloc(
+      const MoveAssignPropagatingCountingAlloc<U>& other)
+      : Base(other.bytes_used_, other.instance_count_) {}
+
+  template <typename U>
+  struct rebind {
+    using other = MoveAssignPropagatingCountingAlloc<U>;
+  };
+};
+
+template <typename T>
+struct SwapPropagatingCountingAlloc : public CountingAllocator<T> {
+  using propagate_on_container_swap = std::true_type;
+
+  using Base = CountingAllocator<T>;
+  using Base::Base;
+
+  template <typename U>
+  explicit SwapPropagatingCountingAlloc(
+      const SwapPropagatingCountingAlloc<U>& other)
+      : Base(other.bytes_used_, other.instance_count_) {}
+
+  template <typename U>
+  struct rebind {
+    using other = SwapPropagatingCountingAlloc<U>;
+  };
+};
+
+template <typename T>
+struct PropagatingCountingAlloc : public CountingAllocator<T> {
+  using propagate_on_container_copy_assignment = std::true_type;
+  using propagate_on_container_move_assignment = std::true_type;
+  using propagate_on_container_swap = std::true_type;
+
+  using Base = CountingAllocator<T>;
+  using Base::Base;
+
+  template <typename U>
+  explicit PropagatingCountingAlloc(const PropagatingCountingAlloc<U> &other)
+      : Base(other.bytes_used_, other.instance_count_) {}
+
+  template <typename U>
+  struct rebind {
+    using other = PropagatingCountingAlloc<U>;
+  };
+};
+
+// Tries to allocate memory at the minimum alignment even when the default
+// allocator uses a higher alignment.
+template <typename T>
+struct MinimumAlignmentAlloc : std::allocator<T> {
+  MinimumAlignmentAlloc() = default;
+
+  template <typename U>
+  explicit MinimumAlignmentAlloc(const MinimumAlignmentAlloc<U>& /*other*/) {}
+
+  template <class U>
+  struct rebind {
+    using other = MinimumAlignmentAlloc<U>;
+  };
+
+  T* allocate(size_t n) {
+    T* ptr = std::allocator<T>::allocate(n + 1);
+    char* cptr = reinterpret_cast<char*>(ptr);
+    cptr += alignof(T);
+    return reinterpret_cast<T*>(cptr);
+  }
+
+  void deallocate(T* ptr, size_t n) {
+    char* cptr = reinterpret_cast<char*>(ptr);
+    cptr -= alignof(T);
+    std::allocator<T>::deallocate(reinterpret_cast<T*>(cptr), n + 1);
+  }
+};
+
+}  // namespace container_internal
+ABSL_NAMESPACE_END
+}  // namespace absl
+
+#endif  // ABSL_CONTAINER_INTERNAL_TEST_ALLOCATOR_H_