From 148d5e9ca0aafb1639098f6686ae1b0e25de9f8d Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Fri, 9 Jan 2026 17:48:54 -0500 Subject: [PATCH] xo-objectd2 xo-printable xo-facet: pp working for List(Integer) Also streamline facet switching --- include/xo/object2/DInteger.hpp | 23 ++- include/xo/object2/DList.hpp | 38 ++++- include/xo/object2/IPrintable_DInteger.hpp | 57 +++++++ include/xo/object2/IPrintable_DList.hpp | 2 +- include/xo/object2/object2_register_types.hpp | 3 + src/object2/CMakeLists.txt | 4 +- src/object2/DInteger.cpp | 32 ++++ src/object2/DList.cpp | 17 ++- src/object2/IPrintable_DInteger.cpp | 28 ++++ src/object2/object2_register_types.cpp | 39 +++++ utest/CMakeLists.txt | 1 + utest/Printable.test.cpp | 141 ++++++++++++++++++ utest/X1Collector.test.cpp | 2 +- 13 files changed, 379 insertions(+), 8 deletions(-) create mode 100644 include/xo/object2/IPrintable_DInteger.hpp create mode 100644 src/object2/DInteger.cpp create mode 100644 src/object2/IPrintable_DInteger.cpp create mode 100644 utest/Printable.test.cpp diff --git a/include/xo/object2/DInteger.hpp b/include/xo/object2/DInteger.hpp index 3457af7..2592147 100644 --- a/include/xo/object2/DInteger.hpp +++ b/include/xo/object2/DInteger.hpp @@ -5,11 +5,32 @@ #pragma once +#include +#include #include namespace xo { namespace scm { - using DInteger = std::int64_t; + struct DInteger { + using AAllocator = xo::mm::AAllocator; + using ppindentinfo = xo::print::ppindentinfo; + + explicit DInteger(long x) : value_{x} {} + + /** allocate boxed value @p x using memory from @p mm **/ + static DInteger * make(obj mm, + long x); + + double value() const noexcept { return value_; } + + bool pretty(const ppindentinfo & ppii) const; + + operator long() const noexcept { return value_; } + + private: + /** boxed integer value **/ + long value_; + }; } /*nmaespace obj*/ } /*namespace xo*/ diff --git a/include/xo/object2/DList.hpp b/include/xo/object2/DList.hpp index dc0729b..1e863a6 100644 --- a/include/xo/object2/DList.hpp +++ b/include/xo/object2/DList.hpp @@ -13,6 +13,7 @@ namespace xo { namespace scm { + // TODO: consider renaming to DCons struct DList { using size_type = std::size_t; using AGCObject = xo::mm::AGCObject; @@ -22,8 +23,27 @@ namespace xo { DList(xo::obj h, DList * r) : head_{h}, rest_{r} {} + template + static obj nil(); + + /** shortcut for + * cons(mm, cdr, cdr.data()) + **/ + template + static obj cons(obj mm, + obj car, + obj cdr); + /** sentinel for null list **/ - static DList * null(); + static DList * _nil(); + + /** list with first element @p car, + * followed by contents of list @p cdr. + * Shares structure with @p cdr + **/ + static DList * _cons(obj mm, + obj car, + DList * cdr); /** list with one element @p h1, allocated from @p mm **/ static DList * list(obj mm, @@ -51,6 +71,22 @@ namespace xo { DList * rest_ = nullptr; }; + template + obj + DList::nil() + { + return obj(DList::_nil()); + } + + template + obj + DList::cons(obj mm, + obj car, + obj cdr) + { + return obj(DList::_cons(mm, car, cdr.data())); + } + } /*namespace scm*/ } /*namespace xo*/ diff --git a/include/xo/object2/IPrintable_DInteger.hpp b/include/xo/object2/IPrintable_DInteger.hpp new file mode 100644 index 0000000..d18b25a --- /dev/null +++ b/include/xo/object2/IPrintable_DInteger.hpp @@ -0,0 +1,57 @@ +/** @file IPrintable_DInteger.hpp + * + * Generated automagically from ingredients: + * 1. code generator: + * [/home/roland/proj/xo-umbrella2/xo-facet/codegen/genfacet] + * arguments: + * --input [idl/IPrintable_DInteger.json5] + * 2. jinja2 template for abstract facet .hpp file: + * [iface_facet_any.hpp.j2] + * 3. idl for facet methods + * [idl/IPrintable_DInteger.json5] + **/ + +#pragma once + +#include +#include +#include "DInteger.hpp" + +namespace xo { namespace scm { class IPrintable_DInteger; } } + +namespace xo { + namespace facet { + template <> + struct FacetImplementation + { + using ImplType = xo::print::IPrintable_Xfer + ; + }; + } +} + +namespace xo { + namespace scm { + /** @class IPrintable_DInteger + **/ + class IPrintable_DInteger { + public: + /** @defgroup scm-printable-dinteger-type-traits **/ + ///@{ + using ppindentinfo = xo::print::APrintable::ppindentinfo; + ///@} + /** @defgroup scm-printable-dinteger-methods **/ + ///@{ + /** Pretty-printing support for this object. +See [xo-indentlog/xo/indentlog/pretty.hpp] **/ + static bool pretty(const DInteger & self, const ppindentinfo & ppii); + + ///@} + }; + + } /*namespace scm*/ +} /*namespace xo*/ + +/* end */ diff --git a/include/xo/object2/IPrintable_DList.hpp b/include/xo/object2/IPrintable_DList.hpp index 6a38f02..ac4c531 100644 --- a/include/xo/object2/IPrintable_DList.hpp +++ b/include/xo/object2/IPrintable_DList.hpp @@ -54,4 +54,4 @@ See [xo-indentlog/xo/indentlog/pretty.hpp] **/ } /*namespace scm*/ } /*namespace xo*/ -/* end */ \ No newline at end of file +/* end */ diff --git a/include/xo/object2/object2_register_types.hpp b/include/xo/object2/object2_register_types.hpp index 9b2656a..110779c 100644 --- a/include/xo/object2/object2_register_types.hpp +++ b/include/xo/object2/object2_register_types.hpp @@ -13,6 +13,9 @@ namespace xo { * Return true iff all types register successfully. **/ bool object2_register_types(obj gc); + + /** Register object2 (facet,impl) combinations with FacetRegistry **/ + bool object2_register_facets(); } } diff --git a/src/object2/CMakeLists.txt b/src/object2/CMakeLists.txt index 62754f9..d784e88 100644 --- a/src/object2/CMakeLists.txt +++ b/src/object2/CMakeLists.txt @@ -7,10 +7,12 @@ set(SELF_SRCS IGCObject_DList.cpp ISequence_Any.cpp ISequence_DList.cpp - IPrintable_DFloat.cpp IPrintable_DList.cpp + IPrintable_DFloat.cpp + IPrintable_DInteger.cpp DList.cpp DFloat.cpp + DInteger.cpp object2_register_types.cpp ) diff --git a/src/object2/DInteger.cpp b/src/object2/DInteger.cpp new file mode 100644 index 0000000..1aa3efb --- /dev/null +++ b/src/object2/DInteger.cpp @@ -0,0 +1,32 @@ +/** @file DInteger.cpp +* + * @author Roland Conybeare, Jan 2026 + **/ + +#include "DInteger.hpp" +#include + +namespace xo { + using xo::facet::typeseq; + using xo::print::ppdetail_atomic; + + namespace scm { + DInteger * + DInteger::make(obj mm, + long x) + { + void * mem = mm.alloc(typeseq::id(), + sizeof(DInteger)); + + return new (mem) DInteger(x); + } + + bool + DInteger::pretty(const ppindentinfo & ppii) const + { + return ppdetail_atomic::print_pretty(ppii, value_); + } + } /*namespace scm*/ +} /*namespace xo*/ + +/* end DInteger.cpp */ diff --git a/src/object2/DList.cpp b/src/object2/DList.cpp index 8d851e7..777d503 100644 --- a/src/object2/DList.cpp +++ b/src/object2/DList.cpp @@ -19,18 +19,28 @@ namespace xo { static DList s_null(obj(), nullptr); DList * - DList::null() + DList::_nil() { return &s_null; } + DList * + DList::_cons(obj mm, + obj car, + DList * cdr) + { + void * mem = mm.alloc(typeseq::id(), sizeof(DList)); + + return new (mem) DList(car, cdr); + } + DList * DList::list(obj mm, obj h1) { void * mem = mm.alloc(typeseq::id(), sizeof(DList)); - return new (mem) DList(h1, DList::null()); + return new (mem) DList(h1, DList::_nil()); } DList * @@ -112,7 +122,8 @@ namespace xo { obj elt = FacetRegistry::instance().variant(l->head_); - // what if no converter registered ? + + assert(elt); if (!pps->print_upto(elt)) return false; diff --git a/src/object2/IPrintable_DInteger.cpp b/src/object2/IPrintable_DInteger.cpp new file mode 100644 index 0000000..8e9bc77 --- /dev/null +++ b/src/object2/IPrintable_DInteger.cpp @@ -0,0 +1,28 @@ +/** @file IPrintable_DInteger.cpp + * + * Generated automagically from ingredients: + * 1. code generator: + * [/home/roland/proj/xo-umbrella2/xo-facet/codegen/genfacet] + * arguments: + * --input [idl/IPrintable_DInteger.json5] + * 2. jinja2 template for abstract facet .hpp file: + * [iface_facet_any.hpp.j2] + * 3. idl for facet methods + * [idl/IPrintable_DInteger.json5] +**/ + +#include "IPrintable_DInteger.hpp" + +namespace xo { + namespace scm { + auto + IPrintable_DInteger::pretty(const DInteger & self, const ppindentinfo & ppii) -> bool + { + return self.pretty(ppii); + } + + + } /*namespace scm*/ +} /*namespace xo*/ + +/* end IPrintable_DInteger.cpp */ diff --git a/src/object2/object2_register_types.cpp b/src/object2/object2_register_types.cpp index e472401..131b8cf 100644 --- a/src/object2/object2_register_types.cpp +++ b/src/object2/object2_register_types.cpp @@ -4,22 +4,36 @@ **/ #include "object2_register_types.hpp" + #include "IGCObject_DList.hpp" #include "IGCObject_DFloat.hpp" #include "IGCObject_DInteger.hpp" +#include "IPrintable_DList.hpp" +//#include "IPrintable_DFloat.hpp" +#include "IPrintable_DInteger.hpp" + +#include +#include + namespace xo { + using xo::print::APrintable; + using xo::mm::AAllocator; using xo::mm::ACollector; using xo::mm::AGCObject; using xo::mm::IGCObject_Any; + using xo::facet::FacetRegistry; using xo::facet::impl_for; using xo::facet::typeseq; + using xo::scope; namespace scm { bool object2_register_types(obj gc) { + scope log(XO_DEBUG(true)); + bool ok = true; ok &= gc.install_type(impl_for()); @@ -28,6 +42,31 @@ namespace xo { return ok; } + + bool + object2_register_facets() + { + scope log(XO_DEBUG(true)); + + FacetRegistry::register_impl(); + FacetRegistry::register_impl(); + + FacetRegistry::register_impl(); +// FacetRegistry::register_impl(); + + FacetRegistry::register_impl(); + FacetRegistry::register_impl(); + + log && log(xtag("DList.tseq", typeseq::id())); + log && log(xtag("DFloat.tseq", typeseq::id())); + log && log(xtag("DInteger.tseq", typeseq::id())); + + log && log(xtag("AAllocator.tseq", typeseq::id())); + log && log(xtag("APrintable.tseq", typeseq::id())); + log && log(xtag("AGCObject.tseq", typeseq::id())); + + return true; + } } } /*namespace xo*/ diff --git a/utest/CMakeLists.txt b/utest/CMakeLists.txt index 258f56a..7054457 100644 --- a/utest/CMakeLists.txt +++ b/utest/CMakeLists.txt @@ -4,6 +4,7 @@ set(UTEST_EXE utest.object2) set(UTEST_SRCS object2_utest_main.cpp X1Collector.test.cpp + Printable.test.cpp ) xo_add_utest_executable(${UTEST_EXE} ${UTEST_SRCS}) diff --git a/utest/Printable.test.cpp b/utest/Printable.test.cpp new file mode 100644 index 0000000..d385a8e --- /dev/null +++ b/utest/Printable.test.cpp @@ -0,0 +1,141 @@ +/** @file Printable.test.cpp + * + * @author Roland Conybeare, Jan 2026 + **/ + +#include "DList.hpp" +#include "object2_register_types.hpp" + +#include +#include +#include + +#include +#include + +#include +#include +#include +#include + +#include + +#include + +#include +#include + +#include + +namespace ut { + using xo::scm::object2_register_types; + using xo::scm::object2_register_facets; + using xo::scm::DList; + using xo::scm::DInteger; + using xo::mm::AAllocator; + using xo::mm::ACollector; + using xo::mm::AGCObject; + using xo::mm::DX1Collector; + using xo::mm::CollectorConfig; + using xo::mm::ArenaConfig; + using xo::print::APrintable; + using xo::facet::FacetRegistry; + using xo::facet::with_facet; + using xo::facet::obj; + using xo::facet::typeseq; + using xo::print::ppstate_standalone; + using xo::print::ppconfig; + using xo::scope; + using xo::xtag; + using std::string; + + namespace { + struct testcase_pp { + explicit testcase_pp(size_t gc_z, size_t gc_threshold, int z, const std::string & expected) + : gc_gen_size_{gc_z}, gc_trigger_threshold_{gc_threshold}, expected_{expected} { + for (int i = 0; i < z; ++i) { + list_.push_back(1000 + 197 * i); + } + } + + size_t gc_gen_size_ = 0; + size_t gc_trigger_threshold_ = 0; + std::vector list_; + std::string expected_; + }; + + std::vector + s_testcase_v = { + testcase_pp(16384, 8192, 0, "()"), + testcase_pp(16384, 8192, 1, "(1000)"), + testcase_pp(16384, 8192, 2, "(1000 1197)"), + testcase_pp(16384, 8192, 5, "(1000 1197 1394 1591 1788)"), + testcase_pp(16384, 8192, 10, "(1000 1197 1394 1591 1788 1985 2182 2379 2576 2773)"), + testcase_pp(16384, 8192, 20, "(...)"), + }; + } + + TEST_CASE("printable1", "[pp][x1][list]") + { + constexpr bool c_debug_flag = true; + scope log(XO_DEBUG(c_debug_flag)); + + bool ok = object2_register_facets(); + REQUIRE(ok); + + FacetRegistry::instance().dump(&std::cerr); + + for (std::size_t i_tc = 0, n_tc = s_testcase_v.size(); i_tc < n_tc; ++i_tc) { + try { + const testcase_pp & tc = s_testcase_v[i_tc]; + + CollectorConfig cfg{ + .name_ = "pp_test", + .arena_config_ = ArenaConfig{ + .size_ = tc.gc_gen_size_, + .store_header_flag_ = true}, + .object_types_z_ = 16384, + .gc_trigger_v_{{tc.gc_trigger_threshold_, + tc.gc_trigger_threshold_}}, + .debug_flag_ = c_debug_flag + }; + + DX1Collector gc(cfg); + auto gc_o = with_facet::mkobj(&gc); + auto c_o = with_facet::mkobj(&gc); + + bool ok = object2_register_types(c_o); + REQUIRE(ok); + + auto l0_o = DList::nil(); + + c_o.add_gc_root(&l0_o); + + for(int ip1 = tc.list_.size(); ip1 > 0; --ip1) { + // auto xi_o = Integer::make(g_o, ...); + DInteger * xi = DInteger::make(gc_o, tc.list_[ip1 - 1]); + auto xi_o = with_facet::mkobj(xi); + + l0_o = DList::cons(gc_o, xi_o, l0_o); + } + + // TODO: log_streambuf using DArena + std::stringstream ss; + ppconfig ppc; + ppstate_standalone pps(&ss, 0, &ppc); + + obj l0_po(static_cast(l0_o.data())); + REQUIRE(l0_po._typeseq() == typeseq::id()); + + pps.pretty(l0_po); + + REQUIRE(ss.str() == string(tc.expected_)); + } catch (std::exception & ex) { + std::cerr << "caught exception: " << ex.what() << std::endl; + REQUIRE(false); + } + } + } /* TEST_CASE(printable1) */ +} + +/* end Printable.test.cpp */ diff --git a/utest/X1Collector.test.cpp b/utest/X1Collector.test.cpp index 8b37c8a..9d4256a 100644 --- a/utest/X1Collector.test.cpp +++ b/utest/X1Collector.test.cpp @@ -74,7 +74,7 @@ namespace ut { TEST_CASE("x1", "[gc][x1]") { - constexpr bool c_debug_flag = true; + constexpr bool c_debug_flag = false; 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) {