blob: cf35e83310f746b012bf4727501c0e80b57953d9 [file] [log] [blame]
// { dg-do run { target c++26 } }
#include <memory>
#include <scoped_allocator>
#include <utility>
#include <vector>
#include <optional>
#include <testsuite_hooks.h>
#include <testsuite_allocator.h>
using __gnu_test::propagating_allocator;
using __gnu_test::tracker_allocator;
using Counter = __gnu_test::tracker_allocator_counter;
void
verifyNoAllocations()
{
VERIFY( Counter::get_allocation_count() == 0 );
VERIFY( Counter::get_deallocation_count() == 0 );
VERIFY( Counter::get_construct_count() == 0 );
VERIFY( Counter::get_destruct_count() == 0 );
}
template<bool Propagate>
void
test_ctor()
{
using PropAlloc = propagating_allocator<int, Propagate>;
using Vector = std::vector<int, PropAlloc>;
using ScopedAlloc = std::scoped_allocator_adaptor<
propagating_allocator<Vector, Propagate, tracker_allocator<Vector>>,
PropAlloc>;
using Indirect = std::indirect<Vector, ScopedAlloc>;
const Indirect val(std::in_place, {1, 2, 3});
std::optional<Indirect> src;
auto make = [&val, &src] -> Indirect&& {
src.emplace(std::allocator_arg, ScopedAlloc{11, 22}, val);
Counter::reset();
return std::move(*src);
};
Indirect i1(make());
VERIFY( src->valueless_after_move() );
VERIFY( *i1 == *val );
VERIFY( i1->get_allocator().get_personality() == 22 );
VERIFY( i1.get_allocator().get_personality() == 11 );
verifyNoAllocations();
Indirect i2(std::allocator_arg, ScopedAlloc{11, 22}, make());
VERIFY( src->valueless_after_move() );
VERIFY( *i2 == *val );
VERIFY( i2->get_allocator().get_personality() == 22 );
VERIFY( i2.get_allocator().get_personality() == 11 );
verifyNoAllocations();
Indirect i3(std::allocator_arg, ScopedAlloc{33, 44}, make());
// We move-from contained object
VERIFY( !src->valueless_after_move() );
VERIFY( *i3 == *val );
VERIFY( i3->get_allocator().get_personality() == 44 );
VERIFY( i3.get_allocator().get_personality() == 33 );
VERIFY( Counter::get_allocation_count() == sizeof(Vector) );
VERIFY( Counter::get_deallocation_count() == 0 );
VERIFY( Counter::get_construct_count() == 1 );
VERIFY( Counter::get_destruct_count() == 0 );
}
template<bool Propagate>
void
test_assign()
{
using PropAlloc = propagating_allocator<int, Propagate>;
using Vector = std::vector<int, PropAlloc>;
using ScopedAlloc = std::scoped_allocator_adaptor<
propagating_allocator<Vector, Propagate, tracker_allocator<Vector>>,
PropAlloc>;
using Indirect = std::indirect<Vector, ScopedAlloc>;
const Indirect val(std::in_place, {1, 2, 3});
std::optional<Indirect> src;
auto make = [&val, &src] -> Indirect&& {
src.emplace(std::allocator_arg, ScopedAlloc{11, 22}, val);
Counter::reset();
return std::move(*src);
};
Indirect i1(std::allocator_arg, ScopedAlloc{11, 22});
i1 = make();
VERIFY( src->valueless_after_move() );
VERIFY( *i1 == *val );
VERIFY( i1->get_allocator().get_personality() == 22 );
VERIFY( i1.get_allocator().get_personality() == 11 );
VERIFY( Counter::get_allocation_count() == 0 );
VERIFY( Counter::get_deallocation_count() == sizeof(Vector) );
VERIFY( Counter::get_construct_count() == 0 );
VERIFY( Counter::get_destruct_count() == 1 );
Indirect i2(std::allocator_arg, ScopedAlloc{33, 44});
i2 = make();
VERIFY( *i2 == *val );
if (Propagate)
{
VERIFY( src->valueless_after_move() );
VERIFY( i2->get_allocator().get_personality() == 22 );
VERIFY( i2.get_allocator().get_personality() == 11 );
VERIFY( Counter::get_allocation_count() == 0 );
VERIFY( Counter::get_construct_count() == 0 );
}
else
{
// We allocate new holder and move-from contained object
VERIFY( !src->valueless_after_move() );
VERIFY( i2->get_allocator().get_personality() == 44 );
VERIFY( i2.get_allocator().get_personality() == 33 );
VERIFY( Counter::get_allocation_count() == sizeof(Vector) );
VERIFY( Counter::get_construct_count() == 1 );
}
VERIFY( Counter::get_deallocation_count() == sizeof(Vector) );
VERIFY( Counter::get_destruct_count() == 1 );
Indirect i3(std::allocator_arg, ScopedAlloc{11, 22});
auto(std::move(i3));
i3 = make();
VERIFY( *i3 == *val );
VERIFY( src->valueless_after_move() );
VERIFY( i3->get_allocator().get_personality() == 22 );
VERIFY( i3.get_allocator().get_personality() == 11 );
verifyNoAllocations();
Indirect i4(std::allocator_arg, ScopedAlloc{33, 44});
auto(std::move(i4));
i4 = make();
VERIFY( *i4 == *val );
if (Propagate)
{
VERIFY( src->valueless_after_move() );
VERIFY( i4->get_allocator().get_personality() == 22 );
VERIFY( i4.get_allocator().get_personality() == 11 );
VERIFY( Counter::get_allocation_count() == 0 );
VERIFY( Counter::get_construct_count() == 0 );
}
else
{
// We allocate new holder and move-from contained object
VERIFY( !src->valueless_after_move() );
VERIFY( i4->get_allocator().get_personality() == 44 );
VERIFY( i4.get_allocator().get_personality() == 33 );
VERIFY( Counter::get_allocation_count() == sizeof(Vector) );
VERIFY( Counter::get_construct_count() == 1 );
}
VERIFY( Counter::get_deallocation_count() == 0 );
VERIFY( Counter::get_destruct_count() == 0 );
}
template<bool Propagate>
void
test_swap()
{
using PropAlloc = propagating_allocator<int, Propagate>;
using Vector = std::vector<int, PropAlloc>;
using ScopedAlloc = std::scoped_allocator_adaptor<
propagating_allocator<Vector, Propagate, tracker_allocator<Vector>>,
PropAlloc>;
using Indirect = std::indirect<Vector, ScopedAlloc>;
const Indirect val1(std::in_place, {1, 2, 3});
const Indirect val2(std::in_place, {2, 4, 6});
Indirect i1(std::allocator_arg, ScopedAlloc{11, 22}, val1);
Indirect i2(std::allocator_arg, ScopedAlloc{11, 22}, val2);
Counter::reset();
i1.swap(i2);
VERIFY( *i2 == *val1 );
VERIFY( *i1 == *val2 );
verifyNoAllocations();
auto(std::move(i1));
Counter::reset();
i1.swap(i2);
VERIFY( *i1 == *val1 );
VERIFY( i2.valueless_after_move() );
verifyNoAllocations();
if (!Propagate)
return;
Indirect i3(std::allocator_arg, ScopedAlloc{33, 44}, val2);
Counter::reset();
i1.swap(i3);
VERIFY( *i1 == *val2 );
VERIFY( i1->get_allocator().get_personality() == 44 );
VERIFY( i1.get_allocator().get_personality() == 33 );
VERIFY( *i3 == *val1 );
VERIFY( i3->get_allocator().get_personality() == 22 );
VERIFY( i3.get_allocator().get_personality() == 11 );
verifyNoAllocations();
i1.swap(i2);
VERIFY( i1.valueless_after_move() );
VERIFY( i1.get_allocator().get_personality() == 11 );
VERIFY( *i2 == *val2 );
VERIFY( i2->get_allocator().get_personality() == 44 );
VERIFY( i2.get_allocator().get_personality() == 33 );
verifyNoAllocations();
}
template<bool Propagate>
void
test_valueless()
{
using PropAlloc = propagating_allocator<int, Propagate>;
using Vector = std::vector<int, PropAlloc>;
using ScopedAlloc = std::scoped_allocator_adaptor<
propagating_allocator<Vector, Propagate, tracker_allocator<Vector>>,
PropAlloc>;
using Indirect = std::indirect<Vector, ScopedAlloc>;
auto e = [] {
Indirect res(std::allocator_arg, ScopedAlloc{11, 22});
auto(std::move(res));
Counter::reset();
return res;
};
Indirect i1(e());
VERIFY( i1.valueless_after_move() );
VERIFY( i1.get_allocator().get_personality() == 11 );
verifyNoAllocations();
Indirect i2(std::allocator_arg, ScopedAlloc{33, 44}, e());
VERIFY( i2.valueless_after_move() );
VERIFY( i2.get_allocator().get_personality() == 33 );
verifyNoAllocations();
Indirect i3(std::allocator_arg, ScopedAlloc{33, 44});
i3 = e();
VERIFY( i3.valueless_after_move() );
if (Propagate)
VERIFY( i3.get_allocator().get_personality() == 11 );
else
VERIFY( i3.get_allocator().get_personality() == 33 );
VERIFY( Counter::get_allocation_count() == 0 );
VERIFY( Counter::get_deallocation_count() == sizeof(Vector) );
VERIFY( Counter::get_construct_count() == 0 );
VERIFY( Counter::get_destruct_count() == 1 );
i2 = e();
VERIFY( i2.valueless_after_move() );
if (Propagate)
VERIFY( i2.get_allocator().get_personality() == 11 );
else
VERIFY( i2.get_allocator().get_personality() == 33 );
verifyNoAllocations();
i3.swap(i2);
VERIFY( i2.valueless_after_move() );
VERIFY( i1.valueless_after_move() );
verifyNoAllocations();
if (!Propagate)
return;
Indirect i4(std::allocator_arg, ScopedAlloc{33, 44}, e());
i4.swap(i1);
verifyNoAllocations();
}
template<bool Propagate>
void
test_all()
{
test_ctor<Propagate>();
test_assign<Propagate>();
test_swap<Propagate>();
test_valueless<Propagate>();
}
int main()
{
test_all<true>();
test_all<false>();
}