[libc++] Make test_allocator constexpr-friendly for constexpr string/vector
authorNikolas Klauser <nikolasklauser@berlin.de>
Sun, 7 Nov 2021 15:11:24 +0000 (16:11 +0100)
committerMark de Wever <koraq@xs4all.nl>
Sun, 7 Nov 2021 15:15:28 +0000 (16:15 +0100)
Make test_allocator etc. constexpr-friendly so they can be used to test constexpr string and possibly constexpr vector

Reviewed By: Quuxplusone, #libc, ldionne

Differential Revision: https://reviews.llvm.org/D110994

25 files changed:
libcxx/test/std/containers/associative/map/map.cons/assign_initializer_list.pass.cpp
libcxx/test/std/containers/associative/set/set.cons/assign_initializer_list.pass.cpp
libcxx/test/std/containers/container.requirements/container.requirements.general/allocator_move.pass.cpp
libcxx/test/std/containers/sequences/deque/deque.modifiers/push_back_exception_safety.pass.cpp
libcxx/test/std/containers/sequences/deque/deque.modifiers/push_front_exception_safety.pass.cpp
libcxx/test/std/containers/sequences/vector.bool/move.pass.cpp
libcxx/test/std/containers/sequences/vector/vector.cons/move.pass.cpp
libcxx/test/std/re/re.results/re.results.const/move.pass.cpp
libcxx/test/std/strings/basic.string/string.capacity/capacity.pass.cpp
libcxx/test/std/strings/basic.string/string.cons/move_alloc.pass.cpp
libcxx/test/std/thread/futures/futures.promise/alloc_ctor.pass.cpp
libcxx/test/std/thread/futures/futures.promise/move_assign.pass.cpp
libcxx/test/std/thread/futures/futures.promise/move_ctor.pass.cpp
libcxx/test/std/thread/futures/futures.promise/swap.pass.cpp
libcxx/test/std/thread/futures/futures.shared_future/dtor.pass.cpp
libcxx/test/std/thread/futures/futures.task/futures.task.members/ctor_func_alloc.pass.cpp
libcxx/test/std/thread/futures/futures.unique_future/dtor.pass.cpp
libcxx/test/std/utilities/function.objects/func.wrap/func.wrap.func/func.wrap.func.con/alloc_F.pass.cpp
libcxx/test/std/utilities/memory/util.smartptr/util.smartptr.shared/util.smartptr.shared.const/nullptr_t_deleter_allocator.pass.cpp
libcxx/test/std/utilities/memory/util.smartptr/util.smartptr.shared/util.smartptr.shared.const/nullptr_t_deleter_allocator_throw.pass.cpp
libcxx/test/std/utilities/memory/util.smartptr/util.smartptr.shared/util.smartptr.shared.const/pointer_deleter_allocator.pass.cpp
libcxx/test/std/utilities/memory/util.smartptr/util.smartptr.shared/util.smartptr.shared.const/pointer_deleter_allocator_throw.pass.cpp
libcxx/test/std/utilities/memory/util.smartptr/util.smartptr.shared/util.smartptr.shared.create/allocate_shared.pass.cpp
libcxx/test/std/utilities/memory/util.smartptr/util.smartptr.shared/util.smartptr.shared.mod/reset_pointer_deleter_allocator.pass.cpp
libcxx/test/support/test_allocator.h

