From 93429becadce2e5d74f33795c8a26b7aa10f3d68 Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Fri, 16 Jan 2026 16:10:00 -0500 Subject: [PATCH] xo-gc: + CollectorTypeRegistry for streamlined init --- .../cmake/xo_expression2Config.cmake.in | 1 + .../xo/expression2/init_expression2.hpp | 21 ++++++ xo-expression2/src/expression2/CMakeLists.txt | 4 + .../src/expression2/init_expression2.cpp | 41 ++++++++++ .../utest/expression2_utest_main.cpp | 20 ++++- xo-gc/include/xo/gc/CollectorTypeRegistry.hpp | 74 +++++++++++++++++++ xo-gc/src/gc/CMakeLists.txt | 3 + xo-gc/src/gc/CollectorTypeRegistry.cpp | 45 +++++++++++ xo-object2/cmake/xo_object2Config.cmake.in | 1 + .../include/xo/object2/init_object2.hpp | 21 ++++++ xo-object2/src/object2/CMakeLists.txt | 2 + xo-object2/src/object2/init_object2.cpp | 39 ++++++++++ xo-object2/utest/DString.test.cpp | 11 ++- xo-object2/utest/X1Collector.test.cpp | 18 ++++- xo-object2/utest/object2_utest_main.cpp | 20 ++++- xo-subsys/include/xo/subsys/Subsystem.hpp | 4 +- 16 files changed, 319 insertions(+), 6 deletions(-) create mode 100644 xo-expression2/include/xo/expression2/init_expression2.hpp create mode 100644 xo-expression2/src/expression2/init_expression2.cpp create mode 100644 xo-gc/include/xo/gc/CollectorTypeRegistry.hpp create mode 100644 xo-gc/src/gc/CollectorTypeRegistry.cpp create mode 100644 xo-object2/include/xo/object2/init_object2.hpp create mode 100644 xo-object2/src/object2/init_object2.cpp diff --git a/xo-expression2/cmake/xo_expression2Config.cmake.in b/xo-expression2/cmake/xo_expression2Config.cmake.in index d48c29a4..c8cfbcad 100644 --- a/xo-expression2/cmake/xo_expression2Config.cmake.in +++ b/xo-expression2/cmake/xo_expression2Config.cmake.in @@ -11,6 +11,7 @@ find_dependency(reflect) find_dependency(xo_object2) find_dependency(xo_printable2) find_dependency(xo_flatstring) +find_dependency(cmake) find_dependency(indentlog) include("${CMAKE_CURRENT_LIST_DIR}/@PROJECT_NAME@Targets.cmake") diff --git a/xo-expression2/include/xo/expression2/init_expression2.hpp b/xo-expression2/include/xo/expression2/init_expression2.hpp new file mode 100644 index 00000000..c5e290a8 --- /dev/null +++ b/xo-expression2/include/xo/expression2/init_expression2.hpp @@ -0,0 +1,21 @@ +/** @file init_expression2.hpp +* + * @author Roland Conybeare, Jan 2026 + **/ + +#pragma once + +#include + +namespace xo { + /* tag to represent the xo-expression2/ subsystem within ordered initialization */ + enum S_expression2_tag {}; + + template <> + struct InitSubsys { + static void init(); + static InitEvidence require(); + }; +} /*namespace xo*/ + +/* end init_expression2.hpp */ diff --git a/xo-expression2/src/expression2/CMakeLists.txt b/xo-expression2/src/expression2/CMakeLists.txt index 41700e9c..8ddedb9c 100644 --- a/xo-expression2/src/expression2/CMakeLists.txt +++ b/xo-expression2/src/expression2/CMakeLists.txt @@ -2,13 +2,16 @@ set(SELF_LIB xo_expression2) set(SELF_SRCS + init_expression2.cpp DConstant.cpp TypeRef.cpp IExpression_Any.cpp IExpression_DConstant.cpp StringTable.cpp DUniqueString.cpp + IGCObject_DUniqueString.cpp expression2_register_facets.cpp + expression2_register_types.cpp ) xo_add_shared_library4(${SELF_LIB} ${PROJECT_NAME}Targets ${PROJECT_VERSION} 1 ${SELF_SRCS}) @@ -18,4 +21,5 @@ xo_dependency(${SELF_LIB} reflect) xo_dependency(${SELF_LIB} xo_object2) xo_dependency(${SELF_LIB} xo_printable2) xo_dependency(${SELF_LIB} xo_flatstring) +xo_dependency(${SELF_LIB} subsys) xo_dependency(${SELF_LIB} indentlog) diff --git a/xo-expression2/src/expression2/init_expression2.cpp b/xo-expression2/src/expression2/init_expression2.cpp new file mode 100644 index 00000000..e975ef99 --- /dev/null +++ b/xo-expression2/src/expression2/init_expression2.cpp @@ -0,0 +1,41 @@ +/** @file init_expression2.cpp +* + * @author Roland Conybeare, Jan 2026 + **/ + +#include "init_expression2.hpp" +#include "expression2_register_facets.hpp" +#include "expression2_register_types.hpp" + +#include +#include + +namespace xo { + using xo::scm::expression2_register_facets; + using xo::scm::expression2_register_types; + using xo::mm::CollectorTypeRegistry; + + void + InitSubsys::init() + { + expression2_register_facets(); + + CollectorTypeRegistry::instance().register_types(&expression2_register_types); + } + + InitEvidence + InitSubsys::require() + { + InitEvidence retval; + + /* direct subsystem deps for xo-object2/ */ + retval ^= InitSubsys::require(); + + /* xo-expression2/'s own initialization code */ + retval ^= Subsystem::provide("expression2", &init); + + return retval; + } +} /*namespace xo*/ + +/* end init_expression2.cpp */ diff --git a/xo-expression2/utest/expression2_utest_main.cpp b/xo-expression2/utest/expression2_utest_main.cpp index e13405df..004d2598 100644 --- a/xo-expression2/utest/expression2_utest_main.cpp +++ b/xo-expression2/utest/expression2_utest_main.cpp @@ -1,6 +1,24 @@ /* file expression2_utest_main.cpp */ -#define CATCH_CONFIG_MAIN +#include + +#define CATCH_CONFIG_RUNNER #include "catch2/catch.hpp" +int +main(int argc, char* argv[]) +{ + using xo::Subsystem; + + // Your custom initialization code here + Subsystem::initialize_all(); + + // Run Catch2's test session + int result = Catch::Session().run(argc, argv); + + // cleanup here, if any + + return result; +} + /* end expression2_utest_main.cpp */ diff --git a/xo-gc/include/xo/gc/CollectorTypeRegistry.hpp b/xo-gc/include/xo/gc/CollectorTypeRegistry.hpp new file mode 100644 index 00000000..4474e20c --- /dev/null +++ b/xo-gc/include/xo/gc/CollectorTypeRegistry.hpp @@ -0,0 +1,74 @@ +/** @file CollectorTypeRegistry.hpp + * + * @brief Runtime type registration for gc-aware types + * + * @author Roland Conybeare, Jan 2026 + **/ + +#pragma once + +#include "Collector.hpp" +#include + +namespace xo { + namespace mm { + /** @class CollectorTypeRegistry + * + * @brief Runtime registry for gc-aware types + * + * Singleton to remember known gc-aware types; + * use to simplify registering such types + * with a collector instance. + * + * Remark: splitting work here between + * 1. static initializer work: tracking gc-aware types, + * 2. runtime post-configuration work: report + * gc-aware types to GC instances + * + * Use: + * 1. subsystem foo provides function foo_register_types(obj gc) + * Function calls + * gc.install_type(impl_for()) + * for each gc-aware type provided by subsystem foo + * + * Example: in file xo-object2/src/object2/object2_register_types.cpp, see + * object2_register_types() + * + * 2. during subsystem init, call + * CollectorTypeRegistry::instance().register_types(&foo_register_types); + * + * Example: in file xo-object2/src/object2/init_object2.cpp, see + * InitSubsys::init() + * + * 3. during Collector setup, call + * obj gc = ...; + * CollectorTypeRegistry::instance().install_types(gc); + * + * Example: in file xo-object2/utest/X1Collector.test.cpp + * TEST_CASE("x1") + **/ + class CollectorTypeRegistry { + public: + using init_function_type = std::function)>; + + public: + /** singleton instance **/ + static CollectorTypeRegistry & instance(); + + /** remember a gc-aware type-registration function **/ + void register_types(init_function_type init_fn); + + /** register known GC-aware types with @p gc. + * Calls @c gc.isntall_type() for each + * such type. + **/ + bool install_types(obj gc); + + private: + /** initialization steps for a new Collector instance **/ + std::vector init_seq_v_; + }; + } +} + +/* end CollectorTypeRegistry.hpp */ diff --git a/xo-gc/src/gc/CMakeLists.txt b/xo-gc/src/gc/CMakeLists.txt index 2d42c4c9..44cef925 100644 --- a/xo-gc/src/gc/CMakeLists.txt +++ b/xo-gc/src/gc/CMakeLists.txt @@ -3,8 +3,11 @@ set(SELF_LIB xo_gc) set(SELF_SRCS + CollectorTypeRegistry.cpp + ICollector_Any.cpp IGCObject_Any.cpp + IAllocator_DX1Collector.cpp ICollector_DX1Collector.cpp IAllocIterator_DX1CollectorIterator.cpp diff --git a/xo-gc/src/gc/CollectorTypeRegistry.cpp b/xo-gc/src/gc/CollectorTypeRegistry.cpp new file mode 100644 index 00000000..cb039dd8 --- /dev/null +++ b/xo-gc/src/gc/CollectorTypeRegistry.cpp @@ -0,0 +1,45 @@ +/** @file CollectorTypeRegistry.cpp + **/ + +#include "CollectorTypeRegistry.hpp" +#include + +namespace xo { + namespace mm { + CollectorTypeRegistry & + CollectorTypeRegistry::instance() { + static CollectorTypeRegistry s_instance; + + return s_instance; + } + + void + CollectorTypeRegistry::register_types(init_function_type fn) { + scope log(XO_DEBUG(true)); + + init_seq_v_.push_back(fn); + } + + bool + CollectorTypeRegistry::install_types(obj gc) { + scope log(XO_DEBUG(true)); + + bool ok = true; + + size_t i = 0; + size_t n = init_seq_v_.size(); + log && log("run n init steps", xtag("n", n)); + + for (const auto & fn : init_seq_v_) { + log && log("do install fn (", i+1, "/", n, ")"); + + ok = ok & fn(gc); + } + + return ok; + } + + } /*namespace mm*/ +} /*namespace xo*/ + +/* end CollectorTypeRegistry.cpp */ diff --git a/xo-object2/cmake/xo_object2Config.cmake.in b/xo-object2/cmake/xo_object2Config.cmake.in index 45104c22..36d3bb62 100644 --- a/xo-object2/cmake/xo_object2Config.cmake.in +++ b/xo-object2/cmake/xo_object2Config.cmake.in @@ -3,6 +3,7 @@ include(CMakeFindDependencyMacro) find_dependency(xo_gc) find_dependency(xo_printable2) +find_dependency(subsys) find_dependency(indentlog) include("${CMAKE_CURRENT_LIST_DIR}/@PROJECT_NAME@Targets.cmake") check_required_components("@PROJECT_NAME@") diff --git a/xo-object2/include/xo/object2/init_object2.hpp b/xo-object2/include/xo/object2/init_object2.hpp new file mode 100644 index 00000000..5c26e76d --- /dev/null +++ b/xo-object2/include/xo/object2/init_object2.hpp @@ -0,0 +1,21 @@ +/** @file init_object2.hpp +* + * @author Roland Conybeare, Jan 2026 + **/ + +#pragma once + +#include + +namespace xo { + /* tag to represent the xo-expression2/ subsystem within ordered initialization */ + enum S_object2_tag {}; + + template <> + struct InitSubsys { + static void init(); + static InitEvidence require(); + }; +} /*namespace xo*/ + +/* end init_object2.hpp */ diff --git a/xo-object2/src/object2/CMakeLists.txt b/xo-object2/src/object2/CMakeLists.txt index 3ab39f32..a87c349b 100644 --- a/xo-object2/src/object2/CMakeLists.txt +++ b/xo-object2/src/object2/CMakeLists.txt @@ -19,6 +19,7 @@ set(SELF_SRCS DFloat.cpp DInteger.cpp DString.cpp + init_object2.cpp object2_register_types.cpp object2_register_facets.cpp ) @@ -27,4 +28,5 @@ xo_add_shared_library4(${SELF_LIB} ${PROJECT_NAME}Targets ${PROJECT_VERSION} 1 $ # note: deps here must also appear in cmake/xo_object2Config.cmake.in xo_dependency(${SELF_LIB} xo_gc) xo_dependency(${SELF_LIB} xo_printable2) +xo_dependency(${SELF_LIB} subsys) xo_dependency(${SELF_LIB} indentlog) diff --git a/xo-object2/src/object2/init_object2.cpp b/xo-object2/src/object2/init_object2.cpp new file mode 100644 index 00000000..b5e57aba --- /dev/null +++ b/xo-object2/src/object2/init_object2.cpp @@ -0,0 +1,39 @@ +/** @file init_object2.cpp +* + * @author Roland Conybeare, Jan 2026 + **/ + +#include "init_object2.hpp" +#include "object2_register_facets.hpp" +#include "object2_register_types.hpp" +#include + +namespace xo { + using xo::scm::object2_register_facets; + using xo::scm::object2_register_types; + using xo::mm::CollectorTypeRegistry; + + void + InitSubsys::init() + { + object2_register_facets(); + + CollectorTypeRegistry::instance().register_types(&object2_register_types); + } + + InitEvidence + InitSubsys::require() + { + InitEvidence retval; + + /* direct subsystem deps for xo-object2/ */ + // retval ^= InitSubsys::require(); + + /* xo-expression2/'s own initialization code */ + retval ^= Subsystem::provide("object2", &init); + + return retval; + } +} /*namespace xo*/ + +/* end init_object2.cpp */ diff --git a/xo-object2/utest/DString.test.cpp b/xo-object2/utest/DString.test.cpp index 124cebb5..39dffef5 100644 --- a/xo-object2/utest/DString.test.cpp +++ b/xo-object2/utest/DString.test.cpp @@ -3,7 +3,8 @@ * @author Roland Conybeare, Jan 2026 **/ -#include +#include "init_object2.hpp" +#include "StringOps.hpp" #include #include #include @@ -19,6 +20,14 @@ namespace xo { using xo::facet::obj; namespace ut { + static InitEvidence s_init = (InitSubsys::require()); + + TEST_CASE("DString-init", "[object2][DString]") + { + // real purpose: ensure s_init survives static linking + REQUIRE(s_init.evidence()); + } + TEST_CASE("DString-empty", "[object2][DString]") { ArenaConfig cfg { .name_ = "testarena", diff --git a/xo-object2/utest/X1Collector.test.cpp b/xo-object2/utest/X1Collector.test.cpp index 85610da2..0f20e68a 100644 --- a/xo-object2/utest/X1Collector.test.cpp +++ b/xo-object2/utest/X1Collector.test.cpp @@ -3,6 +3,7 @@ * @author Roland Conybeare, Dec 2025 **/ +#include "init_object2.hpp" #include "ListOps.hpp" #include "DFloat.hpp" #include "DInteger.hpp" @@ -14,6 +15,7 @@ #include "number/IGCObject_DInteger.hpp" #include "list/IGCObject_DList.hpp" +#include #include #include @@ -23,18 +25,22 @@ #include #include +#include + #include #include #include namespace ut { + using xo::S_object2_tag; using xo::scm::object2_register_types; using xo::scm::ListOps; using xo::scm::DList; using xo::scm::DArray; using xo::scm::DFloat; using xo::scm::DInteger; + using xo::mm::CollectorTypeRegistry; using xo::mm::AAllocator; using xo::mm::ACollector; using xo::mm::AllocHeader; @@ -49,6 +55,9 @@ namespace ut { using xo::mm::padding; using xo::facet::with_facet; using xo::facet::typeseq; + using xo::Subsystem; + using xo::InitEvidence; + using xo::InitSubsys; using xo::scope; using xo::xtag; @@ -79,8 +88,13 @@ namespace ut { }; } + static InitEvidence s_init = (InitSubsys::require()); + TEST_CASE("x1", "[gc][x1]") { + // real purpose: ensure s_init survives static linking + REQUIRE(s_init.evidence()); + /** * This is a basic Collector test for xo-object2 data types **/ @@ -89,6 +103,8 @@ namespace ut { scope log(XO_DEBUG(c_debug_flag)); for (std::size_t i_tc = 0, n_tc = s_testcase_v.size(); i_tc < n_tc; ++i_tc) { + scope log(XO_DEBUG(true), xtag("i_tc", i_tc)); + try { const testcase_x1 & tc = s_testcase_v[i_tc]; @@ -169,7 +185,7 @@ namespace ut { auto c_o = with_facet::mkobj(&gc); /* register object types */ - bool ok = object2_register_types(c_o); + bool ok = CollectorTypeRegistry::instance().install_types(c_o); REQUIRE(ok); diff --git a/xo-object2/utest/object2_utest_main.cpp b/xo-object2/utest/object2_utest_main.cpp index a3dcb813..d868f233 100644 --- a/xo-object2/utest/object2_utest_main.cpp +++ b/xo-object2/utest/object2_utest_main.cpp @@ -1,6 +1,24 @@ /* file object2_utest_main.cpp */ -#define CATCH_CONFIG_MAIN +#include + +#define CATCH_CONFIG_RUNNER #include "catch2/catch.hpp" +int +main(int argc, char* argv[]) +{ + using xo::Subsystem; + + // Your custom initialization code here + Subsystem::initialize_all(); + + // Run Catch2's test session + int result = Catch::Session().run(argc, argv); + + // cleanup here, if any + + return result; +} + /* end object2_utest_main.cpp */ diff --git a/xo-subsys/include/xo/subsys/Subsystem.hpp b/xo-subsys/include/xo/subsys/Subsystem.hpp index 3cc6012a..07a96377 100644 --- a/xo-subsys/include/xo/subsys/Subsystem.hpp +++ b/xo-subsys/include/xo/subsys/Subsystem.hpp @@ -130,8 +130,8 @@ namespace xo { public: SubsystemImpl() = default; SubsystemImpl(bool require_flag, - std::string_view subsys_name, - std::function init_fn) + std::string_view subsys_name, + std::function init_fn) : require_flag_{require_flag}, subsys_name_{subsys_name}, init_fn_{init_fn} {}