diff --git a/libcxx/test/std/containers/associative/map/map.cons/assign_initializer_list.pass.cpp b/libcxx/test/std/containers/associative/map/map.cons/assign_initializer_list.pass.cpp --- a/libcxx/test/std/containers/associative/map/map.cons/assign_initializer_list.pass.cpp +++ b/libcxx/test/std/containers/associative/map/map.cons/assign_initializer_list.pass.cpp @@ -74,17 +74,18 @@ void duplicate_keys_test() { + test_allocator_statistics alloc_stats; typedef std::map, test_allocator > > 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(), test_allocator >(&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**) diff --git a/libcxx/test/std/containers/associative/set/set.cons/assign_initializer_list.pass.cpp b/libcxx/test/std/containers/associative/set/set.cons/assign_initializer_list.pass.cpp --- a/libcxx/test/std/containers/associative/set/set.cons/assign_initializer_list.pass.cpp +++ b/libcxx/test/std/containers/associative/set/set.cons/assign_initializer_list.pass.cpp @@ -55,17 +55,18 @@ } void duplicate_keys_test() { + test_allocator_statistics alloc_stats; typedef std::set, test_allocator > 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(), test_allocator(&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**) { diff --git a/libcxx/test/std/containers/container.requirements/container.requirements.general/allocator_move.pass.cpp b/libcxx/test/std/containers/container.requirements/container.requirements.general/allocator_move.pass.cpp --- a/libcxx/test/std/containers/container.requirements/container.requirements.general/allocator_move.pass.cpp +++ b/libcxx/test/std/containers/container.requirements/container.requirements.general/allocator_move.pass.cpp @@ -27,27 +27,28 @@ template 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); diff --git a/libcxx/test/std/containers/sequences/deque/deque.modifiers/push_back_exception_safety.pass.cpp b/libcxx/test/std/containers/sequences/deque/deque.modifiers/push_back_exception_safety.pass.cpp --- a/libcxx/test/std/containers/sequences/deque/deque.modifiers/push_back_exception_safety.pass.cpp +++ b/libcxx/test/std/containers/sequences/deque/deque.modifiers/push_back_exception_safety.pass.cpp @@ -86,11 +86,12 @@ } { + test_allocator_statistics alloc_stats; typedef std::deque > C; - C vec; - C vec2(vec); + C vec((test_allocator(&alloc_stats))); + C vec2(vec, test_allocator(&alloc_stats)); - C::allocator_type::throw_after = 1; + alloc_stats.throw_after = 1; try { vec.push_back(instance); assert(false); diff --git a/libcxx/test/std/containers/sequences/deque/deque.modifiers/push_front_exception_safety.pass.cpp b/libcxx/test/std/containers/sequences/deque/deque.modifiers/push_front_exception_safety.pass.cpp --- a/libcxx/test/std/containers/sequences/deque/deque.modifiers/push_front_exception_safety.pass.cpp +++ b/libcxx/test/std/containers/sequences/deque/deque.modifiers/push_front_exception_safety.pass.cpp @@ -86,11 +86,12 @@ } { + test_allocator_statistics alloc_stats; typedef std::deque > C; - C vec; - C vec2(vec); + C vec((test_allocator(&alloc_stats))); + C vec2(vec, test_allocator(&alloc_stats)); - C::allocator_type::throw_after = 1; + alloc_stats.throw_after = 1; try { vec.push_front(instance); assert(false); diff --git a/libcxx/test/std/containers/sequences/vector.bool/move.pass.cpp b/libcxx/test/std/containers/sequences/vector.bool/move.pass.cpp --- a/libcxx/test/std/containers/sequences/vector.bool/move.pass.cpp +++ b/libcxx/test/std/containers/sequences/vector.bool/move.pass.cpp @@ -20,9 +20,10 @@ int main(int, char**) { + test_allocator_statistics alloc_stats; { - std::vector > l(test_allocator(5)); - std::vector > lo(test_allocator(5)); + std::vector > l(test_allocator(5, &alloc_stats)); + std::vector > lo(test_allocator(5, &alloc_stats)); for (int i = 1; i <= 3; ++i) { l.push_back(true); @@ -60,24 +61,24 @@ assert(l2.get_allocator() == lo.get_allocator()); } { - test_alloc_base::clear(); + alloc_stats.clear(); using Vect = std::vector >; using AllocT = Vect::allocator_type; - Vect v(test_allocator(42, 101)); - assert(test_alloc_base::count == 1); + Vect v(test_allocator(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); diff --git a/libcxx/test/std/containers/sequences/vector/vector.cons/move.pass.cpp b/libcxx/test/std/containers/sequences/vector/vector.cons/move.pass.cpp --- a/libcxx/test/std/containers/sequences/vector/vector.cons/move.pass.cpp +++ b/libcxx/test/std/containers/sequences/vector/vector.cons/move.pass.cpp @@ -23,9 +23,10 @@ int main(int, char**) { + test_allocator_statistics alloc_stats; { - std::vector > l(test_allocator(5)); - std::vector > lo(test_allocator(5)); + std::vector > l(test_allocator(5, &alloc_stats)); + std::vector > lo(test_allocator(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 @@ assert(is_contiguous_container_asan_correct(c2)); } { - test_alloc_base::clear(); + alloc_stats.clear(); using Vect = std::vector >; - Vect v(test_allocator(42, 101)); - assert(test_alloc_base::count == 1); - assert(test_alloc_base::copied == 1); - assert(test_alloc_base::moved == 0); + Vect v(test_allocator(42, 101, &alloc_stats)); + assert(alloc_stats.count == 1); + assert(alloc_stats.copied == 1); + assert(alloc_stats.moved == 0); { const test_allocator& 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& a = v.get_allocator(); assert(a.get_id() == test_alloc_base::moved_value); diff --git a/libcxx/test/std/re/re.results/re.results.const/move.pass.cpp b/libcxx/test/std/re/re.results/re.results.const/move.pass.cpp --- a/libcxx/test/std/re/re.results/re.results.const/move.pass.cpp +++ b/libcxx/test/std/re/re.results/re.results.const/move.pass.cpp @@ -37,16 +37,17 @@ int main(int, char**) { + test_allocator_statistics alloc_stats; test (std::allocator >()); #ifndef TEST_HAS_NO_WIDE_CHARACTERS test(std::allocator >()); #endif - test (test_allocator >(3)); - assert(test_alloc_base::moved == 1); + test (test_allocator >(3, &alloc_stats)); + assert(alloc_stats.moved == 1); #ifndef TEST_HAS_NO_WIDE_CHARACTERS - test(test_allocator >(3)); - assert(test_alloc_base::moved == 2); + test(test_allocator >(3, &alloc_stats)); + assert(alloc_stats.moved == 2); #endif return 0; diff --git a/libcxx/test/std/strings/basic.string/string.capacity/capacity.pass.cpp b/libcxx/test/std/strings/basic.string/string.capacity/capacity.pass.cpp --- a/libcxx/test/std/strings/basic.string/string.capacity/capacity.pass.cpp +++ b/libcxx/test/std/strings/basic.string/string.capacity/capacity.pass.cpp @@ -18,11 +18,13 @@ #include "test_macros.h" +test_allocator_statistics alloc_stats; + template 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 @@ assert(false); } #endif - S::allocator_type::throw_after = INT_MAX; + alloc_stats.throw_after = INT_MAX; } int main(int, char**) { { typedef std::basic_string, test_allocator > S; - S s; + S s((test_allocator(&alloc_stats))); test(s); s.assign(10, 'a'); s.erase(5); diff --git a/libcxx/test/std/strings/basic.string/string.cons/move_alloc.pass.cpp b/libcxx/test/std/strings/basic.string/string.cons/move_alloc.pass.cpp --- a/libcxx/test/std/strings/basic.string/string.cons/move_alloc.pass.cpp +++ b/libcxx/test/std/strings/basic.string/string.cons/move_alloc.pass.cpp @@ -19,7 +19,6 @@ #include "test_allocator.h" #include "min_allocator.h" - template void test(S s0, const typename S::allocator_type& a) @@ -33,9 +32,9 @@ assert(s2.get_allocator() == a); } - int main(int, char**) { + test_allocator_statistics alloc_stats; { typedef test_allocator A; typedef std::basic_string, A> S; @@ -44,12 +43,12 @@ #elif TEST_STD_VER >= 11 static_assert((noexcept(S()) == std::is_nothrow_move_constructible::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 A; typedef std::basic_string, A> S; @@ -58,10 +57,10 @@ #elif TEST_STD_VER >= 11 static_assert((noexcept(S()) == std::is_nothrow_move_constructible::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 A; typedef std::basic_string, A> S; diff --git a/libcxx/test/std/thread/futures/futures.promise/alloc_ctor.pass.cpp b/libcxx/test/std/thread/futures/futures.promise/alloc_ctor.pass.cpp --- a/libcxx/test/std/thread/futures/futures.promise/alloc_ctor.pass.cpp +++ b/libcxx/test/std/thread/futures/futures.promise/alloc_ctor.pass.cpp @@ -25,31 +25,32 @@ int main(int, char**) { - assert(test_alloc_base::alloc_count == 0); + test_allocator_statistics alloc_stats; + assert(alloc_stats.alloc_count == 0); { - std::promise p(std::allocator_arg, test_allocator(42)); - assert(test_alloc_base::alloc_count == 1); + std::promise p(std::allocator_arg, test_allocator(42, &alloc_stats)); + assert(alloc_stats.alloc_count == 1); std::future 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 p(std::allocator_arg, test_allocator(42)); - assert(test_alloc_base::alloc_count == 1); + std::promise p(std::allocator_arg, test_allocator(42, &alloc_stats)); + assert(alloc_stats.alloc_count == 1); std::future 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 p(std::allocator_arg, test_allocator(42)); - assert(test_alloc_base::alloc_count == 1); + std::promise p(std::allocator_arg, test_allocator(42, &alloc_stats)); + assert(alloc_stats.alloc_count == 1); std::future 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 p(std::allocator_arg, bare_allocator()); diff --git a/libcxx/test/std/thread/futures/futures.promise/move_assign.pass.cpp b/libcxx/test/std/thread/futures/futures.promise/move_assign.pass.cpp --- a/libcxx/test/std/thread/futures/futures.promise/move_assign.pass.cpp +++ b/libcxx/test/std/thread/futures/futures.promise/move_assign.pass.cpp @@ -23,15 +23,16 @@ int main(int, char**) { - assert(test_alloc_base::alloc_count == 0); + test_allocator_statistics alloc_stats; + assert(alloc_stats.alloc_count == 0); { - std::promise p0(std::allocator_arg, test_allocator()); - std::promise p(std::allocator_arg, test_allocator()); - assert(test_alloc_base::alloc_count == 2); + std::promise p0(std::allocator_arg, test_allocator(&alloc_stats)); + std::promise p(std::allocator_arg, test_allocator(&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 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 @@ 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 p0(std::allocator_arg, test_allocator()); - std::promise p(std::allocator_arg, test_allocator()); - assert(test_alloc_base::alloc_count == 2); + std::promise p0(std::allocator_arg, test_allocator(&alloc_stats)); + std::promise p(std::allocator_arg, test_allocator(&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 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 @@ 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 p0(std::allocator_arg, test_allocator()); - std::promise p(std::allocator_arg, test_allocator()); - assert(test_alloc_base::alloc_count == 2); + std::promise p0(std::allocator_arg, test_allocator(&alloc_stats)); + std::promise p(std::allocator_arg, test_allocator(&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 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 @@ 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; } diff --git a/libcxx/test/std/thread/futures/futures.promise/move_ctor.pass.cpp b/libcxx/test/std/thread/futures/futures.promise/move_ctor.pass.cpp --- a/libcxx/test/std/thread/futures/futures.promise/move_ctor.pass.cpp +++ b/libcxx/test/std/thread/futures/futures.promise/move_ctor.pass.cpp @@ -23,13 +23,14 @@ int main(int, char**) { - assert(test_alloc_base::alloc_count == 0); + test_allocator_statistics alloc_stats; + assert(alloc_stats.alloc_count == 0); { - std::promise p0(std::allocator_arg, test_allocator()); + std::promise p0(std::allocator_arg, test_allocator(&alloc_stats)); std::promise p(std::move(p0)); - assert(test_alloc_base::alloc_count == 1); + assert(alloc_stats.alloc_count == 1); std::future 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 @@ { 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 p0(std::allocator_arg, test_allocator()); + std::promise p0(std::allocator_arg, test_allocator(&alloc_stats)); std::promise p(std::move(p0)); - assert(test_alloc_base::alloc_count == 1); + assert(alloc_stats.alloc_count == 1); std::future 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 @@ { 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 p0(std::allocator_arg, test_allocator()); + std::promise p0(std::allocator_arg, test_allocator(&alloc_stats)); std::promise p(std::move(p0)); - assert(test_alloc_base::alloc_count == 1); + assert(alloc_stats.alloc_count == 1); std::future 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 @@ { 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; } diff --git a/libcxx/test/std/thread/futures/futures.promise/swap.pass.cpp b/libcxx/test/std/thread/futures/futures.promise/swap.pass.cpp --- a/libcxx/test/std/thread/futures/futures.promise/swap.pass.cpp +++ b/libcxx/test/std/thread/futures/futures.promise/swap.pass.cpp @@ -25,63 +25,64 @@ int main(int, char**) { - assert(test_alloc_base::alloc_count == 0); + test_allocator_statistics alloc_stats; + assert(alloc_stats.alloc_count == 0); { - std::promise p0(std::allocator_arg, test_allocator()); - std::promise p(std::allocator_arg, test_allocator()); - assert(test_alloc_base::alloc_count == 2); + std::promise p0(std::allocator_arg, test_allocator(&alloc_stats)); + std::promise p(std::allocator_arg, test_allocator(&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 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 p0(std::allocator_arg, test_allocator()); - std::promise p(std::allocator_arg, test_allocator()); - assert(test_alloc_base::alloc_count == 2); + std::promise p0(std::allocator_arg, test_allocator(&alloc_stats)); + std::promise p(std::allocator_arg, test_allocator(&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 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 p0(std::allocator_arg, test_allocator()); + std::promise p0(std::allocator_arg, test_allocator(&alloc_stats)); std::promise 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 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 p0(std::allocator_arg, test_allocator()); + std::promise p0(std::allocator_arg, test_allocator(&alloc_stats)); std::promise 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 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; } diff --git a/libcxx/test/std/thread/futures/futures.shared_future/dtor.pass.cpp b/libcxx/test/std/thread/futures/futures.shared_future/dtor.pass.cpp --- a/libcxx/test/std/thread/futures/futures.shared_future/dtor.pass.cpp +++ b/libcxx/test/std/thread/futures/futures.shared_future/dtor.pass.cpp @@ -24,49 +24,50 @@ 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 f; { - std::promise p(std::allocator_arg, test_allocator()); - assert(test_alloc_base::alloc_count == 1); + std::promise p(std::allocator_arg, test_allocator(&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 f; { - std::promise p(std::allocator_arg, test_allocator()); - assert(test_alloc_base::alloc_count == 1); + std::promise p(std::allocator_arg, test_allocator(&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 f; { - std::promise p(std::allocator_arg, test_allocator()); - assert(test_alloc_base::alloc_count == 1); + std::promise p(std::allocator_arg, test_allocator(&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; } diff --git a/libcxx/test/std/thread/futures/futures.task/futures.task.members/ctor_func_alloc.pass.cpp b/libcxx/test/std/thread/futures/futures.task/futures.task.members/ctor_func_alloc.pass.cpp --- a/libcxx/test/std/thread/futures/futures.task/futures.task.members/ctor_func_alloc.pass.cpp +++ b/libcxx/test/std/thread/futures/futures.task/futures.task.members/ctor_func_alloc.pass.cpp @@ -47,10 +47,11 @@ int main(int, char**) { + test_allocator_statistics alloc_stats; { std::packaged_task p(std::allocator_arg, - test_allocator(), A(5)); - assert(test_alloc_base::alloc_count > 0); + test_allocator(&alloc_stats), A(5)); + assert(alloc_stats.alloc_count > 0); assert(p.valid()); std::future f = p.get_future(); p(3, 'a'); @@ -58,14 +59,14 @@ 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 p(std::allocator_arg, - test_allocator(), a); - assert(test_alloc_base::alloc_count > 0); + test_allocator(&alloc_stats), a); + assert(alloc_stats.alloc_count > 0); assert(p.valid()); std::future f = p.get_future(); p(3, 'a'); @@ -73,31 +74,31 @@ 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 p(std::allocator_arg, test_allocator(), &func); - assert(test_alloc_base::alloc_count > 0); + std::packaged_task p(std::allocator_arg, test_allocator(&alloc_stats), &func); + assert(alloc_stats.alloc_count > 0); assert(p.valid()); std::future 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 p(std::allocator_arg, test_allocator(), func); - assert(test_alloc_base::alloc_count > 0); + std::packaged_task p(std::allocator_arg, test_allocator(&alloc_stats), func); + assert(alloc_stats.alloc_count > 0); assert(p.valid()); std::future 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; { diff --git a/libcxx/test/std/thread/futures/futures.unique_future/dtor.pass.cpp b/libcxx/test/std/thread/futures/futures.unique_future/dtor.pass.cpp --- a/libcxx/test/std/thread/futures/futures.unique_future/dtor.pass.cpp +++ b/libcxx/test/std/thread/futures/futures.unique_future/dtor.pass.cpp @@ -24,49 +24,50 @@ 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 f; { - std::promise p(std::allocator_arg, test_allocator()); - assert(test_alloc_base::alloc_count == 1); + std::promise p(std::allocator_arg, test_allocator(&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 f; { - std::promise p(std::allocator_arg, test_allocator()); - assert(test_alloc_base::alloc_count == 1); + std::promise p(std::allocator_arg, test_allocator(&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 f; { - std::promise p(std::allocator_arg, test_allocator()); - assert(test_alloc_base::alloc_count == 1); + std::promise p(std::allocator_arg, test_allocator(&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; } diff --git a/libcxx/test/std/utilities/function.objects/func.wrap/func.wrap.func/func.wrap.func.con/alloc_F.pass.cpp b/libcxx/test/std/utilities/function.objects/func.wrap/func.wrap.func/func.wrap.func.con/alloc_F.pass.cpp --- a/libcxx/test/std/utilities/function.objects/func.wrap/func.wrap.func/func.wrap.func.con/alloc_F.pass.cpp +++ b/libcxx/test/std/utilities/function.objects/func.wrap/func.wrap.func/func.wrap.func.con/alloc_F.pass.cpp @@ -25,7 +25,6 @@ #include "count_new.h" #include "../function_types.h" - #if TEST_STD_VER >= 11 struct RValueCallable { template @@ -69,7 +68,7 @@ std::function 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()); assert(*f2.template target() == target); assert(f2.template target() == 0); @@ -86,7 +85,7 @@ TargetType target = &MemFunClass::foo; assert(globalMemCounter.checkOutstandingNewEq(0)); std::function 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()); assert(*f2.template target() == target); assert(f2.template target() == 0); @@ -113,13 +112,14 @@ int main(int, char**) { + test_allocator_statistics alloc_stats; globalMemCounter.reset(); { bare_allocator bare_alloc; test_for_alloc(bare_alloc); } { - non_default_test_allocator non_default_alloc(42); + non_default_test_allocator non_default_alloc(42, &alloc_stats); test_for_alloc(non_default_alloc); } #if TEST_STD_VER >= 11 diff --git a/libcxx/test/std/utilities/memory/util.smartptr/util.smartptr.shared/util.smartptr.shared.const/nullptr_t_deleter_allocator.pass.cpp b/libcxx/test/std/utilities/memory/util.smartptr/util.smartptr.shared/util.smartptr.shared.const/nullptr_t_deleter_allocator.pass.cpp --- a/libcxx/test/std/utilities/memory/util.smartptr/util.smartptr.shared/util.smartptr.shared.const/nullptr_t_deleter_allocator.pass.cpp +++ b/libcxx/test/std/utilities/memory/util.smartptr/util.smartptr.shared/util.smartptr.shared.const/nullptr_t_deleter_allocator.pass.cpp @@ -30,8 +30,9 @@ int main(int, char**) { + test_allocator_statistics alloc_stats; { - std::shared_ptr p(nullptr, test_deleter(3), test_allocator(5)); + std::shared_ptr p(nullptr, test_deleter(3), test_allocator(5, &alloc_stats)); assert(A::count == 0); assert(p.use_count() == 1); assert(p.get() == 0); @@ -42,14 +43,14 @@ assert(d); assert(d->state() == 3); #endif - assert(test_allocator::count == 1); - assert(test_allocator::alloc_count == 1); + assert(alloc_stats.count == 1); + assert(alloc_stats.alloc_count == 1); } assert(A::count == 0); assert(test_deleter::count == 0); assert(test_deleter::dealloc_count == 1); - assert(test_allocator::count == 0); - assert(test_allocator::alloc_count == 0); + assert(alloc_stats.count == 0); + assert(alloc_stats.alloc_count == 0); test_deleter::dealloc_count = 0; // Test an allocator with a minimal interface { diff --git a/libcxx/test/std/utilities/memory/util.smartptr/util.smartptr.shared/util.smartptr.shared.const/nullptr_t_deleter_allocator_throw.pass.cpp b/libcxx/test/std/utilities/memory/util.smartptr/util.smartptr.shared/util.smartptr.shared.const/nullptr_t_deleter_allocator_throw.pass.cpp --- a/libcxx/test/std/utilities/memory/util.smartptr/util.smartptr.shared/util.smartptr.shared.const/nullptr_t_deleter_allocator_throw.pass.cpp +++ b/libcxx/test/std/utilities/memory/util.smartptr/util.smartptr.shared/util.smartptr.shared.const/nullptr_t_deleter_allocator_throw.pass.cpp @@ -30,10 +30,11 @@ int main(int, char**) { + test_allocator_statistics alloc_stats; try { - test_allocator::throw_after = 0; - std::shared_ptr p(nullptr, test_deleter(3), test_allocator(5)); + alloc_stats.throw_after = 0; + std::shared_ptr p(nullptr, test_deleter(3), test_allocator(5, &alloc_stats)); assert(false); } catch (std::bad_alloc&) @@ -41,8 +42,8 @@ assert(A::count == 0); assert(test_deleter::count == 0); assert(test_deleter::dealloc_count == 1); - assert(test_allocator::count == 0); - assert(test_allocator::alloc_count == 0); + assert(alloc_stats.count == 0); + assert(alloc_stats.alloc_count == 0); } return 0; diff --git a/libcxx/test/std/utilities/memory/util.smartptr/util.smartptr.shared/util.smartptr.shared.const/pointer_deleter_allocator.pass.cpp b/libcxx/test/std/utilities/memory/util.smartptr/util.smartptr.shared/util.smartptr.shared.const/pointer_deleter_allocator.pass.cpp --- a/libcxx/test/std/utilities/memory/util.smartptr/util.smartptr.shared/util.smartptr.shared.const/pointer_deleter_allocator.pass.cpp +++ b/libcxx/test/std/utilities/memory/util.smartptr/util.smartptr.shared/util.smartptr.shared.const/pointer_deleter_allocator.pass.cpp @@ -62,9 +62,10 @@ int main(int, char**) { + test_allocator_statistics alloc_stats; { A* ptr = new A; - std::shared_ptr p(ptr, test_deleter(3), test_allocator(5)); + std::shared_ptr p(ptr, test_deleter(3), test_allocator(5, &alloc_stats)); assert(A::count == 1); assert(p.use_count() == 1); assert(p.get() == ptr); @@ -75,14 +76,14 @@ assert(d); assert(d->state() == 3); #endif - assert(test_allocator::count == 1); - assert(test_allocator::alloc_count == 1); + assert(alloc_stats.count == 1); + assert(alloc_stats.alloc_count == 1); } assert(A::count == 0); assert(test_deleter::count == 0); assert(test_deleter::dealloc_count == 1); - assert(test_allocator::count == 0); - assert(test_allocator::alloc_count == 0); + assert(alloc_stats.count == 0); + assert(alloc_stats.alloc_count == 0); test_deleter::dealloc_count = 0; // Test an allocator with a minimal interface { diff --git a/libcxx/test/std/utilities/memory/util.smartptr/util.smartptr.shared/util.smartptr.shared.const/pointer_deleter_allocator_throw.pass.cpp b/libcxx/test/std/utilities/memory/util.smartptr/util.smartptr.shared/util.smartptr.shared.const/pointer_deleter_allocator_throw.pass.cpp --- a/libcxx/test/std/utilities/memory/util.smartptr/util.smartptr.shared/util.smartptr.shared.const/pointer_deleter_allocator_throw.pass.cpp +++ b/libcxx/test/std/utilities/memory/util.smartptr/util.smartptr.shared/util.smartptr.shared.const/pointer_deleter_allocator_throw.pass.cpp @@ -30,20 +30,21 @@ int main(int, char**) { + test_allocator_statistics alloc_stats; A* ptr = new A; try { - test_allocator::throw_after = 0; - std::shared_ptr p(ptr, test_deleter(3), test_allocator(5)); + alloc_stats.throw_after = 0; + std::shared_ptr p(ptr, test_deleter(3), test_allocator(5, &alloc_stats)); assert(false); } catch (std::bad_alloc&) { - assert(A::count == 0); - assert(test_deleter::count == 0); + assert(alloc_stats.count == 0); + assert(alloc_stats.count == 0); assert(test_deleter::dealloc_count == 1); - assert(test_allocator::count == 0); - assert(test_allocator::alloc_count == 0); + assert(alloc_stats.count == 0); + assert(alloc_stats.alloc_count == 0); } return 0; diff --git a/libcxx/test/std/utilities/memory/util.smartptr/util.smartptr.shared/util.smartptr.shared.create/allocate_shared.pass.cpp b/libcxx/test/std/utilities/memory/util.smartptr/util.smartptr.shared/util.smartptr.shared.create/allocate_shared.pass.cpp --- a/libcxx/test/std/utilities/memory/util.smartptr/util.smartptr.shared/util.smartptr.shared.create/allocate_shared.pass.cpp +++ b/libcxx/test/std/utilities/memory/util.smartptr/util.smartptr.shared/util.smartptr.shared.create/allocate_shared.pass.cpp @@ -141,17 +141,18 @@ test >(); test >(); + test_allocator_statistics alloc_stats; { int i = 67; char c = 'e'; - std::shared_ptr p = std::allocate_shared(test_allocator(54), i, c); - assert(test_allocator::alloc_count == 1); + std::shared_ptr p = std::allocate_shared(test_allocator(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::alloc_count == 0); + assert(alloc_stats.alloc_count == 0); { int i = 67; char c = 'e'; diff --git a/libcxx/test/std/utilities/memory/util.smartptr/util.smartptr.shared/util.smartptr.shared.mod/reset_pointer_deleter_allocator.pass.cpp b/libcxx/test/std/utilities/memory/util.smartptr/util.smartptr.shared/util.smartptr.shared.mod/reset_pointer_deleter_allocator.pass.cpp --- a/libcxx/test/std/utilities/memory/util.smartptr/util.smartptr.shared/util.smartptr.shared.mod/reset_pointer_deleter_allocator.pass.cpp +++ b/libcxx/test/std/utilities/memory/util.smartptr/util.smartptr.shared/util.smartptr.shared.mod/reset_pointer_deleter_allocator.pass.cpp @@ -43,10 +43,11 @@ int main(int, char**) { + test_allocator_statistics alloc_stats; { std::shared_ptr p(new B); A* ptr = new A; - p.reset(ptr, test_deleter(3), test_allocator(4)); + p.reset(ptr, test_deleter(3), test_allocator(4, &alloc_stats)); assert(A::count == 1); assert(B::count == 1); assert(p.use_count() == 1); @@ -58,18 +59,18 @@ assert(d); assert(d->state() == 3); #endif - assert(test_allocator::count == 1); - assert(test_allocator::alloc_count == 1); + assert(alloc_stats.count == 1); + assert(alloc_stats.alloc_count == 1); } assert(A::count == 0); assert(test_deleter::count == 0); assert(test_deleter::dealloc_count == 1); - assert(test_allocator::count == 0); - assert(test_allocator::alloc_count == 0); + assert(alloc_stats.count == 0); + assert(alloc_stats.alloc_count == 0); { std::shared_ptr p; A* ptr = new A; - p.reset(ptr, test_deleter(3), test_allocator(4)); + p.reset(ptr, test_deleter(3), test_allocator(4, &alloc_stats)); assert(A::count == 1); assert(B::count == 1); assert(p.use_count() == 1); @@ -81,14 +82,14 @@ assert(d); assert(d->state() == 3); #endif - assert(test_allocator::count == 1); - assert(test_allocator::alloc_count == 1); + assert(alloc_stats.count == 1); + assert(alloc_stats.alloc_count == 1); } assert(A::count == 0); assert(test_deleter::count == 0); assert(test_deleter::dealloc_count == 2); - assert(test_allocator::count == 0); - assert(test_allocator::alloc_count == 0); + assert(alloc_stats.count == 0); + assert(alloc_stats.alloc_count == 0); #if TEST_STD_VER > 14 { diff --git a/libcxx/test/support/test_allocator.h b/libcxx/test/support/test_allocator.h --- a/libcxx/test/support/test_allocator.h +++ b/libcxx/test/support/test_allocator.h @@ -26,23 +26,16 @@ 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 @@ 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 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 friend class test_allocator; @@ -87,74 +79,113 @@ typedef test_allocator 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 - test_allocator(const test_allocator& a) TEST_NOEXCEPT : data_(a.data_), id_(a.id_) { - ++count; - ++converted; + TEST_CONSTEXPR_CXX14 test_allocator(const test_allocator& 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().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().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(p)) T(val); } #else template - void construct(pointer p, U&& val) { + TEST_CONSTEXPR_CXX14 void construct(pointer p, U&& val) { ::new (static_cast(p)) T(std::forward(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 non_default_test_allocator : public test_alloc_base { - int data_; +class non_default_test_allocator { + int data_ = 0; + test_allocator_statistics* stats_ = nullptr; template friend class non_default_test_allocator; @@ -173,59 +204,71 @@ typedef non_default_test_allocator 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 - non_default_test_allocator(const non_default_test_allocator& a) TEST_NOEXCEPT : data_(a.data_) { - ++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; } - ~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().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(p)) T(val); } -#else - template - void construct(pointer p, U&& val) { - ::new (static_cast(p)) T(std::forward(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().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 : public test_alloc_base { - int data_; - int id_; +class test_allocator { + int data_ = 0; + int id_ = 0; + test_allocator_statistics* stats_ = nullptr; template friend class test_allocator; @@ -242,26 +285,46 @@ typedef test_allocator 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 - test_allocator(const test_allocator& 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& 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 other_allocator { - int data_; + int data_ = -1; template friend class other_allocator; @@ -269,17 +332,22 @@ 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 - other_allocator(const other_allocator& 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& 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().allocate(n); } + TEST_CONSTEXPR_CXX20 void deallocate(T* p, std::size_t s) { std::allocator().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 @@ // All constructors must be passed the Tag type. // DefaultInsertable into vector>, - Tag_X(Ctor_Tag) {} + constexpr Tag_X(Ctor_Tag) {} // CopyInsertable into vector>, - Tag_X(Ctor_Tag, const Tag_X&) {} + constexpr Tag_X(Ctor_Tag, const Tag_X&) {} // MoveInsertable into vector>, and - Tag_X(Ctor_Tag, Tag_X&&) {} + constexpr Tag_X(Ctor_Tag, Tag_X&&) {} // EmplaceConstructible into vector> from args. template - Tag_X(Ctor_Tag, Args&&...) {} + constexpr Tag_X(Ctor_Tag, Args&&...) {} // not DefaultConstructible, CopyConstructible or MoveConstructible. Tag_X() = delete; @@ -317,15 +385,13 @@ 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>. friend class TaggingAllocator; }; @@ -337,71 +403,109 @@ TaggingAllocator() = default; template - TaggingAllocator(const TaggingAllocator&) {} - - T* allocate(std::size_t n) { return std::allocator{}.allocate(n); } - - void deallocate(T* p, std::size_t n) { std::allocator{}.deallocate(p, n); } + constexpr TaggingAllocator(const TaggingAllocator&){}; template void construct(Tag_X* p, Args&&... args) { ::new ((void*)p) Tag_X(Ctor_Tag{}, std::forward(args)...); } - template - void construct(U* p, Args&&... args) { - ::new ((void*)p) U(std::forward(args)...); - } - - template + template void destroy(U* p) { p->~U(); } -}; - -template -bool operator==(const TaggingAllocator&, const TaggingAllocator&) { - return true; -} -template -bool operator!=(const TaggingAllocator&, const TaggingAllocator&) { - return false; -} + TEST_CONSTEXPR_CXX20 T* allocate(std::size_t n) { return std::allocator{}.allocate(n); } + TEST_CONSTEXPR_CXX20 void deallocate(T* p, std::size_t n) { std::allocator{}.deallocate(p, n); } +}; #endif template 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 - 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().allocate(N); outstanding_ += N; return static_cast(last_alloc_); } - void deallocate(void* ptr, std::size_t N) { + template + 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().deallocate(ptr, N); } }; +namespace detail { +template +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 > allocator_traits; + std::allocator 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 + TEST_CONSTEXPR control_block(Args... args) : content(std::forward(args)...) {} + size_t ref_count = 1; + T content; + }; + + control_block* block = nullptr; + + template + friend TEST_CONSTEXPR_CXX20 thread_unsafe_shared_ptr make_thread_unsafe_shared(Args...); +}; + +template +TEST_CONSTEXPR_CXX20 thread_unsafe_shared_ptr make_thread_unsafe_shared(Args... args) { + typedef typename thread_unsafe_shared_ptr::control_block control_block_type; + typedef std::allocator_traits > allocator_traits; + + thread_unsafe_shared_ptr ptr; + std::allocator alloc; + ptr.block = allocator_traits::allocate(alloc, 1); + allocator_traits::construct(alloc, ptr.block, std::forward(args)...); + + return ptr; +} +} // namespace detail + template class limited_allocator { template friend class limited_allocator; typedef limited_alloc_handle BuffT; - std::shared_ptr handle_; + detail::thread_unsafe_shared_ptr handle_; public: typedef T value_type; @@ -417,29 +521,28 @@ typedef limited_allocator other; }; - limited_allocator() : handle_(new BuffT) {} + TEST_CONSTEXPR_CXX20 limited_allocator() : handle_(detail::make_thread_unsafe_shared()) {} - limited_allocator(limited_allocator const& other) : handle_(other.handle_) {} + limited_allocator(limited_allocator const&) = default; template - explicit limited_allocator(limited_allocator const& other) : handle_(other.handle_) {} + TEST_CONSTEXPR explicit limited_allocator(limited_allocator const& other) : handle_(other.handle_) {} limited_allocator& operator=(const limited_allocator&) = delete; - pointer allocate(size_type n) { return handle_->template allocate(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(n); } + TEST_CONSTEXPR_CXX20 void deallocate(pointer p, size_type n) { handle_->template deallocate(p, n); } + TEST_CONSTEXPR size_type max_size() const { return N; } + TEST_CONSTEXPR BuffT* getHandle() const { return handle_.get(); } }; template -inline bool operator==(limited_allocator const& LHS, limited_allocator const& RHS) { +TEST_CONSTEXPR inline bool operator==(limited_allocator const& LHS, limited_allocator const& RHS) { return LHS.getHandle() == RHS.getHandle(); } template -inline bool operator!=(limited_allocator const& LHS, limited_allocator const& RHS) { +TEST_CONSTEXPR inline bool operator!=(limited_allocator const& LHS, limited_allocator const& RHS) { return !(LHS == RHS); }