// { dg-do run { target c++26 } } #include #include #include #include #include #include #include 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 void test_ctor() { using PropAlloc = propagating_allocator; using Vector = std::vector; using ScopedAlloc = std::scoped_allocator_adaptor< propagating_allocator>, PropAlloc>; using Indirect = std::indirect; const Indirect val(std::in_place, {1, 2, 3}); std::optional 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 void test_assign() { using PropAlloc = propagating_allocator; using Vector = std::vector; using ScopedAlloc = std::scoped_allocator_adaptor< propagating_allocator>, PropAlloc>; using Indirect = std::indirect; const Indirect val(std::in_place, {1, 2, 3}); std::optional 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 void test_swap() { using PropAlloc = propagating_allocator; using Vector = std::vector; using ScopedAlloc = std::scoped_allocator_adaptor< propagating_allocator>, PropAlloc>; using Indirect = std::indirect; 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 void test_valueless() { using PropAlloc = propagating_allocator; using Vector = std::vector; using ScopedAlloc = std::scoped_allocator_adaptor< propagating_allocator>, PropAlloc>; using Indirect = std::indirect; 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 void test_all() { test_ctor(); test_assign(); test_swap(); test_valueless(); } int main() { test_all(); test_all(); }