/* @file IAlloc.test.cpp * * author: Roland Conybeare, Aug 2025 */ //#include "xo/allocutil/IAlloc.hpp" #include "xo/alloc/ArenaAlloc.hpp" #include "xo/indentlog/print/tag.hpp" #include namespace xo { using xo::gc::IAlloc; using xo::gc::ArenaAlloc; namespace ut { TEST_CASE("ialloc", "[alloc]") { static_assert((sizeof(std::uintptr_t) == 8) && "possibly fine if this fails, but would want to know"); REQUIRE(IAlloc::alloc_padding(0) == 0); for (std::size_t i = 1; i < sizeof(std::uintptr_t); ++i) { REQUIRE(IAlloc::alloc_padding(i) + i == IAlloc::c_alloc_alignment); } REQUIRE(IAlloc::alloc_padding(IAlloc::c_alloc_alignment) == 0); for (std::size_t i = 1; i < sizeof(std::uintptr_t); ++i) { REQUIRE(IAlloc::alloc_padding(IAlloc::c_alloc_alignment + i) + i == IAlloc::c_alloc_alignment); } } /* although xo::gc::allocator is intended for * IAlloc derivatives (so T is ArenaAlloc | GC), * * it only relies on allocate() and deallocate() methods */ namespace { struct TestCase { explicit TestCase(size_t arena_z, size_t n, size_t n2) : arena_z_{arena_z}, n_{n}, n2_{n2} {} size_t arena_z_ = 0; size_t n_ = 0; size_t n2_ = 0; }; std::vector s_testcase_v = { TestCase{1024*1024, 9, 13} }; } TEST_CASE("gc.allocator", "[alloc]") { using xo::gc::allocator; constexpr bool c_debug_flag = false; for (size_t i_tc = 0, n_tc = s_testcase_v.size(); i_tc < n_tc; ++i_tc) { INFO(xtag("i_tc", i_tc)); const TestCase & tc = s_testcase_v[i_tc]; up mm1 = ArenaAlloc::make("arena1", tc.arena_z_, c_debug_flag); up mm2 = ArenaAlloc::make("arena2", tc.arena_z_, c_debug_flag); REQUIRE(mm1.get()); REQUIRE(mm1->allocated() == 0); allocator alloc1(mm1.get()); allocator alloc1a(mm1.get()); REQUIRE(mm2.get()); REQUIRE(mm2->allocated() == 0); allocator alloc2(mm2.get()); SECTION("IAlloc identity determines allocator equality") { REQUIRE(alloc1 == alloc1a); REQUIRE(alloc1 != alloc2); } int * p1 = nullptr; size_t z1 = 0; SECTION("alloc space for ints") { p1 = alloc1.allocate(tc.n_); REQUIRE(p1 != nullptr); // note: allowing for alignment REQUIRE(mm1->allocated() >= sizeof(int32_t) * tc.n_); REQUIRE(mm1->allocated() < sizeof(int32_t) * tc.n_ + IAlloc::c_alloc_alignment); z1 = mm1->allocated(); // deallocate exists.. alloc1.deallocate(p1, tc.n_); // ..but is a no-op REQUIRE(mm1->allocated() == z1); } int * p2 = nullptr; SECTION("allocator independence") { REQUIRE(mm2->allocated() == 0); p2 = alloc2.allocate(tc.n2_); REQUIRE(p2 != nullptr); REQUIRE(p1 != p2); REQUIRE(mm2->allocated() >= sizeof(int32_t) * tc.n2_); REQUIRE(mm2->allocated() < sizeof(int32_t) * tc.n2_ + IAlloc::c_alloc_alignment); // mm1 unaffected by mm2 allocation REQUIRE(mm1->allocated() == z1); } } } } /*namespace ut*/ } /*namespace xo*/ /* end IAlloc.test.cpp */