From 3b1be6843c1f126da29b233e05f67d9fcd192749 Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Thu, 25 Dec 2025 12:33:07 -0500 Subject: [PATCH] xo-facet: extend facet gen scope to IFoo_{Xfer,Any}, RFoo --- .../xo/alloc2/alloc/IAllocator_Any.hpp | 1 - xo-alloc2/src/alloc2/IAllocator_Any.cpp | 8 -- xo-facet/codegen/abstract_facet.hpp.j2 | 14 +++ xo-facet/codegen/genfacet.py | 82 ++++++++++++--- xo-facet/codegen/iface_facet_any.cpp.j2 | 38 +++++++ xo-facet/codegen/iface_facet_any.hpp.j2 | 89 ++++++++++++----- xo-facet/codegen/iface_facet_xfer.hpp.j2 | 99 +++++++++++++++++++ xo-facet/codegen/router_facet.hpp.j2 | 94 ++++++++++++++++++ xo-object2/idl/Sequence.json5 | 1 + xo-object2/include/xo/object2/ASequence.hpp | 50 ++++++++-- xo-object2/src/object2/CMakeLists.txt | 1 + 11 files changed, 420 insertions(+), 57 deletions(-) create mode 100644 xo-facet/codegen/iface_facet_any.cpp.j2 create mode 100644 xo-facet/codegen/iface_facet_xfer.hpp.j2 create mode 100644 xo-facet/codegen/router_facet.hpp.j2 diff --git a/xo-alloc2/include/xo/alloc2/alloc/IAllocator_Any.hpp b/xo-alloc2/include/xo/alloc2/alloc/IAllocator_Any.hpp index 842d147e..dd0df835 100644 --- a/xo-alloc2/include/xo/alloc2/alloc/IAllocator_Any.hpp +++ b/xo-alloc2/include/xo/alloc2/alloc/IAllocator_Any.hpp @@ -8,7 +8,6 @@ #include "AAllocator.hpp" #include "AllocIterator.hpp" #include -#include namespace xo { namespace mm { struct IAllocator_Any; } diff --git a/xo-alloc2/src/alloc2/IAllocator_Any.cpp b/xo-alloc2/src/alloc2/IAllocator_Any.cpp index 081a78e9..1d12c6cb 100644 --- a/xo-alloc2/src/alloc2/IAllocator_Any.cpp +++ b/xo-alloc2/src/alloc2/IAllocator_Any.cpp @@ -27,14 +27,6 @@ namespace xo { std::terminate(); } -#ifdef NOPE - vt - IAllocator_Any::begin(Copaque, DArena &) const noexcept - { - _fatal(); - } -#endif - int32_t IAllocator_Any::s_typeseq = typeseq::id(); diff --git a/xo-facet/codegen/abstract_facet.hpp.j2 b/xo-facet/codegen/abstract_facet.hpp.j2 index a100fd77..59e61270 100644 --- a/xo-facet/codegen/abstract_facet.hpp.j2 +++ b/xo-facet/codegen/abstract_facet.hpp.j2 @@ -32,12 +32,23 @@ using Opaque = void *; **/ class {{abstract_facet}} { public: + {% if using_dox %} + /** @defgroup {{facet_ns2}}-{{facet_name_lc}}-type-traits **/ + ///@{ + {% endif %} // types {% for ty in types %} /** {{ty.doc}} **/ using {{ty.name}} = {{ty.definition}}; {% endfor %} + {% if using_dox %} + ///@} + {% endif %} + {% if using_dox %} + /** @defgroup {{facet_ns2}}-{{facet_name_lc}}-methods **/ + ///@{ + {% endif %} // const methods /** RTTI: unique id# for actual runtime data representation **/ virtual int32_t _typeseq() const noexcept = 0; @@ -51,6 +62,9 @@ public: /** {{md.doc}} **/ virtual {{md.return_type}} {{md.name}}({{md.args | args}}) {{md | qualifiers}} = 0; {% endfor %} + {% if using_dox %} + ///@} + {% endif %} }; /*{{abstract_facet}}*/ /** Implementation {{iface_facet}}_DRepr of {{abstract_facet}} for state DRepr diff --git a/xo-facet/codegen/genfacet.py b/xo-facet/codegen/genfacet.py index 36b8396f..8668c4da 100755 --- a/xo-facet/codegen/genfacet.py +++ b/xo-facet/codegen/genfacet.py @@ -38,18 +38,36 @@ def format_args_nonames(args): def format_arg_names(args): """ Format argument names, for forwarding """ - return ', '.join(p['name'] for p in args) + names = [p['name'] for p in args] + return ', '.join([f"_dcast({names[0]})"] + names[1:]) + +def format_args_nodata(args): + """ Format arguments, but exclude data arg + """ + return format_args(args[1:]) + +def format_args_routing(args): + """ Format argument names, for routing + """ + names = [p['name'] for p in args] + return ', '.join([f"O::data()"] + names[1:]) def main(): parser = argparse.ArgumentParser() parser.add_argument('--input', required=True, help='input IDL JSON5 file') - parser.add_argument('--output', required=True, help='output directory') + parser.add_argument('--output-hpp', required=True, help='.hpp output directory') + parser.add_argument('--output-cpp', required=True, help='.cpp output directory') + args = parser.parse_args() idl_fname = args.input idl = load_idl(idl_fname) - output_dir = Path(args.output) - output_dir.mkdir(parents=False, exist_ok=True) + # + output_hpp_dir = Path(args.output_hpp) + output_hpp_dir.mkdir(parents=False, exist_ok=True) + # + output_cpp_dir = Path(args.output_cpp) + output_cpp_dir.mkdir(parents=False, exist_ok=True) # setup jinja2 template_dir = Path(__file__).parent @@ -66,11 +84,17 @@ def main(): env.filters['args'] = format_args env.filters['argtypes'] = format_args_nonames env.filters['argnames'] = format_arg_names + env.filters['argsnodata'] = format_args_nodata + env.filters['argrouting'] = format_args_routing + + # true to insert doxygen markup in generated .hpp/.cpp files + using_dox = idl['using_doxygen'] facet_includes = idl['includes'] facet_ns1 = idl['namespace1'] facet_ns2 = idl['namespace2'] facet_name = idl['facet'] # e.g. Sequence + facet_name_lc = facet_name.lower() facet_brief = idl['brief'] facet_doc = '\n'.join(idl['doc']) @@ -95,15 +119,25 @@ def main(): iface_facet_impltype = f'{iface_facet}_ImplType' # iface_facet_any = f'{iface_facet}_Any' - iface_facet_any_fname = f'{iface_facet_any}.hpp' + iface_facet_any_hpp_fname = f'{iface_facet_any}.hpp' + iface_facet_any_cpp_fname = f'{iface_facet_any}.cpp' + # + iface_facet_xfer = f'{iface_facet}_Xfer' + iface_facet_xfer_hpp_fname = f'{iface_facet_xfer}.hpp' + iface_facet_xfer_cpp_fname = f'{iface_facet_xfer}.cpp' + # + router_facet = f'R{facet_name}' + router_facet_hpp_fname = f'{router_facet}.hpp' context = { 'genfacet': __file__, 'genfacet_input': args.input, + 'using_dox': using_dox, # 'facet_includes': facet_includes, 'facet_ns1': facet_ns1, 'facet_ns2': facet_ns2, + 'facet_name_lc': facet_name_lc, #'name': facet_name, 'idl_fname': idl_fname, # @@ -117,7 +151,19 @@ def main(): # 'iface_facet_any': iface_facet_any, 'iface_facet_any_hpp_j2': 'iface_facet_any.hpp.j2', - 'iface_facet_any_fname': iface_facet_any_fname, + 'iface_facet_any_cpp_j2': 'iface_facet_any.cpp.j2', + 'iface_facet_any_hpp_fname': iface_facet_any_hpp_fname, + 'iface_facet_any_cpp_fname': iface_facet_any_cpp_fname, + # + 'iface_facet_xfer': iface_facet_xfer, + 'iface_facet_xfer_hpp_j2': 'iface_facet_xfer.hpp.j2', + 'iface_facet_xfer_cpp_j2': 'iface_facet_xfer.cpp.j2', + 'iface_facet_xfer_hpp_fname': iface_facet_xfer_hpp_fname, + 'iface_facet_xfer_cpp_fname': iface_facet_xfer_cpp_fname, + # + 'router_facet': router_facet, + 'router_facet_hpp_j2': 'router_facet.hpp.j2', + 'router_facet_hpp_fname': router_facet_hpp_fname, # 'types': types, # @@ -129,18 +175,30 @@ def main(): # generate .hpp files templates = {} - templates[abstract_facet_fname] = context['abstract_facet_hpp_j2'] - templates[iface_facet_any_fname] = context['iface_facet_any_hpp_j2'] + templates[abstract_facet_fname] = [output_hpp_dir, + context['abstract_facet_hpp_j2']] + templates[iface_facet_any_hpp_fname] = [output_hpp_dir, + context['iface_facet_any_hpp_j2']] + templates[iface_facet_any_cpp_fname] = [output_cpp_dir, + context['iface_facet_any_cpp_j2']] + templates[iface_facet_xfer_hpp_fname] = [output_hpp_dir, + context['iface_facet_xfer_hpp_j2']] + templates[router_facet_hpp_fname] = [output_hpp_dir, + context['router_facet_hpp_j2']] - for output_file, template_name in templates.items(): - print(f'output_file: [{output_file}]') + for out_file, record in templates.items(): + out_dir = record[0] + template_name = record[1] + + print(f'out_dir: [{out_dir}]') + print(f'out_file: [{out_file}]') print(f'template_name: [{template_name}]') template = env.get_template(template_name) content = template.render(**context) - (output_dir / output_file).write_text(content) - print(f"Generated {output_dir}/{output_file}") + (out_dir / out_file).write_text(content) + print(f"Generated {out_dir}/{out_file}") if __name__ == '__main__': diff --git a/xo-facet/codegen/iface_facet_any.cpp.j2 b/xo-facet/codegen/iface_facet_any.cpp.j2 new file mode 100644 index 00000000..2f11e38b --- /dev/null +++ b/xo-facet/codegen/iface_facet_any.cpp.j2 @@ -0,0 +1,38 @@ +/** @file {{iface_facet_any_cpp_fname}} + * + **/ + +#include "{{iface_facet_any_hpp_fname}}" +#include + +namespace {{facet_ns1}} { +namespace {{facet_ns2}} { + +using xo::facet::DVariantPlaceholder; +using xo::facet::typeseq; +using xo::facet::valid_facet_implementation; + +void +{{iface_facet_any}}::_fatal() +{ + /* control here on uninitialized IAllocator_Any. + * Initialized instance will have specific implementation type + */ + std::cerr << "fatal" + << ": attempt to call uninitialized" + << " {{iface_facet_any}} method" + << std::endl; + std::terminate(); +} + +int32_t +{{iface_facet_any}}::s_typeseq = typeseq::id(); + +bool +{{iface_facet_any}}::_valid + = valid_facet_implementation<{{abstract_facet}}, {{iface_facet_any}}>(); + +} /*namespace {{facet_ns2}}*/ +} /*namespace {{facet_ns1}}*/ + +/* end {{iface_facet_any_cpp_fname}} */ diff --git a/xo-facet/codegen/iface_facet_any.hpp.j2 b/xo-facet/codegen/iface_facet_any.hpp.j2 index 11bbef36..70a27a98 100644 --- a/xo-facet/codegen/iface_facet_any.hpp.j2 +++ b/xo-facet/codegen/iface_facet_any.hpp.j2 @@ -1,4 +1,4 @@ -/** @file {{iface_facet_any_fname}} +/** @file {{iface_facet_any_hpp_fname}} * * Generated automagically from ingredients: * 1. code generator: @@ -34,39 +34,74 @@ struct FacetImplementation<{{facet_ns1}}::{{facet_ns2}}::{{abstract_facet}}, namespace {{facet_ns1}} { namespace {{facet_ns2}} { -/** @class {{iface_facet_any}} - * @brief {{abstract_facet}} implementation for empty variant instance - **/ -class {{iface_facet_any}} : public {{abstract_facet}} { -public: - {% for ty in types %} - using {{ty.name}} = {{abstract_facet}}::{{ty.name}}; - {% endfor %} + /** @class {{iface_facet_any}} + * @brief {{abstract_facet}} implementation for empty variant instance + **/ + class {{iface_facet_any}} : public {{abstract_facet}} { + public: + {% if using_dox %} + /** @defgroup {{facet_ns2}}-{{facet_name_lc}}-any-type-traits **/ + ///@{ + {% endif %} - const {{abstract_facet}} * iface() const { return std::launder(this); } + {% for ty in types %} + using {{ty.name}} = {{abstract_facet}}::{{ty.name}}; + {% endfor %} - // from {{abstract_facet}} + {% if using_dox %} + ///@} + {% endif %} + {% if using_dox %} + /** @defgroup {{facet_ns2}}-{{facet_name_lc}}-any-methods **/ + ///@{ + {% endif %} - // const methods - int32_t _typeseq() const noexcept override { return s_typeseq; } - {% for md in const_methods %} - [[noreturn]] {{md.return_type}} {{md.name}}({{md.args | argtypes}}) {{md | qualifiers}} override { _fatal(); } - {% endfor %} + const {{abstract_facet}} * iface() const { return std::launder(this); } - // nonconst methods - {% for md in nonconst_methods %} - [[noreturn]] {{md.return_type}} {{md.name}}({{md.args | argtypes}}) {{md | qualifiers}} override { _fatail(); } - {% endfor %} + // from {{abstract_facet}} -private: - [[noreturn]] static void _fatal(); + // const methods + int32_t _typeseq() const noexcept override { return s_typeseq; } + {% for md in const_methods %} + [[noreturn]] {{md.return_type}} {{md.name}}({{md.args | argtypes}}) {{md | qualifiers}} override { _fatal(); } + {% endfor %} -public: - static int32_t s_typeseq; - static bool _valid; -}; + // nonconst methods + {% for md in nonconst_methods %} + [[noreturn]] {{md.return_type}} {{md.name}}({{md.args | argtypes}}) {{md | qualifiers}} override { _fatail(); } + {% endfor %} + + {% if using_dox %} + ///@} + {% endif %} + + private: + {% if using_dox %} + /** @defgraoup {{facet_ns2}}-{{facet_name_lc}}-any-private-methods **/ + ///@{ + {% endif %} + + [[noreturn]] static void _fatal(); + + {% if using_dox %} + ///@} + {% endif %} + + public: + {% if using_dox %} + /** @defgraoup {{facet_ns2}}-{{facet_name_lc}}-any-member-vars **/ + ///@{ + {% endif %} + + static int32_t s_typeseq; + static bool _valid; + + {% if using_dox %} + ///@} + {% endif %} + }; } /*namespace {{facet_ns2}} */ } /*namespace {{facet_ns1}} */ -/* {{iface_facet_any_fname}} */ +/* {{iface_facet_any_hpp_fname}} */ diff --git a/xo-facet/codegen/iface_facet_xfer.hpp.j2 b/xo-facet/codegen/iface_facet_xfer.hpp.j2 new file mode 100644 index 00000000..bdfd6156 --- /dev/null +++ b/xo-facet/codegen/iface_facet_xfer.hpp.j2 @@ -0,0 +1,99 @@ +/** @file {{iface_facet_xfer_hpp_fname}} + * + * Generated automagically from ingredients: + * 1. code generator: + * [{{genfacet}}] + * arguments: + * --input [{{genfacet_input}}] + * 2. jinja2 template for abstract facet .hpp file: + * [{{ iface_facet_any_hpp_j2 }}] + * 3. idl for facet methods + * [{{ idl_fname }}] + **/ + +#pragma once + +#include "{{abstract_facet_fname}}" + +namespace {{facet_ns1}} { +namespace {{facet_ns2}} { + /** @class {{iface_facet_xfer}} + **/ + template + class {{iface_facet_xfer}} : public {{abstract_facet}} { + public: + {% if using_dox %} + /** @defgroup {{facet_ns2}}-{{facet_name_lc}}-xfer-type-traits **/ + ///@{ + {% endif %} + using Impl = {{iface_facet}}_DRepr; + {% for ty in types %} + using {{ty.name}} = {{abstract_facet}}::{{ty.name}}; + {% endfor %} + {% if using_dox %} + ///@} + {% endif %} + + {% if using_dox %} + /** @defgroup {{facet_ns2}}-{{facet_name_lc}}-xfer-methods **/ + ///@{ + {% endif %} + + static const DRepr & _dcast(Copaque d) { return *(const DRepr *)d; } + static DRepr & _dcast(Opaque d) { return *(DRepr *)d; } + + // from {{abstract_facet}} + + // const methods + int32_t _typeseq() const noexcept override { return s_typeseq; } + {% for md in const_methods %} + {{md.return_type}} {{md.name}}({{md.args | args}}) {{md | qualifiers}} override { + return I::{{md.name}}({{md.args | argnames}}); + } + {% endfor %} + + // non-const methods + {% for md in nonconst_methods %} + {{md.return_type}} {{md.name}}({{md.args | args}}) {{md | qualifiers}} override { + return I::{{md.name}}({{md.args | argnames}}); + } + {% endfor %} + + {% if using_dox %} + ///@} + {% endif %} + + private: + using I = Impl; + + public: + {% if using_dox %} + /** @defgraoup {{facet_ns2}}-{{facet_name_lc}}-xfer-member-vars **/ + ///@{ + {% endif %} + + /** typeseq for template parameter DRepr **/ + static int32_t s_typeseq; + /** true iff satisfies facet implementation **/ + static bool _valid; + + {% if using_dox %} + ///@} + {% endif %} + }; + + template + int32_t + {{iface_facet_xfer}}::s_typeseq + = xo::facet::typeseq::id(); + + template + bool + {{iface_facet_xfer}}::_valid + = xo::facet::valid_facet_implementation<{{abstract_facet}}, + {{iface_facet_xfer}}>(); + +} /*namespace {{facet_ns2}} */ +} /*namespace {{facet_ns1}}*/ + +/* end {{iface_facet_xfer_hpp_fname}} */ diff --git a/xo-facet/codegen/router_facet.hpp.j2 b/xo-facet/codegen/router_facet.hpp.j2 new file mode 100644 index 00000000..9d323de7 --- /dev/null +++ b/xo-facet/codegen/router_facet.hpp.j2 @@ -0,0 +1,94 @@ +/** @file {{router_facet_hpp_fname}} + * + * Generated automagically from ingredients: + * 1. code generator: + * [{{genfacet}}] + * arguments: + * --input [{{genfacet_input}}] + * 2. jinja2 template for abstract facet .hpp file: + * [{{ iface_facet_any_hpp_j2 }}] + * 3. idl for facet methods + * [{{ idl_fname }}] + **/ + +#pragma once + +#include "{{abstract_facet_fname}}" + +namespace {{facet_ns1}} { +namespace {{facet_ns2}} { + +/** @class {{router_facet}} + **/ +template +class {{router_facet}} : public Object { +private: + using O = Object; + +public: + {% if using_dox %} + /** @defgroup {{facet_ns2}}-{{facet_name_lc}}-router-type-traits **/ + ///@{ + {% endif %} + using ObjectType = Object; + using DataPtr = Object::DataPtr; + {% for ty in types %} + using {{ty.name}} = {{abstract_facet}}::{{ty.name}}; + {% endfor %} + {% if using_dox %} + ///@} + {% endif %} + + {% if using_dox %} + /** @defgroup {{facet_ns2}}-{{facet_name_lc}}-router-ctors **/ + ///@{ + {% endif %} + {{router_facet}}() {} + {{router_facet}}(Object::DataPtr data) : Object{std::move(data)} {} + + {% if using_dox %} + ///@} + /** @defgroup {{facet_ns2}}-{{facet_name_lc}}-router-methods **/ + ///@{ + {% endif %} + + // const methods + int32_t _typeseq() const noexcept { return O::iface()->_typeseq(); } + {% for md in const_methods %} + {{md.return_type}} {{md.name}}({{md.args | argsnodata}}) {{md | qualifiers}} override { + return O::iface()->{{md.name}}({{md.args | argrouting}}); + } + {% endfor %} + + // non-const methods + // << do something for non-const methods >> + // + + {% if using_dox %} + ///@} + /** @defgroup {{facet_ns2}}-{{facet_name_lc}}-member-vars **/ + ///@{ + {% endif %} + + static bool _valid; + + {% if using_dox %} + ///@} + {% endif %} +}; + +template +bool +{{router_facet}}::_valid = xo::facet::valid_object_router(); + +} /*namespace {{facet_ns2}}*/ +} /*namespace {{facet_ns1}}*/ + +namespace xo { namespace facet { + template + struct RoutingFor<{{facet_ns1}}::{{facet_ns2}}::{{abstract_facet}}, Object> { + using RoutingType = {{facet_ns1}}::{{facet_ns2}}::{{router_facet}}; + }; +} } + +/* end {{router_facet_hpp_fname}} */ diff --git a/xo-object2/idl/Sequence.json5 b/xo-object2/idl/Sequence.json5 index 7ec535cd..433d3ca1 100644 --- a/xo-object2/idl/Sequence.json5 +++ b/xo-object2/idl/Sequence.json5 @@ -4,6 +4,7 @@ namespace2: "scm", facet: "Sequence", brief: "an ordered collection of variants", + using_doxygen: true, doc: [ "Elements appear in some determinstic order.", "Sequence is GC-aware --> elements must be GC-aware" diff --git a/xo-object2/include/xo/object2/ASequence.hpp b/xo-object2/include/xo/object2/ASequence.hpp index db12e6bd..4c4c806c 100644 --- a/xo-object2/include/xo/object2/ASequence.hpp +++ b/xo-object2/include/xo/object2/ASequence.hpp @@ -2,7 +2,7 @@ * * Generated automagically from ingredients: * 1. code generator: - * [/home/roland/proj/xo-umbrella2/xo-object2/../xo-facet/codegen/genfacet.py] + * [/Users/roland/proj/xo-umbrella2/xo-object2/../xo-facet/codegen/genfacet.py] * arguments: * --input [./idl/Sequence.json5] * 2. jinja2 template for abstract facet .hpp file: @@ -15,29 +15,61 @@ // includes (via {facet_includes}) #include +#include +#include +#include namespace xo { namespace scm { +using Copaque = const void *; +using Opaque = void *; + /** Elements appear in some determinstic order. Sequence is GC-aware --> elements must be GC-aware **/ class ASequence { public: + /** @defgroup scm-sequence-type-traits **/ + ///@{ + // types + /** type for length of a sequence **/ + using size_type = std::size_t; + /** facet for types with GC support **/ + using AGCObject = xo::mm::AGCObject; + ///@} + /** @defgroup scm-sequence-methods **/ + ///@{ + // const methods + /** RTTI: unique id# for actual runtime data representation **/ + virtual int32_t _typeseq() const noexcept = 0; /** true iff sequence is empty **/ - virtual bool is_empty() const noexcept = 0; - - + virtual bool is_empty(Copaque data) const noexcept = 0; /** true iff sequence is finite **/ - virtual bool is_finite() const noexcept = 0; - - + virtual bool is_finite(Copaque data) const noexcept = 0; /** return element @p index of this sequence **/ - virtual obj at(size_type index) const = 0; + virtual obj at(Copaque data, size_type index) const = 0; + // nonconst methods + ///@} }; /*ASequence*/ +/** Implementation ISequence_DRepr of ASequence for state DRepr + * should provide a specialization: + * + * template <> + * struct xo::facet::FacetImplementation { + * using Impltype = ISequence_DRepr; + * }; + * + * then ISequence_ImplType --> ISequence_DRepr + **/ +template +using ISequence_ImplType = xo::facet::FacetImplType; + } /*namespace scm*/ -} /*namespace xo*/ \ No newline at end of file +} /*namespace xo*/ + +/* */ \ No newline at end of file diff --git a/xo-object2/src/object2/CMakeLists.txt b/xo-object2/src/object2/CMakeLists.txt index 644216aa..d7df7235 100644 --- a/xo-object2/src/object2/CMakeLists.txt +++ b/xo-object2/src/object2/CMakeLists.txt @@ -5,6 +5,7 @@ set(SELF_SRCS IGCObject_DFloat.cpp IGCObject_DInteger.cpp IGCObject_DList.cpp + ISequence_Any.cpp ) xo_add_shared_library4(${SELF_LIB} ${PROJECT_NAME}Targets ${PROJECT_VERSION} 1 ${SELF_SRCS})