index 824b362..a22d41e 100644 (file)
@@ -74,17 +74,18 @@ void test_basic() {
 
 
 void duplicate_keys_test() {
+  test_allocator_statistics alloc_stats;
   typedef std::map<int, int, std::less<int>, test_allocator<std::pair<const int, int> > > Map;
   {
-    LIBCPP_ASSERT(test_alloc_base::alloc_count == 0);
-    Map s = {{1, 0}, {2, 0}, {3, 0}};
-    LIBCPP_ASSERT(test_alloc_base::alloc_count == 3);
+    LIBCPP_ASSERT(alloc_stats.alloc_count == 0);
+    Map s({{1, 0}, {2, 0}, {3, 0}}, std::less<int>(), test_allocator<std::pair<const int, int> >(&alloc_stats));
+    LIBCPP_ASSERT(alloc_stats.alloc_count == 3);
     s = {{4, 0}, {4, 0}, {4, 0}, {4, 0}};
-    LIBCPP_ASSERT(test_alloc_base::alloc_count == 1);
+    LIBCPP_ASSERT(alloc_stats.alloc_count == 1);
     assert(s.size() == 1);
     assert(s.begin()->first == 4);
   }
-  LIBCPP_ASSERT(test_alloc_base::alloc_count == 0);
+  LIBCPP_ASSERT(alloc_stats.alloc_count == 0);
 }
 
 int main(int, char**)
index b04d7f5..b096995 100644 (file)
@@ -55,17 +55,18 @@ void basic_test() {
 }
 
 void duplicate_keys_test() {
+  test_allocator_statistics alloc_stats;
   typedef std::set<int, std::less<int>, test_allocator<int> > Set;
   {
-    LIBCPP_ASSERT(test_alloc_base::alloc_count == 0);
-    Set s = {1, 2, 3};
-    LIBCPP_ASSERT(test_alloc_base::alloc_count == 3);
+    LIBCPP_ASSERT(alloc_stats.alloc_count == 0);
+    Set s({1, 2, 3}, std::less<int>(), test_allocator<int>(&alloc_stats));
+    LIBCPP_ASSERT(alloc_stats.alloc_count == 3);
     s = {4, 4, 4, 4, 4};
-    LIBCPP_ASSERT(test_alloc_base::alloc_count == 1);
+    LIBCPP_ASSERT(alloc_stats.alloc_count == 1);
     assert(s.size() == 1);
     assert(*s.begin() == 4);
   }
-  LIBCPP_ASSERT(test_alloc_base::alloc_count == 0);
+  LIBCPP_ASSERT(alloc_stats.alloc_count == 0);
 }
 
 int main(int, char**) {
index 0cc573e..cc8949e 100644 (file)
 
 template <class C>
 void test(int expected_num_allocs = 1) {
+  test_allocator_statistics alloc_stats;
   {
-    test_alloc_base::clear();
+    alloc_stats.clear();
     using AllocT = typename C::allocator_type;
-    C v(AllocT(42, 101));
+    C v(AllocT(42, 101, &alloc_stats));
 
-    assert(test_alloc_base::count == expected_num_allocs);
+    assert(alloc_stats.count == expected_num_allocs);
 
-    const int num_stored_allocs = test_alloc_base::count;
+    const int num_stored_allocs = alloc_stats.count;
     {
       const AllocT& a = v.get_allocator();
-      assert(test_alloc_base::count == 1 + num_stored_allocs);
+      assert(alloc_stats.count == 1 + num_stored_allocs);
       assert(a.get_data() == 42);
       assert(a.get_id() == 101);
     }
-    assert(test_alloc_base::count == num_stored_allocs);
-    test_alloc_base::clear_ctor_counters();
+    assert(alloc_stats.count == num_stored_allocs);
+    alloc_stats.clear_ctor_counters();
 
     C v2 = std::move(v);
-    assert(test_alloc_base::count == num_stored_allocs * 2);
-    assert(test_alloc_base::copied == 0);
-    assert(test_alloc_base::moved == num_stored_allocs);
+    assert(alloc_stats.count == num_stored_allocs * 2);
+    assert(alloc_stats.copied == 0);
+    assert(alloc_stats.moved == num_stored_allocs);
     {
       const AllocT& a = v.get_allocator();
       assert(a.get_id() == test_alloc_base::moved_value);
index b24fd07..1371293 100644 (file)
@@ -86,11 +86,12 @@ int main(int, char**)
     }
 
     {
+    test_allocator_statistics alloc_stats;
     typedef std::deque<CMyClass, test_allocator<CMyClass> > C;
-    C vec;
-    C vec2(vec);
+    C vec((test_allocator<CMyClass>(&alloc_stats)));
+    C vec2(vec, test_allocator<CMyClass>(&alloc_stats));
 
-    C::allocator_type::throw_after = 1;
+    alloc_stats.throw_after = 1;
     try {
         vec.push_back(instance);
         assert(false);
index 990f41f..79f9a14 100644 (file)
@@ -86,11 +86,12 @@ int main(int, char**)
     }
 
     {
+    test_allocator_statistics alloc_stats;
     typedef std::deque<CMyClass, test_allocator<CMyClass> > C;
-    C vec;
-    C vec2(vec);
+    C vec((test_allocator<CMyClass>(&alloc_stats)));
+    C vec2(vec, test_allocator<CMyClass>(&alloc_stats));
 
-    C::allocator_type::throw_after = 1;
+    alloc_stats.throw_after = 1;
     try {
         vec.push_front(instance);
         assert(false);
index 8da56e6..a554ec8 100644 (file)
 
 int main(int, char**)
 {
+    test_allocator_statistics alloc_stats;
     {
-        std::vector<bool, test_allocator<bool> > l(test_allocator<bool>(5));
-        std::vector<bool, test_allocator<bool> > lo(test_allocator<bool>(5));
+        std::vector<bool, test_allocator<bool> > l(test_allocator<bool>(5, &alloc_stats));
+        std::vector<bool, test_allocator<bool> > lo(test_allocator<bool>(5, &alloc_stats));
         for (int i = 1; i <= 3; ++i)
         {
             l.push_back(true);
@@ -60,24 +61,24 @@ int main(int, char**)
         assert(l2.get_allocator() == lo.get_allocator());
     }
     {
-      test_alloc_base::clear();
+      alloc_stats.clear();
       using Vect = std::vector<bool, test_allocator<bool> >;
       using AllocT = Vect::allocator_type;
-      Vect v(test_allocator<bool>(42, 101));
-      assert(test_alloc_base::count == 1);
+      Vect v(test_allocator<bool>(42, 101, &alloc_stats));
+      assert(alloc_stats.count == 1);
       {
         const AllocT& a = v.get_allocator();
-        assert(test_alloc_base::count == 2);
+        assert(alloc_stats.count == 2);
         assert(a.get_data() == 42);
         assert(a.get_id() == 101);
       }
-      assert(test_alloc_base::count == 1);
-      test_alloc_base::clear_ctor_counters();
+      assert(alloc_stats.count == 1);
+      alloc_stats.clear_ctor_counters();
 
       Vect v2 = std::move(v);
-      assert(test_alloc_base::count == 2);
-      assert(test_alloc_base::copied == 0);
-      assert(test_alloc_base::moved == 1);
+      assert(alloc_stats.count == 2);
+      assert(alloc_stats.copied == 0);
+      assert(alloc_stats.moved == 1);
       {
         const AllocT& a = v.get_allocator();
         assert(a.get_id() == test_alloc_base::moved_value);
index 1c21264..8c797d1 100644 (file)
 
 int main(int, char**)
 {
+    test_allocator_statistics alloc_stats;
     {
-        std::vector<MoveOnly, test_allocator<MoveOnly> > l(test_allocator<MoveOnly>(5));
-        std::vector<MoveOnly, test_allocator<MoveOnly> > lo(test_allocator<MoveOnly>(5));
+        std::vector<MoveOnly, test_allocator<MoveOnly> > l(test_allocator<MoveOnly>(5, &alloc_stats));
+        std::vector<MoveOnly, test_allocator<MoveOnly> > lo(test_allocator<MoveOnly>(5, &alloc_stats));
         assert(is_contiguous_container_asan_correct(l));
         assert(is_contiguous_container_asan_correct(lo));
         for (int i = 1; i <= 3; ++i)
@@ -100,24 +101,24 @@ int main(int, char**)
         assert(is_contiguous_container_asan_correct(c2));
     }
     {
-      test_alloc_base::clear();
+      alloc_stats.clear();
       using Vect = std::vector<int, test_allocator<int> >;
-      Vect v(test_allocator<int>(42, 101));
-      assert(test_alloc_base::count == 1);
-      assert(test_alloc_base::copied == 1);
-      assert(test_alloc_base::moved == 0);
+      Vect v(test_allocator<int>(42, 101, &alloc_stats));
+      assert(alloc_stats.count == 1);
+      assert(alloc_stats.copied == 1);
+      assert(alloc_stats.moved == 0);
       {
         const test_allocator<int>& a = v.get_allocator();
         assert(a.get_data() == 42);
         assert(a.get_id() == 101);
       }
-      assert(test_alloc_base::count == 1);
-      test_alloc_base::clear_ctor_counters();
+      assert(alloc_stats.count == 1);
+      alloc_stats.clear_ctor_counters();
 
       Vect v2 = std::move(v);
-      assert(test_alloc_base::count == 2);
-      assert(test_alloc_base::copied == 0);
-      assert(test_alloc_base::moved == 1);
+      assert(alloc_stats.count == 2);
+      assert(alloc_stats.copied == 0);
+      assert(alloc_stats.moved == 1);
       {
         const test_allocator<int>& a = v.get_allocator();
         assert(a.get_id() == test_alloc_base::moved_value);
index 82f2b3e..0806ede 100644 (file)
@@ -37,16 +37,17 @@ test(const Allocator& a)
 
 int main(int, char**)
 {
+    test_allocator_statistics alloc_stats;
     test<char>   (std::allocator<std::sub_match<const char *> >());
 #ifndef TEST_HAS_NO_WIDE_CHARACTERS
     test<wchar_t>(std::allocator<std::sub_match<const wchar_t *> >());
 #endif
 
-    test<char>   (test_allocator<std::sub_match<const char*> >(3));
-    assert(test_alloc_base::moved == 1);
+    test<char>   (test_allocator<std::sub_match<const char*> >(3, &alloc_stats));
+    assert(alloc_stats.moved == 1);
 #ifndef TEST_HAS_NO_WIDE_CHARACTERS
-    test<wchar_t>(test_allocator<std::sub_match<const wchar_t*> >(3));
-    assert(test_alloc_base::moved == 2);
+    test<wchar_t>(test_allocator<std::sub_match<const wchar_t*> >(3, &alloc_stats));
+    assert(alloc_stats.moved == 2);
 #endif
 
   return 0;
index 02187c5..c401384 100644 (file)
 
 #include "test_macros.h"
 
+test_allocator_statistics alloc_stats;
+
 template <class S>
 void
 test(S s)
 {
-    S::allocator_type::throw_after = 0;
+    alloc_stats.throw_after = 0;
 #ifndef TEST_HAS_NO_EXCEPTIONS
     try
 #endif
@@ -37,14 +39,14 @@ test(S s)
         assert(false);
     }
 #endif
-    S::allocator_type::throw_after = INT_MAX;
+    alloc_stats.throw_after = INT_MAX;
 }
 
 int main(int, char**)
 {
     {
     typedef std::basic_string<char, std::char_traits<char>, test_allocator<char> > S;
-    S s;
+    S s((test_allocator<char>(&alloc_stats)));
     test(s);
     s.assign(10, 'a');
     s.erase(5);
index 00af31d..d38e7c4 100644 (file)
@@ -19,7 +19,6 @@
 #include "test_allocator.h"
 #include "min_allocator.h"
 
-
 template <class S>
 void
 test(S s0, const typename S::allocator_type& a)
@@ -33,9 +32,9 @@ test(S s0, const typename S::allocator_type& a)
     assert(s2.get_allocator() == a);
 }
 
-
 int main(int, char**)
 {
+    test_allocator_statistics alloc_stats;
     {
     typedef test_allocator<char> A;
     typedef std::basic_string<char, std::char_traits<char>, A> S;
@@ -44,12 +43,12 @@ int main(int, char**)
 #elif TEST_STD_VER >= 11
     static_assert((noexcept(S()) == std::is_nothrow_move_constructible<A>::value), "" );
 #endif
-    test(S(), A(3));
-    test(S("1"), A(5));
-    test(S("1234567890123456789012345678901234567890123456789012345678901234567890"), A(7));
+    test(S(), A(3, &alloc_stats));
+    test(S("1"), A(5, &alloc_stats));
+    test(S("1234567890123456789012345678901234567890123456789012345678901234567890"), A(7, &alloc_stats));
     }
 
-    int alloc_count = test_alloc_base::alloc_count;
+    int alloc_count = alloc_stats.alloc_count;
     {
     typedef test_allocator<char> A;
     typedef std::basic_string<char, std::char_traits<char>, A> S;
@@ -58,10 +57,10 @@ int main(int, char**)
 #elif TEST_STD_VER >= 11
     static_assert((noexcept(S()) == std::is_nothrow_move_constructible<A>::value), "" );
 #endif
-    S s1 ( "Twas brillig, and the slivy toves did gyre and gymbal in the wabe" );
-    S s2 (std::move(s1), A(1));
+    S s1 ( "Twas brillig, and the slivy toves did gyre and gymbal in the wabe", A(&alloc_stats));
+    S s2 (std::move(s1), A(1, &alloc_stats));
     }
-    assert ( test_alloc_base::alloc_count == alloc_count );
+    assert ( alloc_stats.alloc_count == alloc_count );
     {
     typedef min_allocator<char> A;
     typedef std::basic_string<char, std::char_traits<char>, A> S;
index 150a277..cbb2c2e 100644 (file)
 
 int main(int, char**)
 {
-    assert(test_alloc_base::alloc_count == 0);
+    test_allocator_statistics alloc_stats;
+    assert(alloc_stats.alloc_count == 0);
     {
-        std::promise<int> p(std::allocator_arg, test_allocator<int>(42));
-        assert(test_alloc_base::alloc_count == 1);
+        std::promise<int> p(std::allocator_arg, test_allocator<int>(42, &alloc_stats));
+        assert(alloc_stats.alloc_count == 1);
         std::future<int> f = p.get_future();
-        assert(test_alloc_base::alloc_count == 1);
+        assert(alloc_stats.alloc_count == 1);
         assert(f.valid());
     }
-    assert(test_alloc_base::alloc_count == 0);
+    assert(alloc_stats.alloc_count == 0);
     {
-        std::promise<int&> p(std::allocator_arg, test_allocator<int>(42));
-        assert(test_alloc_base::alloc_count == 1);
+        std::promise<int&> p(std::allocator_arg, test_allocator<int>(42, &alloc_stats));
+        assert(alloc_stats.alloc_count == 1);
         std::future<int&> f = p.get_future();
-        assert(test_alloc_base::alloc_count == 1);
+        assert(alloc_stats.alloc_count == 1);
         assert(f.valid());
     }
-    assert(test_alloc_base::alloc_count == 0);
+    assert(alloc_stats.alloc_count == 0);
     {
-        std::promise<void> p(std::allocator_arg, test_allocator<void>(42));
-        assert(test_alloc_base::alloc_count == 1);
+        std::promise<void> p(std::allocator_arg, test_allocator<void>(42, &alloc_stats));
+        assert(alloc_stats.alloc_count == 1);
         std::future<void> f = p.get_future();
-        assert(test_alloc_base::alloc_count == 1);
+        assert(alloc_stats.alloc_count == 1);
         assert(f.valid());
     }
-    assert(test_alloc_base::alloc_count == 0);
+    assert(alloc_stats.alloc_count == 0);
     // Test with a minimal allocator
     {
         std::promise<int> p(std::allocator_arg, bare_allocator<void>());
index f3978e7..ac504ef 100644 (file)
 
 int main(int, char**)
 {
-    assert(test_alloc_base::alloc_count == 0);
+    test_allocator_statistics alloc_stats;
+    assert(alloc_stats.alloc_count == 0);
     {
-        std::promise<int> p0(std::allocator_arg, test_allocator<int>());
-        std::promise<int> p(std::allocator_arg, test_allocator<int>());
-        assert(test_alloc_base::alloc_count == 2);
+        std::promise<int> p0(std::allocator_arg, test_allocator<int>(&alloc_stats));
+        std::promise<int> p(std::allocator_arg, test_allocator<int>(&alloc_stats));
+        assert(alloc_stats.alloc_count == 2);
         p = std::move(p0);
-        assert(test_alloc_base::alloc_count == 1);
+        assert(alloc_stats.alloc_count == 1);
         std::future<int> f = p.get_future();
-        assert(test_alloc_base::alloc_count == 1);
+        assert(alloc_stats.alloc_count == 1);
         assert(f.valid());
 #ifndef TEST_HAS_NO_EXCEPTIONS
         try
@@ -44,17 +45,17 @@ int main(int, char**)
             assert(e.code() == make_error_code(std::future_errc::no_state));
         }
 #endif
-        assert(test_alloc_base::alloc_count == 1);
+        assert(alloc_stats.alloc_count == 1);
     }
-    assert(test_alloc_base::alloc_count == 0);
+    assert(alloc_stats.alloc_count == 0);
     {
-        std::promise<int&> p0(std::allocator_arg, test_allocator<int>());
-        std::promise<int&> p(std::allocator_arg, test_allocator<int>());
-        assert(test_alloc_base::alloc_count == 2);
+        std::promise<int&> p0(std::allocator_arg, test_allocator<int>(&alloc_stats));
+        std::promise<int&> p(std::allocator_arg, test_allocator<int>(&alloc_stats));
+        assert(alloc_stats.alloc_count == 2);
         p = std::move(p0);
-        assert(test_alloc_base::alloc_count == 1);
+        assert(alloc_stats.alloc_count == 1);
         std::future<int&> f = p.get_future();
-        assert(test_alloc_base::alloc_count == 1);
+        assert(alloc_stats.alloc_count == 1);
         assert(f.valid());
 #ifndef TEST_HAS_NO_EXCEPTIONS
         try
@@ -67,17 +68,17 @@ int main(int, char**)
             assert(e.code() == make_error_code(std::future_errc::no_state));
         }
 #endif
-        assert(test_alloc_base::alloc_count == 1);
+        assert(alloc_stats.alloc_count == 1);
     }
-    assert(test_alloc_base::alloc_count == 0);
+    assert(alloc_stats.alloc_count == 0);
     {
-        std::promise<void> p0(std::allocator_arg, test_allocator<void>());
-        std::promise<void> p(std::allocator_arg, test_allocator<void>());
-        assert(test_alloc_base::alloc_count == 2);
+        std::promise<void> p0(std::allocator_arg, test_allocator<void>(&alloc_stats));
+        std::promise<void> p(std::allocator_arg, test_allocator<void>(&alloc_stats));
+        assert(alloc_stats.alloc_count == 2);
         p = std::move(p0);
-        assert(test_alloc_base::alloc_count == 1);
+        assert(alloc_stats.alloc_count == 1);
         std::future<void> f = p.get_future();
-        assert(test_alloc_base::alloc_count == 1);
+        assert(alloc_stats.alloc_count == 1);
         assert(f.valid());
 #ifndef TEST_HAS_NO_EXCEPTIONS
         try
@@ -90,9 +91,9 @@ int main(int, char**)
             assert(e.code() == make_error_code(std::future_errc::no_state));
         }
 #endif
-        assert(test_alloc_base::alloc_count == 1);
+        assert(alloc_stats.alloc_count == 1);
     }
-    assert(test_alloc_base::alloc_count == 0);
+    assert(alloc_stats.alloc_count == 0);
 
   return 0;
 }
index 1fdd61c..9775e66 100644 (file)
 
 int main(int, char**)
 {
-    assert(test_alloc_base::alloc_count == 0);
+    test_allocator_statistics alloc_stats;
+    assert(alloc_stats.alloc_count == 0);
     {
-        std::promise<int> p0(std::allocator_arg, test_allocator<int>());
+        std::promise<int> p0(std::allocator_arg, test_allocator<int>(&alloc_stats));
         std::promise<int> p(std::move(p0));
-        assert(test_alloc_base::alloc_count == 1);
+        assert(alloc_stats.alloc_count == 1);
         std::future<int> f = p.get_future();
-        assert(test_alloc_base::alloc_count == 1);
+        assert(alloc_stats.alloc_count == 1);
         assert(f.valid());
 #ifndef TEST_HAS_NO_EXCEPTIONS
         try
@@ -41,16 +42,16 @@ int main(int, char**)
         {
             assert(e.code() == make_error_code(std::future_errc::no_state));
         }
-        assert(test_alloc_base::alloc_count == 1);
+        assert(alloc_stats.alloc_count == 1);
 #endif
     }
-    assert(test_alloc_base::alloc_count == 0);
+    assert(alloc_stats.alloc_count == 0);
     {
-        std::promise<int&> p0(std::allocator_arg, test_allocator<int>());
+        std::promise<int&> p0(std::allocator_arg, test_allocator<int>(&alloc_stats));
         std::promise<int&> p(std::move(p0));
-        assert(test_alloc_base::alloc_count == 1);
+        assert(alloc_stats.alloc_count == 1);
         std::future<int&> f = p.get_future();
-        assert(test_alloc_base::alloc_count == 1);
+        assert(alloc_stats.alloc_count == 1);
         assert(f.valid());
 #ifndef TEST_HAS_NO_EXCEPTIONS
         try
@@ -62,16 +63,16 @@ int main(int, char**)
         {
             assert(e.code() == make_error_code(std::future_errc::no_state));
         }
-        assert(test_alloc_base::alloc_count == 1);
+        assert(alloc_stats.alloc_count == 1);
 #endif
     }
-    assert(test_alloc_base::alloc_count == 0);
+    assert(alloc_stats.alloc_count == 0);
     {
-        std::promise<void> p0(std::allocator_arg, test_allocator<void>());
+        std::promise<void> p0(std::allocator_arg, test_allocator<void>(&alloc_stats));
         std::promise<void> p(std::move(p0));
-        assert(test_alloc_base::alloc_count == 1);
+        assert(alloc_stats.alloc_count == 1);
         std::future<void> f = p.get_future();
-        assert(test_alloc_base::alloc_count == 1);
+        assert(alloc_stats.alloc_count == 1);
         assert(f.valid());
 #ifndef TEST_HAS_NO_EXCEPTIONS
         try
@@ -83,10 +84,10 @@ int main(int, char**)
         {
             assert(e.code() == make_error_code(std::future_errc::no_state));
         }
-        assert(test_alloc_base::alloc_count == 1);
+        assert(alloc_stats.alloc_count == 1);
 #endif
     }
-    assert(test_alloc_base::alloc_count == 0);
+    assert(alloc_stats.alloc_count == 0);
 
   return 0;
 }
index bdb4595..fbf77b1 100644 (file)
 
 int main(int, char**)
 {
-    assert(test_alloc_base::alloc_count == 0);
+    test_allocator_statistics alloc_stats;
+    assert(alloc_stats.alloc_count == 0);
     {
-        std::promise<int> p0(std::allocator_arg, test_allocator<int>());
-        std::promise<int> p(std::allocator_arg, test_allocator<int>());
-        assert(test_alloc_base::alloc_count == 2);
+        std::promise<int> p0(std::allocator_arg, test_allocator<int>(&alloc_stats));
+        std::promise<int> p(std::allocator_arg, test_allocator<int>(&alloc_stats));
+        assert(alloc_stats.alloc_count == 2);
         p.swap(p0);
-        assert(test_alloc_base::alloc_count == 2);
+        assert(alloc_stats.alloc_count == 2);
         std::future<int> f = p.get_future();
-        assert(test_alloc_base::alloc_count == 2);
+        assert(alloc_stats.alloc_count == 2);
         assert(f.valid());
         f = p0.get_future();
         assert(f.valid());
-        assert(test_alloc_base::alloc_count == 2);
+        assert(alloc_stats.alloc_count == 2);
     }
-    assert(test_alloc_base::alloc_count == 0);
+    assert(alloc_stats.alloc_count == 0);
     {
-        std::promise<int> p0(std::allocator_arg, test_allocator<int>());
-        std::promise<int> p(std::allocator_arg, test_allocator<int>());
-        assert(test_alloc_base::alloc_count == 2);
+        std::promise<int> p0(std::allocator_arg, test_allocator<int>(&alloc_stats));
+        std::promise<int> p(std::allocator_arg, test_allocator<int>(&alloc_stats));
+        assert(alloc_stats.alloc_count == 2);
         swap(p, p0);
-        assert(test_alloc_base::alloc_count == 2);
+        assert(alloc_stats.alloc_count == 2);
         std::future<int> f = p.get_future();
-        assert(test_alloc_base::alloc_count == 2);
+        assert(alloc_stats.alloc_count == 2);
         assert(f.valid());
         f = p0.get_future();
         assert(f.valid());
-        assert(test_alloc_base::alloc_count == 2);
+        assert(alloc_stats.alloc_count == 2);
     }
-    assert(test_alloc_base::alloc_count == 0);
+    assert(alloc_stats.alloc_count == 0);
     {
-        std::promise<int> p0(std::allocator_arg, test_allocator<int>());
+        std::promise<int> p0(std::allocator_arg, test_allocator<int>(&alloc_stats));
         std::promise<int> p;
-        assert(test_alloc_base::alloc_count == 1);
+        assert(alloc_stats.alloc_count == 1);
         p.swap(p0);
-        assert(test_alloc_base::alloc_count == 1);
+        assert(alloc_stats.alloc_count == 1);
         std::future<int> f = p.get_future();
-        assert(test_alloc_base::alloc_count == 1);
+        assert(alloc_stats.alloc_count == 1);
         assert(f.valid());
         f = p0.get_future();
         assert(f.valid());
-        assert(test_alloc_base::alloc_count == 1);
+        assert(alloc_stats.alloc_count == 1);
     }
-    assert(test_alloc_base::alloc_count == 0);
+    assert(alloc_stats.alloc_count == 0);
     {
-        std::promise<int> p0(std::allocator_arg, test_allocator<int>());
+        std::promise<int> p0(std::allocator_arg, test_allocator<int>(&alloc_stats));
         std::promise<int> p;
-        assert(test_alloc_base::alloc_count == 1);
+        assert(alloc_stats.alloc_count == 1);
         swap(p, p0);
-        assert(test_alloc_base::alloc_count == 1);
+        assert(alloc_stats.alloc_count == 1);
         std::future<int> f = p.get_future();
-        assert(test_alloc_base::alloc_count == 1);
+        assert(alloc_stats.alloc_count == 1);
         assert(f.valid());
         f = p0.get_future();
         assert(f.valid());
-        assert(test_alloc_base::alloc_count == 1);
+        assert(alloc_stats.alloc_count == 1);
     }
-    assert(test_alloc_base::alloc_count == 0);
+    assert(alloc_stats.alloc_count == 0);
 
   return 0;
 }
index 3d72b98..027073f 100644 (file)
 
 int main(int, char**)
 {
-    assert(test_alloc_base::alloc_count == 0);
+    test_allocator_statistics alloc_stats;
+    assert(alloc_stats.alloc_count == 0);
     {
         typedef int T;
         std::shared_future<T> f;
         {
-            std::promise<T> p(std::allocator_arg, test_allocator<T>());
-            assert(test_alloc_base::alloc_count == 1);
+            std::promise<T> p(std::allocator_arg, test_allocator<T>(&alloc_stats));
+            assert(alloc_stats.alloc_count == 1);
             f = p.get_future();
-            assert(test_alloc_base::alloc_count == 1);
+            assert(alloc_stats.alloc_count == 1);
             assert(f.valid());
         }
-        assert(test_alloc_base::alloc_count == 1);
+        assert(alloc_stats.alloc_count == 1);
         assert(f.valid());
     }
-    assert(test_alloc_base::alloc_count == 0);
+    assert(alloc_stats.alloc_count == 0);
     {
         typedef int& T;
         std::shared_future<T> f;
         {
-            std::promise<T> p(std::allocator_arg, test_allocator<int>());
-            assert(test_alloc_base::alloc_count == 1);
+            std::promise<T> p(std::allocator_arg, test_allocator<int>(&alloc_stats));
+            assert(alloc_stats.alloc_count == 1);
             f = p.get_future();
-            assert(test_alloc_base::alloc_count == 1);
+            assert(alloc_stats.alloc_count == 1);
             assert(f.valid());
         }
-        assert(test_alloc_base::alloc_count == 1);
+        assert(alloc_stats.alloc_count == 1);
         assert(f.valid());
     }
-    assert(test_alloc_base::alloc_count == 0);
+    assert(alloc_stats.alloc_count == 0);
     {
         typedef void T;
         std::shared_future<T> f;
         {
-            std::promise<T> p(std::allocator_arg, test_allocator<T>());
-            assert(test_alloc_base::alloc_count == 1);
+            std::promise<T> p(std::allocator_arg, test_allocator<T>(&alloc_stats));
+            assert(alloc_stats.alloc_count == 1);
             f = p.get_future();
-            assert(test_alloc_base::alloc_count == 1);
+            assert(alloc_stats.alloc_count == 1);
             assert(f.valid());
         }
-        assert(test_alloc_base::alloc_count == 1);
+        assert(alloc_stats.alloc_count == 1);
         assert(f.valid());
     }
-    assert(test_alloc_base::alloc_count == 0);
+    assert(alloc_stats.alloc_count == 0);
 
   return 0;
 }
index 2255a45..788afbd 100644 (file)
@@ -47,10 +47,11 @@ int func(int i) { return i; }
 
 int main(int, char**)
 {
+    test_allocator_statistics alloc_stats;
     {
         std::packaged_task<double(int, char)> p(std::allocator_arg,
-                                                test_allocator<A>(), A(5));
-        assert(test_alloc_base::alloc_count > 0);
+                                                test_allocator<A>(&alloc_stats), A(5));
+        assert(alloc_stats.alloc_count > 0);
         assert(p.valid());
         std::future<double> f = p.get_future();
         p(3, 'a');
@@ -58,14 +59,14 @@ int main(int, char**)
         assert(A::n_copies == 0);
         assert(A::n_moves > 0);
     }
-    assert(test_alloc_base::alloc_count == 0);
+    assert(alloc_stats.alloc_count == 0);
     A::n_copies = 0;
     A::n_moves  = 0;
     {
         A a(5);
         std::packaged_task<double(int, char)> p(std::allocator_arg,
-                                                test_allocator<A>(), a);
-        assert(test_alloc_base::alloc_count > 0);
+                                                test_allocator<A>(&alloc_stats), a);
+        assert(alloc_stats.alloc_count > 0);
         assert(p.valid());
         std::future<double> f = p.get_future();
         p(3, 'a');
@@ -73,31 +74,31 @@ int main(int, char**)
         assert(A::n_copies > 0);
         assert(A::n_moves >= 0);
     }
-    assert(test_alloc_base::alloc_count == 0);
+    assert(alloc_stats.alloc_count == 0);
     A::n_copies = 0;
     A::n_moves  = 0;
     {
         A a(5);
-        std::packaged_task<int(int)> p(std::allocator_arg, test_allocator<A>(), &func);
-        assert(test_alloc_base::alloc_count > 0);
+        std::packaged_task<int(int)> p(std::allocator_arg, test_allocator<A>(&alloc_stats), &func);
+        assert(alloc_stats.alloc_count > 0);
         assert(p.valid());
         std::future<int> f = p.get_future();
         p(4);
         assert(f.get() == 4);
     }
-    assert(test_alloc_base::alloc_count == 0);
+    assert(alloc_stats.alloc_count == 0);
     A::n_copies = 0;
     A::n_moves  = 0;
     {
         A a(5);
-        std::packaged_task<int(int)> p(std::allocator_arg, test_allocator<A>(), func);
-        assert(test_alloc_base::alloc_count > 0);
+        std::packaged_task<int(int)> p(std::allocator_arg, test_allocator<A>(&alloc_stats), func);
+        assert(alloc_stats.alloc_count > 0);
         assert(p.valid());
         std::future<int> f = p.get_future();
         p(4);
         assert(f.get() == 4);
     }
-    assert(test_alloc_base::alloc_count == 0);
+    assert(alloc_stats.alloc_count == 0);
     A::n_copies = 0;
     A::n_moves  = 0;
     {
index 05bfe2b..643fb6a 100644 (file)
 
 int main(int, char**)
 {
-    assert(test_alloc_base::alloc_count == 0);
+    test_allocator_statistics alloc_stats;
+    assert(alloc_stats.alloc_count == 0);
     {
         typedef int T;
         std::future<T> f;
         {
-            std::promise<T> p(std::allocator_arg, test_allocator<T>());
-            assert(test_alloc_base::alloc_count == 1);
+            std::promise<T> p(std::allocator_arg, test_allocator<T>(&alloc_stats));
+            assert(alloc_stats.alloc_count == 1);
             f = p.get_future();
-            assert(test_alloc_base::alloc_count == 1);
+            assert(alloc_stats.alloc_count == 1);
             assert(f.valid());
         }
-        assert(test_alloc_base::alloc_count == 1);
+        assert(alloc_stats.alloc_count == 1);
         assert(f.valid());
     }
-    assert(test_alloc_base::alloc_count == 0);
+    assert(alloc_stats.alloc_count == 0);
     {
         typedef int& T;
         std::future<T> f;
         {
-            std::promise<T> p(std::allocator_arg, test_allocator<int>());
-            assert(test_alloc_base::alloc_count == 1);
+            std::promise<T> p(std::allocator_arg, test_allocator<int>(&alloc_stats));
+            assert(alloc_stats.alloc_count == 1);
             f = p.get_future();
-            assert(test_alloc_base::alloc_count == 1);
+            assert(alloc_stats.alloc_count == 1);
             assert(f.valid());
         }
-        assert(test_alloc_base::alloc_count == 1);
+        assert(alloc_stats.alloc_count == 1);
         assert(f.valid());
     }
-    assert(test_alloc_base::alloc_count == 0);
+    assert(alloc_stats.alloc_count == 0);
     {
         typedef void T;
         std::future<T> f;
         {
-            std::promise<T> p(std::allocator_arg, test_allocator<T>());
-            assert(test_alloc_base::alloc_count == 1);
+            std::promise<T> p(std::allocator_arg, test_allocator<T>(&alloc_stats));
+            assert(alloc_stats.alloc_count == 1);
             f = p.get_future();
-            assert(test_alloc_base::alloc_count == 1);
+            assert(alloc_stats.alloc_count == 1);
             assert(f.valid());
         }
-        assert(test_alloc_base::alloc_count == 1);
+        assert(alloc_stats.alloc_count == 1);
         assert(f.valid());
     }
-    assert(test_alloc_base::alloc_count == 0);
+    assert(alloc_stats.alloc_count == 0);
 
   return 0;
 }
index b5821d8..e364e9e 100644 (file)
@@ -25,7 +25,6 @@
 #include "count_new.h"
 #include "../function_types.h"
 
-
 #if TEST_STD_VER >= 11
 struct RValueCallable {
     template <class ...Args>
@@ -37,6 +36,8 @@ struct LValueCallable {
 };
 #endif
 
+test_allocator_statistics alloc_stats;
+
 class DummyClass {};
 
 template <class FuncType, class AllocType>
@@ -69,7 +70,7 @@ void test_FreeFunction(AllocType& alloc)
     std::function<FuncType> f2(std::allocator_arg, alloc, target);
     // The allocator may not fit in the small object buffer, if we allocated
     // check it was done via the allocator.
-    assert(globalMemCounter.checkOutstandingNewEq(test_alloc_base::alloc_count));
+    assert(globalMemCounter.checkOutstandingNewEq(alloc_stats.alloc_count));
     assert(f2.template target<FuncType*>());
     assert(*f2.template target<FuncType*>() == target);
     assert(f2.template target<FuncType>() == 0);
@@ -86,7 +87,7 @@ void test_MemFunClass(AllocType& alloc)
     TargetType target = &MemFunClass::foo;
     assert(globalMemCounter.checkOutstandingNewEq(0));
     std::function<FuncType> f2(std::allocator_arg, alloc, target);
-    assert(globalMemCounter.checkOutstandingNewEq(test_alloc_base::alloc_count));
+    assert(globalMemCounter.checkOutstandingNewEq(alloc_stats.alloc_count));
     assert(f2.template target<TargetType>());
     assert(*f2.template target<TargetType>() == target);
     assert(f2.template target<FuncType*>() == 0);
@@ -111,15 +112,14 @@ void test_for_alloc(Alloc& alloc) {
     test_MemFunClass<int(MemFunClass::*)(int, int) const, int(MemFunClass&, int, int)>(alloc);
 }
 
-int main(int, char**)
-{
+int main(int, char**) {
   globalMemCounter.reset();
   {
     bare_allocator<DummyClass> bare_alloc;
     test_for_alloc(bare_alloc);
   }
     {
-        non_default_test_allocator<DummyClass> non_default_alloc(42);
+        non_default_test_allocator<DummyClass> non_default_alloc(42, &alloc_stats);
         test_for_alloc(non_default_alloc);
     }
 #if TEST_STD_VER >= 11
index fb5e4f4..4d59d7f 100644 (file)
@@ -30,8 +30,9 @@ int A::count = 0;
 
 int main(int, char**)
 {
+    test_allocator_statistics alloc_stats;
     {
-    std::shared_ptr<A> p(nullptr, test_deleter<A>(3), test_allocator<A>(5));
+    std::shared_ptr<A> p(nullptr, test_deleter<A>(3), test_allocator<A>(5, &alloc_stats));
     assert(A::count == 0);
     assert(p.use_count() == 1);
     assert(p.get() == 0);
@@ -42,14 +43,14 @@ int main(int, char**)
     assert(d);
     assert(d->state() == 3);
 #endif
-    assert(test_allocator<A>::count == 1);
-    assert(test_allocator<A>::alloc_count == 1);
+    assert(alloc_stats.count == 1);
+    assert(alloc_stats.alloc_count == 1);
     }
     assert(A::count == 0);
     assert(test_deleter<A>::count == 0);
     assert(test_deleter<A>::dealloc_count == 1);
-    assert(test_allocator<A>::count == 0);
-    assert(test_allocator<A>::alloc_count == 0);
+    assert(alloc_stats.count == 0);
+    assert(alloc_stats.alloc_count == 0);
     test_deleter<A>::dealloc_count = 0;
     // Test an allocator with a minimal interface
     {
index ce9c3e5..5864433 100644 (file)
@@ -30,10 +30,11 @@ int A::count = 0;
 
 int main(int, char**)
 {
+    test_allocator_statistics alloc_stats;
     try
     {
-        test_allocator<A>::throw_after = 0;
-        std::shared_ptr<A> p(nullptr, test_deleter<A>(3), test_allocator<A>(5));
+        alloc_stats.throw_after = 0;
+        std::shared_ptr<A> p(nullptr, test_deleter<A>(3), test_allocator<A>(5, &alloc_stats));
         assert(false);
     }
     catch (std::bad_alloc&)
@@ -41,8 +42,8 @@ int main(int, char**)
         assert(A::count == 0);
         assert(test_deleter<A>::count == 0);
         assert(test_deleter<A>::dealloc_count == 1);
-        assert(test_allocator<A>::count == 0);
-        assert(test_allocator<A>::alloc_count == 0);
+        assert(alloc_stats.count == 0);
+        assert(alloc_stats.alloc_count == 0);
     }
 
   return 0;
index d42ce34..3b86b07 100644 (file)
@@ -62,9 +62,10 @@ public:
 
 int main(int, char**)
 {
+    test_allocator_statistics alloc_stats;
     {
     A* ptr = new A;
-    std::shared_ptr<A> p(ptr, test_deleter<A>(3), test_allocator<A>(5));
+    std::shared_ptr<A> p(ptr, test_deleter<A>(3), test_allocator<A>(5, &alloc_stats));
     assert(A::count == 1);
     assert(p.use_count() == 1);
     assert(p.get() == ptr);
@@ -75,14 +76,14 @@ int main(int, char**)
     assert(d);
     assert(d->state() == 3);
 #endif
-    assert(test_allocator<A>::count == 1);
-    assert(test_allocator<A>::alloc_count == 1);
+    assert(alloc_stats.count == 1);
+    assert(alloc_stats.alloc_count == 1);
     }
     assert(A::count == 0);
     assert(test_deleter<A>::count == 0);
     assert(test_deleter<A>::dealloc_count == 1);
-    assert(test_allocator<A>::count == 0);
-    assert(test_allocator<A>::alloc_count == 0);
+    assert(alloc_stats.count == 0);
+    assert(alloc_stats.alloc_count == 0);
     test_deleter<A>::dealloc_count = 0;
     // Test an allocator with a minimal interface
     {
index 240fd35..6baf2de 100644 (file)
@@ -30,20 +30,21 @@ int A::count = 0;
 
 int main(int, char**)
 {
+    test_allocator_statistics alloc_stats;
     A* ptr = new A;
     try
     {
-        test_allocator<A>::throw_after = 0;
-        std::shared_ptr<A> p(ptr, test_deleter<A>(3), test_allocator<A>(5));
+        alloc_stats.throw_after = 0;
+        std::shared_ptr<A> p(ptr, test_deleter<A>(3), test_allocator<A>(5, &alloc_stats));
         assert(false);
     }
     catch (std::bad_alloc&)
     {
-        assert(A::count == 0);
-        assert(test_deleter<A>::count == 0);
+        assert(alloc_stats.count == 0);
+        assert(alloc_stats.count == 0);
         assert(test_deleter<A>::dealloc_count == 1);
-        assert(test_allocator<A>::count == 0);
-        assert(test_allocator<A>::alloc_count == 0);
+        assert(alloc_stats.count == 0);
+        assert(alloc_stats.alloc_count == 0);
     }
 
   return 0;
index b892fb4..472cb3d 100644 (file)
@@ -141,17 +141,18 @@ int main(int, char**)
     test<bare_allocator<void> >();
     test<test_allocator<void> >();
 
+    test_allocator_statistics alloc_stats;
     {
     int i = 67;
     char c = 'e';
-    std::shared_ptr<A> p = std::allocate_shared<A>(test_allocator<A>(54), i, c);
-    assert(test_allocator<A>::alloc_count == 1);
+    std::shared_ptr<A> p = std::allocate_shared<A>(test_allocator<A>(54, &alloc_stats), i, c);
+    assert(alloc_stats.alloc_count == 1);
     assert(A::count == 1);
     assert(p->get_int() == 67);
     assert(p->get_char() == 'e');
     }
     assert(A::count == 0);
-    assert(test_allocator<A>::alloc_count == 0);
+    assert(alloc_stats.alloc_count == 0);
     {
     int i = 67;
     char c = 'e';
index 17afcca..a6ea07e 100644 (file)
@@ -43,10 +43,11 @@ int A::count = 0;
 
 int main(int, char**)
 {
+    test_allocator_statistics alloc_stats;
     {
         std::shared_ptr<B> p(new B);
         A* ptr = new A;
-        p.reset(ptr, test_deleter<A>(3), test_allocator<A>(4));
+        p.reset(ptr, test_deleter<A>(3), test_allocator<A>(4, &alloc_stats));
         assert(A::count == 1);
         assert(B::count == 1);
         assert(p.use_count() == 1);
@@ -58,18 +59,18 @@ int main(int, char**)
         assert(d);
         assert(d->state() == 3);
 #endif
-        assert(test_allocator<A>::count == 1);
-        assert(test_allocator<A>::alloc_count == 1);
+        assert(alloc_stats.count == 1);
+        assert(alloc_stats.alloc_count == 1);
     }
     assert(A::count == 0);
     assert(test_deleter<A>::count == 0);
     assert(test_deleter<A>::dealloc_count == 1);
-    assert(test_allocator<A>::count == 0);
-    assert(test_allocator<A>::alloc_count == 0);
+    assert(alloc_stats.count == 0);
+    assert(alloc_stats.alloc_count == 0);
     {
         std::shared_ptr<B> p;
         A* ptr = new A;
-        p.reset(ptr, test_deleter<A>(3), test_allocator<A>(4));
+        p.reset(ptr, test_deleter<A>(3), test_allocator<A>(4, &alloc_stats));
         assert(A::count == 1);
         assert(B::count == 1);
         assert(p.use_count() == 1);
@@ -81,14 +82,14 @@ int main(int, char**)
         assert(d);
         assert(d->state() == 3);
 #endif
-        assert(test_allocator<A>::count == 1);
-        assert(test_allocator<A>::alloc_count == 1);
+        assert(alloc_stats.count == 1);
+        assert(alloc_stats.alloc_count == 1);
     }
     assert(A::count == 0);
     assert(test_deleter<A>::count == 0);
     assert(test_deleter<A>::dealloc_count == 2);
-    assert(test_allocator<A>::count == 0);
-    assert(test_allocator<A>::alloc_count == 0);
+    assert(alloc_stats.count == 0);
+    assert(alloc_stats.alloc_count == 0);
 
 #if TEST_STD_VER > 14
     {
index e0e402a..b532006 100644 (file)
@@ -26,23 +26,16 @@ inline typename std::allocator_traits<Alloc>::size_type alloc_max_size(Alloc con
   return AT::max_size(a);
 }
 
-class test_alloc_base {
-protected:
-  static int time_to_throw;
-
-public:
-  static int throw_after;
-  static int count;
-  static int alloc_count;
-  static int copied;
-  static int moved;
-  static int converted;
-
-  const static int destructed_value = -1;
-  const static int default_value = 0;
-  const static int moved_value = INT_MAX;
-
-  static void clear() {
+struct test_allocator_statistics {
+  int time_to_throw = 0;
+  int throw_after = INT_MAX;
+  int count = 0;
+  int alloc_count = 0;
+  int copied = 0;
+  int moved = 0;
+  int converted = 0;
+
+  TEST_CONSTEXPR_CXX14 void clear() {
     assert(count == 0 && "clearing leaking allocator data?");
     count = 0;
     time_to_throw = 0;
@@ -51,25 +44,24 @@ public:
     clear_ctor_counters();
   }
 
-  static void clear_ctor_counters() {
+  TEST_CONSTEXPR_CXX14 void clear_ctor_counters() {
     copied = 0;
     moved = 0;
     converted = 0;
   }
 };
 
-int test_alloc_base::count = 0;
-int test_alloc_base::time_to_throw = 0;
-int test_alloc_base::alloc_count = 0;
-int test_alloc_base::throw_after = INT_MAX;
-int test_alloc_base::copied = 0;
-int test_alloc_base::moved = 0;
-int test_alloc_base::converted = 0;
+struct test_alloc_base {
+  TEST_CONSTEXPR static const int destructed_value = -1;
+  TEST_CONSTEXPR static const int moved_value = INT_MAX;
+};
 
 template <class T>
-class test_allocator : public test_alloc_base {
-  int data_; // participates in equality
-  int id_;   // unique identifier, doesn't participate in equality
+class test_allocator {
+  int data_ = 0; // participates in equality
+  int id_ = 0;   // unique identifier, doesn't participate in equality
+  test_allocator_statistics* stats_ = nullptr;
+
   template <class U>
   friend class test_allocator;
 
@@ -87,74 +79,113 @@ public:
     typedef test_allocator<U> other;
   };
 
-  test_allocator() TEST_NOEXCEPT : data_(0), id_(0) { ++count; }
-  explicit test_allocator(int i, int id = 0) TEST_NOEXCEPT : data_(i), id_(id) { ++count; }
-  test_allocator(const test_allocator& a) TEST_NOEXCEPT : data_(a.data_), id_(a.id_) {
-    ++count;
-    ++copied;
-    assert(a.data_ != destructed_value && a.id_ != destructed_value && "copying from destroyed allocator");
+  TEST_CONSTEXPR test_allocator() TEST_NOEXCEPT = default;
+
+  TEST_CONSTEXPR_CXX14 explicit test_allocator(test_allocator_statistics* stats) TEST_NOEXCEPT : stats_(stats) {
+    if (stats_ != nullptr)
+      ++stats_->count;
+  }
+
+  TEST_CONSTEXPR explicit test_allocator(int data) TEST_NOEXCEPT : data_(data) {}
+
+  TEST_CONSTEXPR_CXX14 explicit test_allocator(int data, test_allocator_statistics* stats) TEST_NOEXCEPT
+      : data_(data), stats_(stats) {
+    if (stats != nullptr)
+      ++stats_->count;
+  }
+
+  TEST_CONSTEXPR explicit test_allocator(int data, int id) TEST_NOEXCEPT : data_(data), id_(id) {}
+
+  TEST_CONSTEXPR_CXX14 explicit test_allocator(int data, int id, test_allocator_statistics* stats) TEST_NOEXCEPT
+      : data_(data), id_(id), stats_(stats) {
+    if (stats_ != nullptr)
+      ++stats_->count;
   }
+
+  TEST_CONSTEXPR_CXX14 test_allocator(const test_allocator& a) TEST_NOEXCEPT
+    : data_(a.data_), id_(a.id_), stats_(a.stats_) {
+    assert(a.data_ != test_alloc_base::destructed_value && a.id_ != test_alloc_base::destructed_value &&
+           "copying from destroyed allocator");
+    if (stats_ != nullptr) {
+      ++stats_->count;
+      ++stats_->copied;
+    }
+  }
+
 #if TEST_STD_VER >= 11
-  test_allocator(test_allocator&& a) TEST_NOEXCEPT : data_(a.data_), id_(a.id_) {
-    ++count;
-    ++moved;
-    assert(a.data_ != destructed_value && a.id_ != destructed_value && "moving from destroyed allocator");
-    a.data_ = moved_value;
-    a.id_ = moved_value;
+  TEST_CONSTEXPR_CXX14 test_allocator(test_allocator&& a) TEST_NOEXCEPT : data_(a.data_), id_(a.id_), stats_(a.stats_) {
+    if (stats_ != nullptr) {
+      ++stats_->count;
+      ++stats_->moved;
+    }
+    assert(a.data_ != test_alloc_base::destructed_value && a.id_ != test_alloc_base::destructed_value &&
+           "moving from destroyed allocator");
+    a.data_ = test_alloc_base::moved_value;
+    a.id_ = test_alloc_base::moved_value;
   }
 #endif
+
   template <class U>
-  test_allocator(const test_allocator<U>& a) TEST_NOEXCEPT : data_(a.data_), id_(a.id_) {
-    ++count;
-    ++converted;
+  TEST_CONSTEXPR_CXX14 test_allocator(const test_allocator<U>& a) TEST_NOEXCEPT
+      : data_(a.data_), id_(a.id_), stats_(a.stats_) {
+    if (stats_ != nullptr) {
+      ++stats_->count;
+      ++stats_->converted;
+    }
   }
-  ~test_allocator() TEST_NOEXCEPT {
-    assert(data_ >= 0);
-    assert(id_ >= 0);
-    --count;
-    data_ = destructed_value;
-    id_ = destructed_value;
+
+  TEST_CONSTEXPR_CXX20 ~test_allocator() TEST_NOEXCEPT {
+    assert(data_ != test_alloc_base::destructed_value);
+    assert(id_ != test_alloc_base::destructed_value);
+    if (stats_ != nullptr)
+      --stats_->count;
+    data_ = test_alloc_base::destructed_value;
+    id_ = test_alloc_base::destructed_value;
   }
-  pointer address(reference x) const { return &x; }
-  const_pointer address(const_reference x) const { return &x; }
-  pointer allocate(size_type n, const void* = 0) {
-    assert(data_ >= 0);
-    if (time_to_throw >= throw_after) {
-#ifndef TEST_HAS_NO_EXCEPTIONS
-      throw std::bad_alloc();
-#else
-      std::terminate();
-#endif
+
+  TEST_CONSTEXPR pointer address(reference x) const { return &x; }
+  TEST_CONSTEXPR const_pointer address(const_reference x) const { return &x; }
+
+  TEST_CONSTEXPR_CXX14 pointer allocate(size_type n, const void* = 0) {
+    assert(data_ != test_alloc_base::destructed_value);
+    if (stats_ != nullptr) {
+      if (stats_->time_to_throw >= stats_->throw_after)
+        TEST_THROW(std::bad_alloc());
+      ++stats_->time_to_throw;
+      ++stats_->alloc_count;
     }
-    ++time_to_throw;
-    ++alloc_count;
-    return (pointer)::operator new(n * sizeof(T));
+    return std::allocator<value_type>().allocate(n);
   }
-  void deallocate(pointer p, size_type) {
-    assert(data_ >= 0);
-    --alloc_count;
-    ::operator delete((void*)p);
+
+  TEST_CONSTEXPR_CXX14 void deallocate(pointer p, size_type s) {
+    assert(data_ != test_alloc_base::destructed_value);
+    if (stats_ != nullptr)
+      --stats_->alloc_count;
+    std::allocator<value_type>().deallocate(p, s);
   }
-  size_type max_size() const TEST_NOEXCEPT { return UINT_MAX / sizeof(T); }
+
+  TEST_CONSTEXPR size_type max_size() const TEST_NOEXCEPT { return UINT_MAX / sizeof(T); }
+
 #if TEST_STD_VER < 11
   void construct(pointer p, const T& val) { ::new (static_cast<void*>(p)) T(val); }
 #else
   template <class U>
-  void construct(pointer p, U&& val) {
+  TEST_CONSTEXPR_CXX14 void construct(pointer p, U&& val) {
     ::new (static_cast<void*>(p)) T(std::forward<U>(val));
   }
 #endif
-  void destroy(pointer p) { p->~T(); }
-  friend bool operator==(const test_allocator& x, const test_allocator& y) { return x.data_ == y.data_; }
-  friend bool operator!=(const test_allocator& x, const test_allocator& y) { return !(x == y); }
+  TEST_CONSTEXPR_CXX14 void destroy(pointer p) { p->~T(); }
+  TEST_CONSTEXPR friend bool operator==(const test_allocator& x, const test_allocator& y) { return x.data_ == y.data_; }
+  TEST_CONSTEXPR friend bool operator!=(const test_allocator& x, const test_allocator& y) { return !(x == y); }
 
-  int get_data() const { return data_; }
-  int get_id() const { return id_; }
+  TEST_CONSTEXPR int get_data() const { return data_; }
+  TEST_CONSTEXPR int get_id() const { return id_; }
 };
 
 template <class T>
-class non_default_test_allocator : public test_alloc_base {
-  int data_;
+class non_default_test_allocator {
+  int data_ = 0;
+  test_allocator_statistics* stats_ = nullptr;
 
   template <class U>
   friend class non_default_test_allocator;
@@ -173,59 +204,71 @@ public:
     typedef non_default_test_allocator<U> other;
   };
 
-  //    non_default_test_allocator() TEST_NOEXCEPT : data_(0) {++count;}
-  explicit non_default_test_allocator(int i) TEST_NOEXCEPT : data_(i) { ++count; }
-  non_default_test_allocator(const non_default_test_allocator& a) TEST_NOEXCEPT : data_(a.data_) { ++count; }
+  TEST_CONSTEXPR_CXX14
+  explicit non_default_test_allocator(int i, test_allocator_statistics* stats = nullptr) TEST_NOEXCEPT
+      : data_(i), stats_(stats) {
+    if (stats_ != nullptr) {
+      ++stats_->count;
+    }
+  }
+
+  TEST_CONSTEXPR_CXX14
+  non_default_test_allocator(const non_default_test_allocator& a) TEST_NOEXCEPT : data_(a.data_), stats_(a.stats_) {
+    if (stats_ != nullptr)
+      ++stats_->count;
+  }
+
   template <class U>
-  non_default_test_allocator(const non_default_test_allocator<U>& a) TEST_NOEXCEPT : data_(a.data_) {
-    ++count;
+  TEST_CONSTEXPR_CXX14 non_default_test_allocator(const non_default_test_allocator<U>& a) TEST_NOEXCEPT
+      : data_(a.data_), stats_(a.stats_) {
+    if (stats_ != nullptr)
+      ++stats_->count;
   }
-  ~non_default_test_allocator() TEST_NOEXCEPT {
-    assert(data_ >= 0);
-    --count;
-    data_ = -1;
+
+  TEST_CONSTEXPR_CXX20 ~non_default_test_allocator() TEST_NOEXCEPT {
+    assert(data_ != test_alloc_base::destructed_value);
+    if (stats_ != nullptr)
+      --stats_->count;
+    data_ = test_alloc_base::destructed_value;
   }
-  pointer address(reference x) const { return &x; }
-  const_pointer address(const_reference x) const { return &x; }
-  pointer allocate(size_type n, const void* = 0) {
-    assert(data_ >= 0);
-    if (time_to_throw >= throw_after) {
-#ifndef TEST_HAS_NO_EXCEPTIONS
-      throw std::bad_alloc();
-#else
-      std::terminate();
-#endif
+
+  TEST_CONSTEXPR pointer address(reference x) const { return &x; }
+  TEST_CONSTEXPR const_pointer address(const_reference x) const { return &x; }
+
+  TEST_CONSTEXPR_CXX20 pointer allocate(size_type n, const void* = nullptr) {
+    assert(data_ != test_alloc_base::destructed_value);
+    if (stats_ != nullptr) {
+      if (stats_->time_to_throw >= stats_->throw_after)
+        TEST_THROW(std::bad_alloc());
+      ++stats_->time_to_throw;
+      ++stats_->alloc_count;
     }
-    ++time_to_throw;
-    ++alloc_count;
-    return (pointer)::operator new(n * sizeof(T));
-  }
-  void deallocate(pointer p, size_type) {
-    assert(data_ >= 0);
-    --alloc_count;
-    ::operator delete((void*)p);
+    return std::allocator<value_type>().allocate(n);
   }
-  size_type max_size() const TEST_NOEXCEPT { return UINT_MAX / sizeof(T); }
-#if TEST_STD_VER < 11
-  void construct(pointer p, const T& val) { ::new (static_cast<void*>(p)) T(val); }
-#else
-  template <class U>
-  void construct(pointer p, U&& val) {
-    ::new (static_cast<void*>(p)) T(std::forward<U>(val));
+
+  TEST_CONSTEXPR_CXX20 void deallocate(pointer p, size_type n) {
+    assert(data_ != test_alloc_base::destructed_value);
+    if (stats_ != nullptr)
+      --stats_->alloc_count;
+    std::allocator<value_type>().deallocate(p, n);
   }
-#endif
-  void destroy(pointer p) { p->~T(); }
 
-  friend bool operator==(const non_default_test_allocator& x, const non_default_test_allocator& y) {
+  TEST_CONSTEXPR size_type max_size() const TEST_NOEXCEPT { return UINT_MAX / sizeof(T); }
+
+  TEST_CONSTEXPR friend bool operator==(const non_default_test_allocator& x, const non_default_test_allocator& y) {
     return x.data_ == y.data_;
   }
-  friend bool operator!=(const non_default_test_allocator& x, const non_default_test_allocator& y) { return !(x == y); }
+
+  TEST_CONSTEXPR friend bool operator!=(const non_default_test_allocator& x, const non_default_test_allocator& y) {
+    return !(x == y);
+  }
 };
 
 template <>
-class test_allocator<void> : public test_alloc_base {
-  int data_;
-  int id_;
+class test_allocator<void> {
+  int data_ = 0;
+  int id_ = 0;
+  test_allocator_statistics* stats_ = nullptr;
 
   template <class U>
   friend class test_allocator;
@@ -242,26 +285,46 @@ public:
     typedef test_allocator<U> other;
   };
 
-  test_allocator() TEST_NOEXCEPT : data_(0), id_(0) {}
-  explicit test_allocator(int i, int id = 0) TEST_NOEXCEPT : data_(i), id_(id) {}
-  test_allocator(const test_allocator& a) TEST_NOEXCEPT : data_(a.data_), id_(a.id_) {}
+  TEST_CONSTEXPR test_allocator() TEST_NOEXCEPT = default;
+
+  TEST_CONSTEXPR_CXX14 explicit test_allocator(test_allocator_statistics* stats) TEST_NOEXCEPT : stats_(stats) {}
+
+  TEST_CONSTEXPR explicit test_allocator(int data) TEST_NOEXCEPT : data_(data) {}
+
+  TEST_CONSTEXPR explicit test_allocator(int data, test_allocator_statistics* stats) TEST_NOEXCEPT
+      : data_(data), stats_(stats)
+  {}
+
+  TEST_CONSTEXPR explicit test_allocator(int data, int id) : data_(data), id_(id) {}
+
+  TEST_CONSTEXPR_CXX14 explicit test_allocator(int data, int id, test_allocator_statistics* stats) TEST_NOEXCEPT
+      : data_(data), id_(id), stats_(stats)
+  {}
+
+  TEST_CONSTEXPR_CXX14 explicit test_allocator(const test_allocator& a) TEST_NOEXCEPT
+      : data_(a.data_), id_(a.id_), stats_(a.stats_)
+  {}
+
   template <class U>
-  test_allocator(const test_allocator<U>& a) TEST_NOEXCEPT : data_(a.data_), id_(a.id_) {}
-  ~test_allocator() TEST_NOEXCEPT {
-    data_ = -1;
-    id_ = -1;
+  TEST_CONSTEXPR_CXX14 test_allocator(const test_allocator<U>& a) TEST_NOEXCEPT
+      : data_(a.data_), id_(a.id_), stats_(a.stats_)
+  {}
+
+  TEST_CONSTEXPR_CXX20 ~test_allocator() TEST_NOEXCEPT {
+    data_ = test_alloc_base::destructed_value;
+    id_ = test_alloc_base::destructed_value;
   }
 
-  int get_id() const { return id_; }
-  int get_data() const { return data_; }
+  TEST_CONSTEXPR int get_id() const { return id_; }
+  TEST_CONSTEXPR int get_data() const { return data_; }
 
-  friend bool operator==(const test_allocator& x, const test_allocator& y) { return x.data_ == y.data_; }
-  friend bool operator!=(const test_allocator& x, const test_allocator& y) { return !(x == y); }
+  TEST_CONSTEXPR friend bool operator==(const test_allocator& x, const test_allocator& y) { return x.data_ == y.data_; }
+  TEST_CONSTEXPR friend bool operator!=(const test_allocator& x, const test_allocator& y) { return !(x == y); }
 };
 
 template <class T>
 class other_allocator {
-  int data_;
+  int data_ = -1;
 
   template <class U>
   friend class other_allocator;
@@ -269,17 +332,22 @@ class other_allocator {
 public:
   typedef T value_type;
 
-  other_allocator() : data_(-1) {}
-  explicit other_allocator(int i) : data_(i) {}
+  TEST_CONSTEXPR_CXX14 other_allocator() {}
+  TEST_CONSTEXPR_CXX14 explicit other_allocator(int i) : data_(i) {}
+
   template <class U>
-  other_allocator(const other_allocator<U>& a) : data_(a.data_) {}
-  T* allocate(std::size_t n) { return (T*)::operator new(n * sizeof(T)); }
-  void deallocate(T* p, std::size_t) { ::operator delete((void*)p); }
+  TEST_CONSTEXPR_CXX14 other_allocator(const other_allocator<U>& a) : data_(a.data_) {}
 
-  other_allocator select_on_container_copy_construction() const { return other_allocator(-2); }
+  TEST_CONSTEXPR_CXX20 T* allocate(std::size_t n) { return std::allocator<value_type>().allocate(n); }
+  TEST_CONSTEXPR_CXX20 void deallocate(T* p, std::size_t s) { std::allocator<value_type>().deallocate(p, s); }
 
-  friend bool operator==(const other_allocator& x, const other_allocator& y) { return x.data_ == y.data_; }
-  friend bool operator!=(const other_allocator& x, const other_allocator& y) { return !(x == y); }
+  TEST_CONSTEXPR_CXX14 other_allocator select_on_container_copy_construction() const { return other_allocator(-2); }
+
+  TEST_CONSTEXPR_CXX14 friend bool operator==(const other_allocator& x, const other_allocator& y) {
+    return x.data_ == y.data_;
+  }
+
+  TEST_CONSTEXPR_CXX14 friend bool operator!=(const other_allocator& x, const other_allocator& y) { return !(x == y); }
 
   typedef std::true_type propagate_on_container_copy_assignment;
   typedef std::true_type propagate_on_container_move_assignment;
@@ -301,15 +369,15 @@ struct Tag_X {
   // All constructors must be passed the Tag type.
 
   // DefaultInsertable into vector<X, TaggingAllocator<X>>,
-  Tag_X(Ctor_Tag) {}
+  constexpr Tag_X(Ctor_Tag) {}
   // CopyInsertable into vector<X, TaggingAllocator<X>>,
-  Tag_X(Ctor_Tag, const Tag_X&) {}
+  constexpr Tag_X(Ctor_Tag, const Tag_X&) {}
   // MoveInsertable into vector<X, TaggingAllocator<X>>, and
-  Tag_X(Ctor_Tag, Tag_X&&) {}
+  constexpr Tag_X(Ctor_Tag, Tag_X&&) {}
 
   // EmplaceConstructible into vector<X, TaggingAllocator<X>> from args.
   template <typename... Args>
-  Tag_X(Ctor_Tag, Args&&...) {}
+  constexpr Tag_X(Ctor_Tag, Args&&...) {}
 
   // not DefaultConstructible, CopyConstructible or MoveConstructible.
   Tag_X() = delete;
@@ -317,15 +385,13 @@ struct Tag_X {
   Tag_X(Tag_X&&) = delete;
 
   // CopyAssignable.
-  Tag_X& operator=(const Tag_X&) { return *this; }
+  TEST_CONSTEXPR_CXX14 Tag_X& operator=(const Tag_X&) { return *this; };
 
   // MoveAssignable.
-  Tag_X& operator=(Tag_X&&) { return *this; }
+  TEST_CONSTEXPR_CXX14 Tag_X& operator=(Tag_X&&) { return *this; };
 
 private:
-  // Not Destructible.
-  ~Tag_X() {}
-
+  ~Tag_X() = default;
   // Erasable from vector<X, TaggingAllocator<X>>.
   friend class TaggingAllocator<Tag_X>;
 };
@@ -337,71 +403,109 @@ public:
   TaggingAllocator() = default;
 
   template <typename U>
-  TaggingAllocator(const TaggingAllocator<U>&) {}
-
-  T* allocate(std::size_t n) { return std::allocator<T>{}.allocate(n); }
-
-  void deallocate(T* p, std::size_t n) { std::allocator<T>{}.deallocate(p, n); }
+  constexpr TaggingAllocator(const TaggingAllocator<U>&){};
 
   template <typename... Args>
   void construct(Tag_X* p, Args&&... args) {
     ::new ((void*)p) Tag_X(Ctor_Tag{}, std::forward<Args>(args)...);
   }
 
-  template <typename U, typename... Args>
-  void construct(U* p, Args&&... args) {
-    ::new ((void*)p) U(std::forward<Args>(args)...);
-  }
-
-  template <typename U, typename... Args>
+  template <typename U>
   void destroy(U* p) {
     p->~U();
   }
-};
-
-template <typename T, typename U>
-bool operator==(const TaggingAllocator<T>&, const TaggingAllocator<U>&) {
-  return true;
-}
 
-template <typename T, typename U>
-bool operator!=(const TaggingAllocator<T>&, const TaggingAllocator<U>&) {
-  return false;
-}
+  TEST_CONSTEXPR_CXX20 T* allocate(std::size_t n) { return std::allocator<T>{}.allocate(n); }
+  TEST_CONSTEXPR_CXX20 void deallocate(T* p, std::size_t n) { std::allocator<T>{}.deallocate(p, n); }
+};
 #endif
 
 template <std::size_t MaxAllocs>
 struct limited_alloc_handle {
-  std::size_t outstanding_;
-  void* last_alloc_;
-
-  limited_alloc_handle() : outstanding_(0), last_alloc_(nullptr) {}
+  std::size_t outstanding_ = 0;
+  void* last_alloc_ = nullptr;
 
   template <class T>
-  T* allocate(std::size_t N) {
+  TEST_CONSTEXPR_CXX20 T* allocate(std::size_t N) {
     if (N + outstanding_ > MaxAllocs)
       TEST_THROW(std::bad_alloc());
-    last_alloc_ = ::operator new(N * sizeof(T));
+    last_alloc_ = std::allocator<T>().allocate(N);
     outstanding_ += N;
     return static_cast<T*>(last_alloc_);
   }
 
-  void deallocate(void* ptr, std::size_t N) {
+  template <class T>
+  TEST_CONSTEXPR_CXX20 void deallocate(T* ptr, std::size_t N) {
     if (ptr == last_alloc_) {
       last_alloc_ = nullptr;
       assert(outstanding_ >= N);
       outstanding_ -= N;
     }
-    ::operator delete(ptr);
+    std::allocator<T>().deallocate(ptr, N);
   }
 };
 
+namespace detail {
+template <class T>
+class thread_unsafe_shared_ptr {
+public:
+  thread_unsafe_shared_ptr() = default;
+
+  TEST_CONSTEXPR_CXX14 thread_unsafe_shared_ptr(const thread_unsafe_shared_ptr& other) : block(other.block) {
+    ++block->ref_count;
+  }
+
+  TEST_CONSTEXPR_CXX20 ~thread_unsafe_shared_ptr() {
+    --block->ref_count;
+    if (block->ref_count != 0)
+      return;
+    typedef std::allocator_traits<std::allocator<control_block> > allocator_traits;
+    std::allocator<control_block> alloc;
+    allocator_traits::destroy(alloc, block);
+    allocator_traits::deallocate(alloc, block, 1);
+  }
+
+  TEST_CONSTEXPR const T& operator*() const { return block->content; }
+  TEST_CONSTEXPR const T* operator->() const { return &block->content; }
+  TEST_CONSTEXPR_CXX14 T& operator*() { return block->content; }
+  TEST_CONSTEXPR_CXX14 T* operator->() { return &block->content; }
+  TEST_CONSTEXPR_CXX14 T* get() { return &block->content; }
+  TEST_CONSTEXPR const T* get() const { return &block->content; }
+
+private:
+  struct control_block {
+    template <class... Args>
+    TEST_CONSTEXPR control_block(Args... args) : content(std::forward<Args>(args)...) {}
+    size_t ref_count = 1;
+    T content;
+  };
+
+  control_block* block = nullptr;
+
+  template <class U, class... Args>
+  friend TEST_CONSTEXPR_CXX20 thread_unsafe_shared_ptr<U> make_thread_unsafe_shared(Args...);
+};
+
+template <class T, class... Args>
+TEST_CONSTEXPR_CXX20 thread_unsafe_shared_ptr<T> make_thread_unsafe_shared(Args... args) {
+  typedef typename thread_unsafe_shared_ptr<T>::control_block control_block_type;
+  typedef std::allocator_traits<std::allocator<control_block_type> > allocator_traits;
+
+  thread_unsafe_shared_ptr<T> ptr;
+  std::allocator<control_block_type> alloc;
+  ptr.block = allocator_traits::allocate(alloc, 1);
+  allocator_traits::construct(alloc, ptr.block, std::forward<Args>(args)...);
+
+  return ptr;
+}
+} // namespace detail
+
 template <class T, std::size_t N>
 class limited_allocator {
   template <class U, std::size_t UN>
   friend class limited_allocator;
   typedef limited_alloc_handle<N> BuffT;
-  std::shared_ptr<BuffT> handle_;
+  detail::thread_unsafe_shared_ptr<BuffT> handle_;
 
 public:
   typedef T value_type;
@@ -417,29 +521,28 @@ public:
     typedef limited_allocator<U, N> other;
   };
 
-  limited_allocator() : handle_(new BuffT) {}
+  TEST_CONSTEXPR_CXX20 limited_allocator() : handle_(detail::make_thread_unsafe_shared<BuffT>()) {}
 
-  limited_allocator(limited_allocator const& other) : handle_(other.handle_) {}
+  limited_allocator(limited_allocator const&) = default;
 
   template <class U>
-  explicit limited_allocator(limited_allocator<U, N> const& other) : handle_(other.handle_) {}
+  TEST_CONSTEXPR explicit limited_allocator(limited_allocator<U, N> const& other) : handle_(other.handle_) {}
 
   limited_allocator& operator=(const limited_allocator&) = delete;
 
-  pointer allocate(size_type n) { return handle_->template allocate<T>(n); }
-  void deallocate(pointer p, size_type n) { handle_->deallocate(p, n); }
-  size_type max_size() const { return N; }
-
-  BuffT* getHandle() const { return handle_.get(); }
+  TEST_CONSTEXPR_CXX20 pointer allocate(size_type n) { return handle_->template allocate<T>(n); }
+  TEST_CONSTEXPR_CXX20 void deallocate(pointer p, size_type n) { handle_->template deallocate<T>(p, n); }
+  TEST_CONSTEXPR size_type max_size() const { return N; }
+  TEST_CONSTEXPR BuffT* getHandle() const { return handle_.get(); }
 };
 
 template <class T, class U, std::size_t N>
-inline bool operator==(limited_allocator<T, N> const& LHS, limited_allocator<U, N> const& RHS) {
+TEST_CONSTEXPR inline bool operator==(limited_allocator<T, N> const& LHS, limited_allocator<U, N> const& RHS) {
   return LHS.getHandle() == RHS.getHandle();
 }
 
 template <class T, class U, std::size_t N>
-inline bool operator!=(limited_allocator<T, N> const& LHS, limited_allocator<U, N> const& RHS) {
+TEST_CONSTEXPR inline bool operator!=(limited_allocator<T, N> const& LHS, limited_allocator<U, N> const& RHS) {
   return !(LHS == RHS);
 }