Add ArenaAllocator::Ptr
This commit is contained in:
@@ -598,3 +598,162 @@ TEST_CASE("format function fallback codepath") {
|
||||
CHECK(result == "Valid format: 42");
|
||||
}
|
||||
}
|
||||
|
||||
// Test object with non-trivial destructor for ArenaAllocator::Ptr testing
|
||||
class TestObject {
|
||||
public:
|
||||
static int destructor_count;
|
||||
static int constructor_count;
|
||||
|
||||
int value;
|
||||
|
||||
TestObject(int v) : value(v) { constructor_count++; }
|
||||
|
||||
~TestObject() { destructor_count++; }
|
||||
|
||||
static void reset_counters() {
|
||||
constructor_count = 0;
|
||||
destructor_count = 0;
|
||||
}
|
||||
};
|
||||
|
||||
int TestObject::destructor_count = 0;
|
||||
int TestObject::constructor_count = 0;
|
||||
|
||||
// Test struct with trivial destructor
|
||||
struct TrivialObject {
|
||||
int value;
|
||||
TrivialObject(int v) : value(v) {}
|
||||
};
|
||||
|
||||
TEST_CASE("ArenaAllocator::Ptr smart pointer functionality") {
|
||||
TestObject::reset_counters();
|
||||
|
||||
SUBCASE("construct returns raw pointer for trivially destructible types") {
|
||||
ArenaAllocator arena;
|
||||
|
||||
auto ptr = arena.construct<TrivialObject>(42);
|
||||
static_assert(std::is_same_v<decltype(ptr), TrivialObject *>,
|
||||
"construct() should return raw pointer for trivially "
|
||||
"destructible types");
|
||||
CHECK(ptr != nullptr);
|
||||
CHECK(ptr->value == 42);
|
||||
}
|
||||
|
||||
SUBCASE("construct returns ArenaAllocator::Ptr for non-trivially "
|
||||
"destructible types") {
|
||||
ArenaAllocator arena;
|
||||
|
||||
auto ptr = arena.construct<TestObject>(42);
|
||||
static_assert(
|
||||
std::is_same_v<decltype(ptr), ArenaAllocator::Ptr<TestObject>>,
|
||||
"construct() should return ArenaAllocator::Ptr for non-trivially "
|
||||
"destructible types");
|
||||
CHECK(ptr);
|
||||
CHECK(ptr->value == 42);
|
||||
CHECK(TestObject::constructor_count == 1);
|
||||
CHECK(TestObject::destructor_count == 0);
|
||||
}
|
||||
|
||||
SUBCASE("ArenaAllocator::Ptr calls destructor on destruction") {
|
||||
ArenaAllocator arena;
|
||||
|
||||
{
|
||||
auto ptr = arena.construct<TestObject>(42);
|
||||
CHECK(TestObject::constructor_count == 1);
|
||||
CHECK(TestObject::destructor_count == 0);
|
||||
} // ptr goes out of scope
|
||||
|
||||
CHECK(TestObject::destructor_count == 1);
|
||||
}
|
||||
|
||||
SUBCASE("ArenaAllocator::Ptr move semantics") {
|
||||
ArenaAllocator arena;
|
||||
|
||||
auto ptr1 = arena.construct<TestObject>(42);
|
||||
CHECK(TestObject::constructor_count == 1);
|
||||
|
||||
auto ptr2 = std::move(ptr1);
|
||||
CHECK(!ptr1); // ptr1 should be null after move
|
||||
CHECK(ptr2);
|
||||
CHECK(ptr2->value == 42);
|
||||
CHECK(TestObject::destructor_count == 0); // No destruction yet
|
||||
|
||||
ptr2.reset();
|
||||
CHECK(TestObject::destructor_count == 1); // Destructor called
|
||||
}
|
||||
|
||||
SUBCASE("ArenaAllocator::Ptr access operators") {
|
||||
ArenaAllocator arena;
|
||||
|
||||
auto ptr = arena.construct<TestObject>(123);
|
||||
|
||||
// Test operator->
|
||||
CHECK(ptr->value == 123);
|
||||
|
||||
// Test operator*
|
||||
CHECK((*ptr).value == 123);
|
||||
|
||||
// Test get()
|
||||
TestObject *raw_ptr = ptr.get();
|
||||
CHECK(raw_ptr != nullptr);
|
||||
CHECK(raw_ptr->value == 123);
|
||||
|
||||
// Test bool conversion
|
||||
CHECK(ptr);
|
||||
CHECK(static_cast<bool>(ptr) == true);
|
||||
}
|
||||
|
||||
SUBCASE("ArenaAllocator::Ptr reset functionality") {
|
||||
ArenaAllocator arena;
|
||||
|
||||
auto ptr = arena.construct<TestObject>(42);
|
||||
CHECK(TestObject::constructor_count == 1);
|
||||
CHECK(TestObject::destructor_count == 0);
|
||||
|
||||
ptr.reset();
|
||||
CHECK(!ptr);
|
||||
CHECK(TestObject::destructor_count == 1);
|
||||
|
||||
// Reset with new object
|
||||
TestObject *raw_obj = arena.construct<TestObject>(84).release();
|
||||
ptr.reset(raw_obj);
|
||||
CHECK(ptr);
|
||||
CHECK(ptr->value == 84);
|
||||
CHECK(TestObject::constructor_count == 2);
|
||||
CHECK(TestObject::destructor_count == 1);
|
||||
}
|
||||
|
||||
SUBCASE("ArenaAllocator::Ptr release functionality") {
|
||||
ArenaAllocator arena;
|
||||
|
||||
auto ptr = arena.construct<TestObject>(42);
|
||||
TestObject *raw_ptr = ptr.release();
|
||||
|
||||
CHECK(!ptr); // ptr should be null after release
|
||||
CHECK(raw_ptr != nullptr);
|
||||
CHECK(raw_ptr->value == 42);
|
||||
CHECK(TestObject::destructor_count == 0); // No destructor called
|
||||
|
||||
// Manually call destructor (since we released ownership)
|
||||
raw_ptr->~TestObject();
|
||||
CHECK(TestObject::destructor_count == 1);
|
||||
}
|
||||
|
||||
SUBCASE("ArenaAllocator::Ptr move assignment") {
|
||||
ArenaAllocator arena;
|
||||
|
||||
auto ptr1 = arena.construct<TestObject>(42);
|
||||
auto ptr2 = arena.construct<TestObject>(84);
|
||||
|
||||
CHECK(TestObject::constructor_count == 2);
|
||||
CHECK(TestObject::destructor_count == 0);
|
||||
|
||||
ptr1 = std::move(ptr2); // Should destroy first object, move second
|
||||
|
||||
CHECK(!ptr2); // ptr2 should be null
|
||||
CHECK(ptr1);
|
||||
CHECK(ptr1->value == 84);
|
||||
CHECK(TestObject::destructor_count == 1); // First object destroyed
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user