xo-facet: extend facet gen scope to IFoo_{Xfer,Any}, RFoo

This commit is contained in:
Roland Conybeare 2025-12-25 12:33:07 -05:00
commit 3b1be6843c
11 changed files with 427 additions and 64 deletions

View file

@ -8,7 +8,6 @@
#include "AAllocator.hpp"
#include "AllocIterator.hpp"
#include <xo/facet/obj.hpp>
#include <cassert>
namespace xo {
namespace mm { struct IAllocator_Any; }

View file

@ -27,14 +27,6 @@ namespace xo {
std::terminate();
}
#ifdef NOPE
vt<AAllocIterator>
IAllocator_Any::begin(Copaque, DArena &) const noexcept
{
_fatal();
}
#endif
int32_t
IAllocator_Any::s_typeseq = typeseq::id<DVariantPlaceholder>();

View file

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

View file

@ -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__':

View file

@ -0,0 +1,38 @@
/** @file {{iface_facet_any_cpp_fname}}
*
**/
#include "{{iface_facet_any_hpp_fname}}"
#include <iostream>
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<DVariantPlaceholder>();
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}} */

View file

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

View file

@ -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 <typename DRepr, typename {{iface_facet}}_DRepr>
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 <typename DRepr, typename {{iface_facet}}_DRepr>
int32_t
{{iface_facet_xfer}}<DRepr, {{iface_facet}}_DRepr>::s_typeseq
= xo::facet::typeseq::id<DRepr>();
template <typename DRepr, typename {{iface_facet}}_DRepr>
bool
{{iface_facet_xfer}}<DRepr, {{iface_facet}}_DRepr>::_valid
= xo::facet::valid_facet_implementation<{{abstract_facet}},
{{iface_facet_xfer}}>();
} /*namespace {{facet_ns2}} */
} /*namespace {{facet_ns1}}*/
/* end {{iface_facet_xfer_hpp_fname}} */

View file

@ -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 <typename Object>
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 <typename Object>
bool
{{router_facet}}<Object>::_valid = xo::facet::valid_object_router<Object>();
} /*namespace {{facet_ns2}}*/
} /*namespace {{facet_ns1}}*/
namespace xo { namespace facet {
template <typename Object>
struct RoutingFor<{{facet_ns1}}::{{facet_ns2}}::{{abstract_facet}}, Object> {
using RoutingType = {{facet_ns1}}::{{facet_ns2}}::{{router_facet}}<Object>;
};
} }
/* end {{router_facet_hpp_fname}} */

View file

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

View file

@ -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 <xo/gc/GCObject.hpp>
#include <xo/facet/obj.hpp>
#include <xo/facet/facet_implementation.hpp>
#include <xo/facet/typeseq.hpp>
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<AGCObject> at(size_type index) const = 0;
virtual obj<AGCObject> 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<ASequence, DRepr> {
* using Impltype = ISequence_DRepr;
* };
*
* then ISequence_ImplType<DRepr> --> ISequence_DRepr
**/
template <typename DRepr>
using ISequence_ImplType = xo::facet::FacetImplType<ASequence, DRepr>;
} /*namespace scm*/
} /*namespace xo*/
} /*namespace xo*/
/* */

View file

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