blob: c80215983b6c335046988c961af2645141d3b192 [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>
struct Base {
friend constexpr
bool operator==(const Base& lhs, const Base& rhs)
{ return lhs.eq(rhs); }
private:
constexpr virtual bool
eq(const Base& other) const = 0;
};
struct Derived : Base
{
constexpr Derived()
: x(0), y(0), z(0)
{ }
constexpr Derived(int a, int b, int c)
: x(a), y(b), z(c)
{ }
private:
constexpr bool
eq(const Base& other) const override
{
if (auto op = dynamic_cast<const Derived*>(&other))
return this->x == op->x && this->y == op->y && this->z == op->z;
return false;
}
int x;
int y;
int z;
};
using __gnu_test::tracker_allocator;
using Counter = __gnu_test::tracker_allocator_counter;
using Polymorphic = std::polymorphic<Base, tracker_allocator<Base>>;
const Polymorphic val(std::in_place_type<Derived>, 1, 2, 3);
constexpr 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 );
}
constexpr void
test_ctor()
{
std::optional<Polymorphic> src;
auto make = [&src] -> Polymorphic&& {
src.emplace(val);
Counter::reset();
return std::move(*src);
};
Polymorphic i1(make());
VERIFY( src->valueless_after_move() );
VERIFY( *i1 == *val );
verifyNoAllocations();
Polymorphic i2(std::allocator_arg, {}, make());
VERIFY( src->valueless_after_move() );
VERIFY( *i2 == *val );
verifyNoAllocations();
}
constexpr void
test_assign()
{
std::optional<Polymorphic> src;
auto make = [&src] -> Polymorphic&& {
src.emplace(val);
Counter::reset();
return std::move(*src);
};
Polymorphic i1(std::in_place_type<Derived>);
i1 = make();
VERIFY( src->valueless_after_move() );
VERIFY( *i1 == *val );
VERIFY( Counter::get_allocation_count() == 0 );
VERIFY( Counter::get_deallocation_count() >= sizeof(Derived) );
VERIFY( Counter::get_construct_count() == 0 );
VERIFY( Counter::get_destruct_count() == 1 );
auto(std::move(i1));
i1 = make();
VERIFY( *i1 == *val );
VERIFY( src->valueless_after_move() );
verifyNoAllocations();
}
constexpr void
test_swap()
{
const Polymorphic val1(std::in_place_type<Derived>, 1, 2, 3);
const Polymorphic val2(std::in_place_type<Derived>, 2, 4, 6);
Polymorphic i1(val1);
Polymorphic i2(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();
}
constexpr void
test_valueless()
{
auto e = [] {
Polymorphic res(std::in_place_type<Derived>);
auto(std::move(res));
Counter::reset();
return res;
};
Polymorphic i1(e());
VERIFY( i1.valueless_after_move() );
verifyNoAllocations();
Polymorphic i2(std::allocator_arg, {}, e());
VERIFY( i2.valueless_after_move() );
verifyNoAllocations();
Polymorphic i3(val);
i3 = e();
VERIFY( Counter::get_allocation_count() == 0 );
VERIFY( Counter::get_deallocation_count() >= sizeof(Derived) );
VERIFY( Counter::get_construct_count() == 0 );
VERIFY( Counter::get_destruct_count() == 1 );
i3 = e();
verifyNoAllocations();
}
constexpr void
test_all()
{
test_ctor();
test_assign();
test_swap();
test_valueless();
}
int main()
{
test_all();
static_assert([] {
test_all();
return true;
});
}