From 1da2d17c3095520a74fe93a5448281857da791df Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Sat, 31 Jan 2026 01:44:53 -0500 Subject: [PATCH] xo-expression2 xo-gc: DSequenceExpr builds [WIP] --- include/xo/object2/GCObjectConverter.hpp | 158 ++++++++++++++ src/object2/GCObjectConverter.cpp | 258 +++++++++++++++++++++++ 2 files changed, 416 insertions(+) create mode 100644 include/xo/object2/GCObjectConverter.hpp create mode 100644 src/object2/GCObjectConverter.cpp diff --git a/include/xo/object2/GCObjectConverter.hpp b/include/xo/object2/GCObjectConverter.hpp new file mode 100644 index 0000000..bf244f4 --- /dev/null +++ b/include/xo/object2/GCObjectConverter.hpp @@ -0,0 +1,158 @@ +/** @file GCObjectConverter.hpp + * + * @author Roland Conybeare, Nov 2025 + **/ + +#pragma once + +#include +#include +#include +//#include "xo/reflect/TaggedPtr.hpp" +#include + +namespace xo { + namespace scm { + /* Convert between xo::reflect::TaggedPtr and xo::Object for + * a particular wrapped c++ type + */ + struct Converter { + using AAllocator = xo::mm::AAllocator; + using AGCObject = xo::mm::AGCObject; + using TaggedPtr = xo::reflect::TaggedPtr; + /** convert from some reflected T* @p src to + * obj dest + * using memory from allocator @p mm + **/ + using ConvertToObjectFn = obj (*)(obj mm, + TaggedPtr src); + /** convert from obj @p src to some refected T* @p dest + * using memory from allocator @p mm. + * + * NOTE: obj is gc-aware -> will likely reside in + * a collected memory region. + **/ + using ConvertFromObjectFn = TaggedPtr (*)(obj mm, + obj obj); + + public: + Converter() = default; + explicit Converter(ConvertToObjectFn to, + ConvertFromObjectFn from) + : cvt_to_object_{to}, + cvt_from_object_{from} + {} + + /** convert tagged pointer @p tp to new object, + * allocated via @p mm. + * + * Conversion will typically be for some specific type; + * see @ref ObjectConverter + **/ + ConvertToObjectFn cvt_to_object_ = nullptr; + + /** convert object to tagged pointer @p, + * allocated via @p mm. + * + * Conversion will typically be for some specific type; + * see @ref ObjectConverter + **/ + ConvertFromObjectFn cvt_from_object_ = nullptr; + }; + + /** @class ObjectConverter + * @brief Conversion to/from Object + * + * For some instance of type T: + * + * @code + * ObjectConverter & converters = ...; + * T x = ...; + * TaggedPtr tp = Reflect::make_tp(&x); + * TypeId tid = tp.td()->id(); + * + * const Converter * cvt = converters.cvt_.lookup(tid); + * + * if (cvt) { + * // cvt is a converter for T instances + * gp obj = (*(cvt->cvt_to_object_))(mm, + * @endcode + **/ + class ObjectConverter { + public: + using AAllocator = xo::mm::AAllocator; + using AGCObject = xo::mm::AGCObject; + using Reflect = xo::reflect::Reflect; + using TaggedPtr = xo::reflect::TaggedPtr; + using TypeId = xo::reflect::TypeId; + + /** sets up standard conversions **/ + ObjectConverter(); + + /** singleton instance **/ + static const ObjectConverter & instance(); + + /** establish conversion: use @p fn to convert values of type @tparam T. **/ + template + void establish_conversion(Converter::ConvertToObjectFn to, + Converter::ConvertFromObjectFn from); + + /** convert tagged poitner @p tp to object. allocates memory only from @p mm. + * return nullptr if no converter available and @p throw_flag not set. + * throw exception if no converter available and @p throw_flag set. + **/ + obj tp_to_gco(obj mm, + TaggedPtr tp, + bool throw_flag) const; + + /** convert @p x to object. + * return converted object; if allocated, using only memory from @p mm. + * return nullptr if no converter available, and @p throw_flag not set. + * throw exception if no converter available, and @p throw_flag set. + **/ + template + obj to_gco(obj mm, const T & x, bool throw_flag); + + /** convert object @p obj to tagged pointer, with typeid @p target_id. + * Allocates memory only from @p mm. + * return null TaggedPtr if no converter available and @p throw_flag not set. + * Throw exception if no converter available and @p throw_flag set. + **/ + TaggedPtr tp_from_gco(obj mm, + obj obj, + TypeId target_type_id, + bool throw_flag) const; + + private: + /** expandable type-driven conversion table. + **/ + xo::reflect::TypeDrivenMap cvt_; + }; + + template + void + ObjectConverter::establish_conversion(Converter::ConvertToObjectFn to, + Converter::ConvertFromObjectFn from) + { + using xo::reflect::TypeDescrW; + using xo::reflect::Reflect; + + TypeDescrW td = Reflect::require(); + Converter * cvt = cvt_.require(td); + + *cvt = Converter(to, from); + } + + template + auto + ObjectConverter::to_gco(obj mm, const T & x, bool throw_flag) + -> obj + { + TaggedPtr x_tp = Reflect::make_tp(&x); + + return tp_to_gco(mm, x_tp, throw_flag); + } + } /*namespace scm*/ +} /*namespace xo*/ + +/* end GCObjectConverter.hpp */ diff --git a/src/object2/GCObjectConverter.cpp b/src/object2/GCObjectConverter.cpp new file mode 100644 index 0000000..6f3f5b4 --- /dev/null +++ b/src/object2/GCObjectConverter.cpp @@ -0,0 +1,258 @@ +/** @file GCObjectConverter.cpp + * + * @author Roland Conybeare, Nov 2025 + **/ + +#include "GCObjectConverter.hpp" + +#include "DInteger.hpp" +#include "number/IGCObject_DInteger.hpp" + +#include "DFloat.hpp" +#include "number/IGCObject_DFloat.hpp" + +#include "DBoolean.hpp" +#include "boolean/IGCObject_DBoolean.hpp" + +#include "DString.hpp" +#include "string/IGCObject_DString.hpp" + +#include +#include +//#include "xo/alloc/Blob.hpp" + +namespace xo { + using xo::mm::AGCObject; + using xo::reflect::Reflect; + using xo::reflect::TaggedPtr; + using xo::reflect::TypeId; + using xo::facet::obj; + using xo::facet::typeseq; + using xo::mm::AAllocator; + + namespace scm { + namespace { + // DInteger <-> T + + template + obj + int_to_gco(obj mm, TaggedPtr src) + { + T * native = src.recover_native(); + + assert(native); + + return DInteger::box(mm, *native); + } + + template + TaggedPtr + gco_to_int(obj mm, + obj obj) + { + + /* mm cannot be GC allocator! + * That's Object-only + */ + + auto int_obj = xo::facet::obj::from(obj); //Integer::from(obj); + + if (!int_obj) { + throw std::runtime_error + (tostr("Object obj found where Integer expected", + xtag("obj", obj))); + } + + void * mem = mm.alloc(typeseq::id(), sizeof(T)); + + T * p = reinterpret_cast(mem); + + *p = int_obj.data()->value(); + + /* Note: + * retval invalidated when + * *mm cleared/recycled/collected + */ + + return Reflect::make_tp(p); + } + + // DFloat <-> T + + template + xo::facet::obj + float_to_gco(xo::facet::obj mm, + TaggedPtr src) + { + T * native = src.recover_native(); + + assert(native); + + return DFloat::box(mm, *native); + } + + template + TaggedPtr + gco_to_float(obj mm, obj obj) + { + auto float_obj = xo::facet::obj::from(obj); + + if (!float_obj) { + throw std::runtime_error + (tostr("Object obj found where Float expected", + xtag("obj", obj))); + } + + void * mem = mm.alloc(typeseq::id(), sizeof(T)); + + T * p = reinterpret_cast(mem); + + *p = float_obj.data()->value(); + + /* Note: + * retval invalidated when *mm cleared/recycled/collected + */ + + return Reflect::make_tp(p); + } + + // DBoolean <-> T + + obj + bool_to_gco(obj mm, TaggedPtr src) + { + bool * native = src.recover_native(); + + assert(native); + + return DBoolean::box(mm, *native); + } + + TaggedPtr + gco_to_bool(obj /*mm*/, + obj obj) + { + static bool s_true = true; + static bool s_false = false; + + auto bool_obj = xo::facet::obj::from(obj); + + if (!bool_obj) { + throw std::runtime_error + (tostr("Object obj found where Boolean expected", + xtag("obj", obj))); + } + + return Reflect::make_tp(bool_obj.data()->value() ? &s_true : &s_false); + } + + // DString <-> T + // w/ + // T = std::string + + obj + string_to_gco(obj mm, TaggedPtr src) + { + // try std::string.. + + std::string * native = src.recover_native(); + + assert(native); + + DString * dstr = DString::from_str(mm, *native); + + return xo::facet::obj(dstr); + } + + TaggedPtr + gco_to_string(obj mm, obj obj) + { + auto string_obj = xo::facet::obj::from(obj); + + if (!string_obj) { + throw std::runtime_error + (tostr("Object obj founcd where String expected", + xtag("obj", obj))); + } + + // still don't have impl for this + // Need regular std::allocator interface + // + + (void)mm; + assert(false); + } + } + + ObjectConverter::ObjectConverter() + { + this->establish_conversion(&int_to_gco, + &gco_to_int); + this->establish_conversion(&int_to_gco, + &gco_to_int); + + this->establish_conversion(&float_to_gco, + &gco_to_float); + + this->establish_conversion(&bool_to_gco, + &gco_to_bool); + + this->establish_conversion(&string_to_gco, + &gco_to_string); + } + + const ObjectConverter & + ObjectConverter::instance() { + static ObjectConverter s_instance; + + return s_instance; + } + + obj + ObjectConverter::tp_to_gco(obj mm, + TaggedPtr x_tp, + bool throw_flag) const + { + using xo::reflect::Reflect; + using xo::reflect::TaggedPtr; + + const Converter * cvt = cvt_.lookup(x_tp.td()); + + if (cvt) { + return (cvt->cvt_to_object_)(mm, x_tp); + } else { + if (throw_flag) { + throw std::runtime_error + (tostr("no to-object-converter available for instance of type", + xtag("id", x_tp.td()->id()), + xtag("name", x_tp.td()->short_name()))); + } + + return obj(); + } + } + + TaggedPtr + ObjectConverter::tp_from_gco(obj mm, + obj obj, + TypeId target_id, + bool throw_flag) const + { + const Converter * cvt = cvt_.lookup(target_id); + + if (cvt) { + return (cvt->cvt_from_object_)(mm, obj); + } else { + if (throw_flag) { + throw std::runtime_error + (tostr("no from-object-converter available for instance of type", + xtag("id", target_id))); + } + + return TaggedPtr::universal_null(); + } + } + } +} + +/* end GCObjectConverter.cpp */