xo-objectd2 xo-printable xo-facet: pp working for List(Integer)

Also streamline facet switching
This commit is contained in:
Roland Conybeare 2026-01-09 17:48:54 -05:00
commit 148d5e9ca0
13 changed files with 379 additions and 8 deletions

View file

@ -5,11 +5,32 @@
#pragma once
#include <xo/alloc2/Allocator.hpp>
#include <xo/indentlog/print/ppindentinfo.hpp>
#include <cstdint>
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<AAllocator> 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*/

View file

@ -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<AGCObject> h,
DList * r) : head_{h}, rest_{r} {}
template <typename AConsFacet = AGCObject>
static obj<AConsFacet,DList> nil();
/** shortcut for
* cons(mm, cdr, cdr.data())
**/
template <typename AConsFacet = AGCObject, typename ACdrFacet = AGCObject>
static obj<AConsFacet,DList> cons(obj<AAllocator> mm,
obj<AGCObject> car,
obj<ACdrFacet,DList> 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<AAllocator> mm,
obj<AGCObject> car,
DList * cdr);
/** list with one element @p h1, allocated from @p mm **/
static DList * list(obj<AAllocator> mm,
@ -51,6 +71,22 @@ namespace xo {
DList * rest_ = nullptr;
};
template <typename AConsFacet>
obj<AConsFacet,DList>
DList::nil()
{
return obj<AConsFacet,DList>(DList::_nil());
}
template <typename AConsFacet, typename ACdrFacet>
obj<AConsFacet,DList>
DList::cons(obj<AAllocator> mm,
obj<AGCObject> car,
obj<ACdrFacet,DList> cdr)
{
return obj<AConsFacet,DList>(DList::_cons(mm, car, cdr.data()));
}
} /*namespace scm*/
} /*namespace xo*/

View file

@ -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 <xo/printable2/Printable.hpp>
#include <xo/printable2/detail/IPrintable_Xfer.hpp>
#include "DInteger.hpp"
namespace xo { namespace scm { class IPrintable_DInteger; } }
namespace xo {
namespace facet {
template <>
struct FacetImplementation<xo::print::APrintable,
xo::scm::DInteger>
{
using ImplType = xo::print::IPrintable_Xfer
<xo::scm::DInteger,
xo::scm::IPrintable_DInteger>;
};
}
}
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 */

View file

@ -54,4 +54,4 @@ See [xo-indentlog/xo/indentlog/pretty.hpp] **/
} /*namespace scm*/
} /*namespace xo*/
/* end */
/* end */

View file

@ -13,6 +13,9 @@ namespace xo {
* Return true iff all types register successfully.
**/
bool object2_register_types(obj<xo::mm::ACollector> gc);
/** Register object2 (facet,impl) combinations with FacetRegistry **/
bool object2_register_facets();
}
}

View file

@ -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
)

32
src/object2/DInteger.cpp Normal file
View file

@ -0,0 +1,32 @@
/** @file DInteger.cpp
*
* @author Roland Conybeare, Jan 2026
**/
#include "DInteger.hpp"
#include <xo/indentlog/print/pretty.hpp>
namespace xo {
using xo::facet::typeseq;
using xo::print::ppdetail_atomic;
namespace scm {
DInteger *
DInteger::make(obj<AAllocator> mm,
long x)
{
void * mem = mm.alloc(typeseq::id<DInteger>(),
sizeof(DInteger));
return new (mem) DInteger(x);
}
bool
DInteger::pretty(const ppindentinfo & ppii) const
{
return ppdetail_atomic<long>::print_pretty(ppii, value_);
}
} /*namespace scm*/
} /*namespace xo*/
/* end DInteger.cpp */

View file

@ -19,18 +19,28 @@ namespace xo {
static DList s_null(obj<AGCObject>(), nullptr);
DList *
DList::null()
DList::_nil()
{
return &s_null;
}
DList *
DList::_cons(obj<AAllocator> mm,
obj<AGCObject> car,
DList * cdr)
{
void * mem = mm.alloc(typeseq::id<DList>(), sizeof(DList));
return new (mem) DList(car, cdr);
}
DList *
DList::list(obj<AAllocator> mm,
obj<AGCObject> h1)
{
void * mem = mm.alloc(typeseq::id<DList>(), sizeof(DList));
return new (mem) DList(h1, DList::null());
return new (mem) DList(h1, DList::_nil());
}
DList *
@ -112,7 +122,8 @@ namespace xo {
obj<APrintable> elt
= FacetRegistry::instance().variant<APrintable, AGCObject>(l->head_);
// what if no converter registered ?
assert(elt);
if (!pps->print_upto(elt))
return false;

View file

@ -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 */

View file

@ -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 <xo/facet/FacetRegistry.hpp>
#include <xo/indentlog/scope.hpp>
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<ACollector> gc)
{
scope log(XO_DEBUG(true));
bool ok = true;
ok &= gc.install_type(impl_for<AGCObject, DList>());
@ -28,6 +42,31 @@ namespace xo {
return ok;
}
bool
object2_register_facets()
{
scope log(XO_DEBUG(true));
FacetRegistry::register_impl<AGCObject, DList>();
FacetRegistry::register_impl<APrintable, DList>();
FacetRegistry::register_impl<AGCObject, DFloat>();
// FacetRegistry::register_impl<APrintable, DFloat>();
FacetRegistry::register_impl<AGCObject, DInteger>();
FacetRegistry::register_impl<APrintable, DInteger>();
log && log(xtag("DList.tseq", typeseq::id<DList>()));
log && log(xtag("DFloat.tseq", typeseq::id<DFloat>()));
log && log(xtag("DInteger.tseq", typeseq::id<DInteger>()));
log && log(xtag("AAllocator.tseq", typeseq::id<AAllocator>()));
log && log(xtag("APrintable.tseq", typeseq::id<APrintable>()));
log && log(xtag("AGCObject.tseq", typeseq::id<AGCObject>()));
return true;
}
}
} /*namespace xo*/

View file

@ -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})

141
utest/Printable.test.cpp Normal file
View file

@ -0,0 +1,141 @@
/** @file Printable.test.cpp
*
* @author Roland Conybeare, Jan 2026
**/
#include "DList.hpp"
#include "object2_register_types.hpp"
#include <xo/object2/DList.hpp>
#include <xo/object2/IGCObject_DList.hpp>
#include <xo/object2/IPrintable_DList.hpp>
#include <xo/object2/DInteger.hpp>
#include <xo/object2/IGCObject_DInteger.hpp>
#include <xo/gc/Collector.hpp>
#include <xo/gc/DX1Collector.hpp>
#include <xo/gc/detail/IAllocator_DX1Collector.hpp>
#include <xo/gc/detail/ICollector_DX1Collector.hpp>
#include <xo/printable2/Printable.hpp>
#include <xo/facet/FacetRegistry.hpp>
#include <xo/indentlog/scope.hpp>
#include <xo/indentlog/print/tag.hpp>
#include <catch2/catch.hpp>
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<int> list_;
std::string expected_;
};
std::vector<testcase_pp>
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<AAllocator>::mkobj(&gc);
auto c_o = with_facet<ACollector>::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<AGCObject>::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<APrintable,DList> l0_po(static_cast<DList*>(l0_o.data()));
REQUIRE(l0_po._typeseq() == typeseq::id<DList>());
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 */

View file

@ -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) {