[libc++] Make test_allocator constexpr-friendly for constexpr string/vector

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
This commit is contained in:
Nikolas Klauser 2021-11-07 16:11:24 +01:00 committed by Mark de Wever
parent f057756a1a
commit 9a140a1586
25 changed files with 543 additions and 418 deletions

View 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**)

View 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**) {

View File

@ -27,27 +27,28 @@
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);

View 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);

View 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);

View File

@ -20,9 +20,10 @@
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);

View File

@ -23,9 +23,10 @@
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);

View 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;

View File

@ -18,11 +18,13 @@
#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);

View 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;

View File

@ -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<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>());

View File

@ -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<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;
}

View File

@ -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<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;
}

View File

@ -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<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;
}

View File

@ -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<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;
}

View 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;
{

View File

@ -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<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;
}

View 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

View 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
{

View 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;

View 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
{

View 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;

View 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';

View 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
{

View 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;
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;
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() {
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;
}
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_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;
}
++time_to_throw;
++alloc_count;
return (pointer)::operator new(n * sizeof(T));
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;
}
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); }
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);
}
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; }
template <class U>
non_default_test_allocator(const non_default_test_allocator<U>& 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;
}
~non_default_test_allocator() TEST_NOEXCEPT {
assert(data_ >= 0);
--count;
data_ = -1;
}
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
}
++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);
}
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));
}
#endif
void destroy(pointer p) { p->~T(); }
friend bool operator==(const non_default_test_allocator& x, const non_default_test_allocator& y) {
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>
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;
}
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;
}
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;
}
return std::allocator<value_type>().allocate(n);
}
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);
}
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();
}
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); }
};
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;
}
#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);
}