From 9b84ef8a7f58ba38ea06046b43d9c1ee331a4711 Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Sun, 10 May 2026 18:19:41 -0400 Subject: [PATCH] xo-alloc2 xo-gc: assorted utest-guided cleanup ++ coverage --- include/xo/alloc2/ArenaIterator.hpp | 15 ++++++ include/xo/alloc2/arena/IAllocator_DArena.hpp | 2 - include/xo/alloc2/role.hpp | 2 + src/alloc2/IAllocator_Any.cpp | 3 +- src/alloc2/IAllocator_DArena.cpp | 7 --- src/alloc2/SetupAlloc2.cpp | 6 +++ utest/CMakeLists.txt | 1 + utest/Generation.test.cpp | 2 +- utest/Role.test.cpp | 46 +++++++++++++++++++ utest/arena.test.cpp | 34 ++++++++++++++ utest/random_allocs.cpp | 3 ++ utest/random_allocs.hpp | 1 + 12 files changed, 111 insertions(+), 11 deletions(-) create mode 100644 include/xo/alloc2/ArenaIterator.hpp create mode 100644 utest/Role.test.cpp diff --git a/include/xo/alloc2/ArenaIterator.hpp b/include/xo/alloc2/ArenaIterator.hpp new file mode 100644 index 00000000..02b49e85 --- /dev/null +++ b/include/xo/alloc2/ArenaIterator.hpp @@ -0,0 +1,15 @@ +/** @file ArenaIterator.hpp + * + * @author Roland Conybeare, May 2026 + **/ + +#pragma once + +// reminder: we can't put this AAllocIterator support in xo-arena +// because xo-arena is a dependency of xo-facet, which we're relying +// on here + +#include +#include "arena/IAllocIterator_DArenaIterator.hpp" + +/* end ArenaIterator.hpp */ diff --git a/include/xo/alloc2/arena/IAllocator_DArena.hpp b/include/xo/alloc2/arena/IAllocator_DArena.hpp index 0512cd57..5a3ad8fd 100644 --- a/include/xo/alloc2/arena/IAllocator_DArena.hpp +++ b/include/xo/alloc2/arena/IAllocator_DArena.hpp @@ -72,8 +72,6 @@ namespace xo { * @p complete_flag to true. **/ static value_type sub_alloc(DArena &, size_type z, bool complete_flag); - /** allocate copy of @p src in arena @p d. **/ - static value_type alloc_copy(DArena & d, value_type src); static void clear(DArena &); /** perform assignment {*lhs_iface, *lhs_data} = {*rhs_iface, rhs_data} **/ static void barrier_assign_aux(DArena &, diff --git a/include/xo/alloc2/role.hpp b/include/xo/alloc2/role.hpp index 9b068a1d..cb8b9137 100644 --- a/include/xo/alloc2/role.hpp +++ b/include/xo/alloc2/role.hpp @@ -30,6 +30,8 @@ namespace xo { operator value_type() const { return role_; } + Role next() const { return Role(role_ + 1); } + value_type role_ = 0; }; } /*namespace mm*/ diff --git a/src/alloc2/IAllocator_Any.cpp b/src/alloc2/IAllocator_Any.cpp index f158e47c..813973c8 100644 --- a/src/alloc2/IAllocator_Any.cpp +++ b/src/alloc2/IAllocator_Any.cpp @@ -15,7 +15,8 @@ namespace xo { namespace mm { void - IAllocator_Any::_fatal() { + IAllocator_Any::_fatal() + { /* control here on uninitialized IAllocator_Any. * Initialized instance will have specific implementation type * e.g. IAllocator_Xfer diff --git a/src/alloc2/IAllocator_DArena.cpp b/src/alloc2/IAllocator_DArena.cpp index 4d9a0a43..3f205a94 100644 --- a/src/alloc2/IAllocator_DArena.cpp +++ b/src/alloc2/IAllocator_DArena.cpp @@ -141,13 +141,6 @@ namespace xo { return s.sub_alloc(req_z, complete_flag); } - std::byte * - IAllocator_DArena::alloc_copy(DArena &s, - value_type src) - { - return s.alloc_copy(src); - } - void IAllocator_DArena::clear(DArena & s) { diff --git a/src/alloc2/SetupAlloc2.cpp b/src/alloc2/SetupAlloc2.cpp index caf8d573..da14c0ff 100644 --- a/src/alloc2/SetupAlloc2.cpp +++ b/src/alloc2/SetupAlloc2.cpp @@ -5,6 +5,7 @@ #include "SetupAlloc2.hpp" #include +#include #include #include @@ -21,8 +22,13 @@ namespace xo { scope log(XO_DEBUG(true)); FacetRegistry::register_impl(); + FacetRegistry::register_impl(); log && log(xtag("DArena.tseq", typeseq::id())); + log && log(xtag("DArenaIterator.tseq", typeseq::id())); + + log && log(xtag("AAllocator.tseq", typeseq::id())); + log && log(xtag("AAllocIterator.tseq", typeseq::id())); return true; } diff --git a/utest/CMakeLists.txt b/utest/CMakeLists.txt index 9f9ece5f..af2d3194 100644 --- a/utest/CMakeLists.txt +++ b/utest/CMakeLists.txt @@ -10,6 +10,7 @@ set(UTEST_SRCS # Collector.test.cpp # DX1CollectorIterator.test.cpp Generation.test.cpp + Role.test.cpp VisitReason.test.cpp dp.test.cpp random_allocs.cpp diff --git a/utest/Generation.test.cpp b/utest/Generation.test.cpp index 43d64389..e62359ea 100644 --- a/utest/Generation.test.cpp +++ b/utest/Generation.test.cpp @@ -39,4 +39,4 @@ namespace xo { } /*namespace ut*/ } /*namespace xo*/ -/* end Generation.hpp */ +/* end Generation.test.cpp */ diff --git a/utest/Role.test.cpp b/utest/Role.test.cpp new file mode 100644 index 00000000..d1de6fe4 --- /dev/null +++ b/utest/Role.test.cpp @@ -0,0 +1,46 @@ +/** @file Role.test.cpp + * + * @author Roland Conybeare, May 2026 + **/ + +#include "role.hpp" +#include + +namespace xo { + using xo::mm::Role; + + namespace ut { + + TEST_CASE("Role-1", "[Role]") + { + /* 1. there are two distinct valid roles, 'to' and 'from', + * 2. valid roles fall in interval [begin, end) + */ + + REQUIRE(Role::to_space() == Role::to_space()); + REQUIRE(Role::from_space() == Role::from_space()); + REQUIRE(Role::to_space() != Role::from_space()); + + Role x0 = Role::begin(); + { + bool ok = (x0 == Role::to_space() || x0 == Role::from_space()); + REQUIRE(ok); + } + REQUIRE(x0 != Role::end()); + + Role x1 = x0.next(); + REQUIRE(x1 != x0); + { + bool ok = (x1 == Role::to_space() || x1 == Role::from_space()); + REQUIRE(ok); + } + REQUIRE(x1 != Role::end()); + + Role x2 = x1.next(); + REQUIRE(x2 == Role::end()); + } + + } +} /*namespace xo*/ + +/* end Role.test.cpp */ diff --git a/utest/arena.test.cpp b/utest/arena.test.cpp index 0beb66d8..0a1c3e90 100644 --- a/utest/arena.test.cpp +++ b/utest/arena.test.cpp @@ -20,6 +20,7 @@ namespace xo { using xo::mm::AllocHeaderConfig; using xo::mm::ArenaConfig; using xo::mm::AllocHeader; + using xo::mm::AllocInfo; using xo::mm::padding; using xo::mm::error; using xo::facet::with_facet; @@ -223,6 +224,39 @@ namespace xo { REQUIRE(a1o.allocated() <= a1o.committed()); REQUIRE(a1o.allocated() + a1o.available() == a1o.committed()); REQUIRE(a1o.committed() <= a1o.reserved()); + + auto committed0_z = a1o.committed(); + + // also test alloc info + AllocInfo m0_info = a1o.alloc_info(m0); + { + REQUIRE(m0_info.size() >= z0); + + // {tseq, age}: feature disabled must be zero + REQUIRE(m0_info.tseq() == 0); + REQUIRE(m0_info.age() == 0); + + REQUIRE(m0_info.payload().first == m0); + REQUIRE(m0_info.payload().second >= m0 + z0); + + REQUIRE(m0_info.guard_z() == cfg.header_.guard_z_); + REQUIRE((uint32_t)m0_info.guard_byte() == (uint32_t)cfg.header_.guard_byte_); + } + + a1o.clear(); + + // allocated size got reset + REQUIRE(a1o.allocated() == 0); + // committed size unchanged + REQUIRE(a1o.committed() == committed0_z); + REQUIRE(a1o.last_error().error_ == error::ok); + REQUIRE(a1o.last_error().error_seq_ == 0); + + // allocator no longer contains m0 (now points to unallocated but committed memory + // (not exposed via AAllocator! + // REQUIRE(a1o.contains_allocated(m0) == false); + + REQUIRE(a1o.contains(m0)); } TEST_CASE("allocator-alloc-3", "[alloc2][Allocator]") diff --git a/utest/random_allocs.cpp b/utest/random_allocs.cpp index 2325140d..470ee840 100644 --- a/utest/random_allocs.cpp +++ b/utest/random_allocs.cpp @@ -39,6 +39,7 @@ namespace utest { bool AllocUtil::random_allocs(uint32_t n_alloc, + uint32_t max_alloc_z, bool catch_flag, xoshiro256ss * p_rgen, obj mm) @@ -64,6 +65,8 @@ namespace utest { double si = ngen(*p_rgen); double zi = ::pow(2.0, si); std::size_t z = ::ceil(zi); + if (z > max_alloc_z) + z = max_alloc_z; bool ok_flag = true; diff --git a/utest/random_allocs.hpp b/utest/random_allocs.hpp index ab0afc4e..5c726e40 100644 --- a/utest/random_allocs.hpp +++ b/utest/random_allocs.hpp @@ -36,6 +36,7 @@ namespace utest { * verify allocator behavior **/ static bool random_allocs(std::uint32_t n_alloc, + std::uint32_t max_alloc_z, bool catch_flag, xo::rng::xoshiro256ss * p_rgen, xo::facet::obj alloc);