From afc44e71fad72a0f2f68c020540e199bfdcd27f4 Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Mon, 29 Dec 2025 14:32:52 -0500 Subject: [PATCH] xo-gc xo-object2 xo-facet: builds w/ ISequence,Dlist --- xo-cmake/cmake/xo_macros/xo_cxx.cmake | 64 +++- xo-facet/codegen/genfacet | 348 ++++++++++++++++-- xo-facet/codegen/iface_facet_repr.cpp.j2 | 34 ++ xo-facet/codegen/iface_facet_repr.hpp.j2 | 70 ++++ xo-gc/include/xo/gc/detail/ACollector.hpp | 9 +- xo-gc/include/xo/gc/detail/AGCObject.hpp | 9 +- xo-gc/include/xo/gc/detail/ICollector_Any.hpp | 2 +- .../xo/gc/detail/ICollector_DX1Collector.hpp | 2 +- .../include/xo/gc/detail/ICollector_Xfer.hpp | 4 +- xo-gc/include/xo/gc/detail/IGCObject_Any.hpp | 8 +- xo-gc/include/xo/gc/detail/IGCObject_Xfer.hpp | 12 +- xo-gc/include/xo/gc/detail/RCollector.hpp | 2 +- xo-gc/include/xo/gc/detail/RGCObject.hpp | 2 +- xo-gc/src/gc/ICollector_DX1Collector.cpp | 8 +- xo-object2/CMakeLists.txt | 10 + xo-object2/idl/ISequence_DList.json5 | 12 + xo-object2/idl/Sequence.json5 | 2 + xo-object2/include/xo/object2/DList.hpp | 14 +- .../include/xo/object2/IGCObject_DFloat.hpp | 1 + .../include/xo/object2/IGCObject_DInteger.hpp | 1 + .../include/xo/object2/IGCObject_DList.hpp | 13 + .../include/xo/object2/ISequence_DList.hpp | 61 +++ xo-object2/src/object2/CMakeLists.txt | 3 + xo-object2/src/object2/DList.cpp | 54 +++ xo-object2/src/object2/IGCObject_DList.cpp | 9 +- xo-object2/src/object2/ISequence_DList.cpp | 40 ++ 26 files changed, 718 insertions(+), 76 deletions(-) create mode 100644 xo-facet/codegen/iface_facet_repr.cpp.j2 create mode 100644 xo-facet/codegen/iface_facet_repr.hpp.j2 create mode 100644 xo-object2/idl/ISequence_DList.json5 create mode 100644 xo-object2/include/xo/object2/ISequence_DList.hpp create mode 100644 xo-object2/src/object2/DList.cpp create mode 100644 xo-object2/src/object2/ISequence_DList.cpp diff --git a/xo-cmake/cmake/xo_macros/xo_cxx.cmake b/xo-cmake/cmake/xo_macros/xo_cxx.cmake index ba43b34e..182f1599 100644 --- a/xo-cmake/cmake/xo_macros/xo_cxx.cmake +++ b/xo-cmake/cmake/xo_macros/xo_cxx.cmake @@ -1646,14 +1646,17 @@ macro(xo_add_genfacet) REQUIRED) message(STATUS "GENFACET_EXECUTABLE=${GENFACET_EXECUTABLE}") + set(generatedFiles + ${GF_OUTPUT_HPP_DIR}/${FACET}.hpp + ${GF_OUTPUT_HPP_DIR}/${GF_OUTPUT_IMPL_SUBDIR}/A${FACET}.hpp + ${GF_OUTPUT_HPP_DIR}/${GF_OUTPUT_IMPL_SUBDIR}/I${FACET}_Any.hpp + ${GF_OUTPUT_HPP_DIR}/${GF_OUTPUT_IMPL_SUBDIR}/I${FACET}_Xfer.hpp + ${GF_OUTPUT_HPP_DIR}/${GF_OUTPUT_IMPL_SUBDIR}/R${FACET}.hpp + ${GF_OUTPUT_CPP_DIR}/I${FACET}_Any.cpp) + # Build the genfacet command add_custom_command( - OUTPUT ${GF_OUTPUT_HPP_DIR}/${FACET}.hpp - ${GF_OUTPUT_HPP_DIR}/${GF_OUTPUT_IMPL_SUBDIR}/A${FACET}.hpp - ${GF_OUTPUT_HPP_DIR}/${GF_OUTPUT_IMPL_SUBDIR}/I${FACET}_Any.hpp - ${GF_OUTPUT_HPP_DIR}/${GF_OUTPUT_IMPL_SUBDIR}/I${FACET}_Xfer.hpp - ${GF_OUTPUT_HPP_DIR}/${GF_OUTPUT_IMPL_SUBDIR}/R${FACET}.hpp - ${GF_OUTPUT_CPP_DIR}/I${FACET}_Any.cpp + OUTPUT $generatedFiles COMMAND ${GENFACET_EXECUTABLE} --input ${GF_INPUT} --output-hpp ${GF_OUTPUT_HPP_DIR} @@ -1666,7 +1669,50 @@ macro(xo_add_genfacet) ) # Create a target for this generation - add_custom_target(${GF_TARGET} - DEPENDS ${GF_GENERATED_FILES} - ) + add_custom_target(${GF_TARGET} DEPENDS ${generatedFiles}) +endmacro() + +macro(xo_add_genfacetimpl) + # Parse arguments + set(options "") + set(oneValueArgs + TARGET # Name for this generation target + FACET # facet name + REPR # representation name + INPUT # Input .json5 file + OUTPUT_HPP_DIR # Directory for .hpp files + OUTPUT_IMPL_SUBDIR # Subdirectory name for impl headers + OUTPUT_CPP_DIR # Directory for .cpp files + ) + set(multiValueArgs "") + + cmake_parse_arguments(GF "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN}) + + find_program(GENFACET_EXECUTABLE NAMES genfacet + HINTS ${CMAKE_SOURCE_DIR}/xo-facet/codegen + DOC "path to xo genfacet code generator" + REQUIRED) + message(STATUS "GENFACET_EXECUTABLE=${GENFACET_EXECUTABLE}") + + set(generatedFiles + ${GF_OUTPUT_HPP_DIR}/${FACET}.hpp + ${GF_OUTPUT_HPP_DIR}/${GF_OUTPUT_IMPL_SUBDIR}/I${FACET}_D${REPR}.hpp + ${GF_OUTPUT_CPP_DIR}/I${FACET}_D${REPR}.cpp) + + # Build the genfacet command + add_custom_command( + OUTPUT ${generatedFiles} + COMMAND ${GENFACET_EXECUTABLE} + --input ${GF_INPUT} + --output-hpp ${GF_OUTPUT_HPP_DIR} + --output-impl-hpp ${GF_OUTPUT_IMPL_SUBDIR} + --output-cpp ${GF_OUTPUT_CPP_DIR} + DEPENDS ${GF_INPUT} + WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} + COMMENT "Generating facet source files from ${GF_INPUT}" + VERBATIM + ) + + # Create a target for this generation + add_custom_target(${GF_TARGET} DEPENDS ${generatedFiles}) endmacro() diff --git a/xo-facet/codegen/genfacet b/xo-facet/codegen/genfacet index 65e1089e..ff809d50 100755 --- a/xo-facet/codegen/genfacet +++ b/xo-facet/codegen/genfacet @@ -15,12 +15,22 @@ def format_method_qualifiers(method): """ quals = [] if method.get('const', False): - quals.append('const') + quals.append(' const') if method.get('noexcept', False): - quals.append('noexcept') + quals.append(' noexcept') return ' '.join(quals) +def format_method_staticqual(method): + """ Build qualifier string for a static method: noexcet + """ + quals = [] + if method.get('noexcept', False): + quals.append(' noexcept') + + return ' '.join(quals) + + def format_args(args, include_names=True): """ Format argument list for a method """ @@ -40,6 +50,12 @@ def format_arg_names(args): names = [p['name'] for p in args] return ', '.join([f"_dcast({names[0]})"] + names[1:]) +def format_arg_names_nodata(args): + """ Format argument names for forwarding, omit data ('self') arg + """ + names = [p['name'] for p in args[1:]] + return ', '.join(names) + def format_args_nodata(args): """ Format arguments, but exclude data arg """ @@ -51,46 +67,21 @@ def format_args_routing(args): 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-impl-hpp', required=True, help='.hpp detail subdir') - parser.add_argument('--output-hpp', required=True, help='.hpp output directory') - parser.add_argument('--output-cpp', required=True, help='.cpp output directory') +def format_args_impl(args, drepr): + """ Format argument names, for implementation (IFoo_DRepr) + """ + names = [f"{p['type']} {p['name']}" for p in args] + return ', '.join([f"const {drepr} & self"] + names[1:]) - args = parser.parse_args() - idl_fname = args.input - idl = load_idl(idl_fname) - # - output_hpp_dir = Path(args.output_hpp) - output_hpp_dir.mkdir(parents=False, exist_ok=True) - # - output_impl_hpp_subdir = Path(args.output_impl_hpp) - output_impl_hpp_dir = Path(args.output_hpp) / output_impl_hpp_subdir - output_impl_hpp_dir.mkdir(parents=False, exist_ok=True) - # - output_cpp_dir = Path(args.output_cpp) - output_cpp_dir.mkdir(parents=False, exist_ok=True) +def gen_facet(env, + idl_fname, + idl, + input_json5, + output_hpp_dir, + output_impl_hpp_dir, + output_cpp_dir): - # setup jinja2 - #template_dir = Path(args.templates) - template_dir = Path(__file__).parent - #template_dir = Path(__file__).parent / 'codegen' - - print(f'template_dir: [{template_dir}]') - - env = Environment(loader = FileSystemLoader(template_dir), - trim_blocks = True, - lstrip_blocks = True) - - # custom filters - env.filters['qualifiers'] = format_method_qualifiers - 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'] @@ -150,7 +141,7 @@ def main(): context = { 'genfacet': __file__, - 'genfacet_input': args.input, + 'genfacet_input': idl_fname, 'using_dox': using_dox, 'impl_hpp_subdir': output_impl_hpp_subdir, # @@ -225,5 +216,282 @@ def main(): print(f"Generated {out_dir}/{out_file}") + +def gen_facet_impl(env, + idl_fname, + idl, + facet_idl, + output_hpp_dir, + output_impl_hpp_subdir, + output_cpp_dir): + + + # true to insert doxygen markup in generated .hpp/.cpp files + using_dox = idl['using_doxygen'] + + # extra include files (or perhaps other definitions) + + # facet_includes: include section for AFoo.hpp: + # + facet_includes = facet_idl['includes'] + # sequence + facet_detail_subdir = facet_idl['detail_subdir'] + # xo - facet_ns1: outer namespace for facet [e.g. xo] + facet_ns1 = facet_idl['namespace1'] + # scm - facet_ns2: nested namespace for facet [e.g. scm] + facet_ns2 = facet_idl['namespace2'] + + # Sequence - facet_name: facet name + facet_name = facet_idl['facet'] + # sequence - facet_name_lc: lower case [e.g. sequence] + facet_name_lc = facet_name.lower() + # brief doc for facet + facet_brief = idl['brief'] + # doc section for facet + facet_doc = '\n'.join(idl['doc']) + + types = facet_idl['types'] + for ty in types: + ty['doc'] = '\n'.join(ty['doc']) + + const_methods = facet_idl['const_methods'] + for md in const_methods: + md['args'] = [{'type': "Copaque", + 'name': "data"}] + md['args'] + md['doc'] = '\n'.join(md['doc']) + + nonconst_methods = facet_idl['nonconst_methods'] + for md in nonconst_methods: + md['args'] = [{'type': "Opaque", + 'name': "data"}] + md['args'] + md['doc'] = '\n'.join(md['doc']) + + # Foo.hpp + facet_hpp_fname = f'{facet_name}.hpp' + # AFoo + abstract_facet = f'A{facet_name}' + # AFoo.hpp + abstract_facet_fname = f'{abstract_facet}.hpp' + # IFoo + iface_facet = f'I{facet_name}' + # IFoo_ImplType + iface_facet_impltype = f'{iface_facet}_ImplType' + # + # IFoo_Any + iface_facet_any = f'{iface_facet}_Any' + # IFoo_Any.hpp + iface_facet_any_hpp_fname = f'{iface_facet_any}.hpp' + # IFoo_Any.cpp + iface_facet_any_cpp_fname = f'{iface_facet_any}.cpp' + # + # IFoo_Xfer + iface_facet_xfer = f'{iface_facet}_Xfer' + # IFoo_Xfer.hpp + iface_facet_xfer_hpp_fname = f'{iface_facet_xfer}.hpp' + # IFoo_Xfer.cpp + iface_facet_xfer_cpp_fname = f'{iface_facet_xfer}.cpp' + # + # RFoo + router_facet = f'R{facet_name}' + # RFoo.hpp + router_facet_hpp_fname = f'{router_facet}.hpp' + + # ================================================================ + # vars for IFacet_DRepr + # ---------------------------------------------------------------- + + # DList + data_repr = idl['repr'] + # dlist + data_repr_lc = data_repr.lower() + # DList.hpp + data_repr_hpp_fname = f'{data_repr}.hpp' + + # repr_ns1: outer namespace for repr [e.g. xo]. + # (need not match facet) + repr_ns1 = idl['namespace1'] + # repr_ns2: nested namespace for repr [e.g. scm]. + repr_ns2 = idl['namespace2'] + + + # iface_facet_repr: IFoo_DRepr + iface_facet_repr = f'{iface_facet}_{data_repr}' + # iface_facet_repr_hpp_fname: IFoo_DRepr.hpp + iface_facet_repr_hpp_fname = f'{iface_facet_repr}.hpp' + # iface_facet_repr_cpp_fname: IFoo_DRepr.cpp + iface_facet_repr_cpp_fname = f'{iface_facet_repr}.cpp' + + # ================================================================ + + context = { + 'genfacet': __file__, + 'genfacet_input': idl_fname, + 'using_dox': using_dox, + 'impl_hpp_subdir': output_impl_hpp_subdir, + # + 'facet_hpp_j2': 'facet.hpp.j2', + 'facet_includes': facet_includes, + 'facet_detail_subdir': facet_detail_subdir, + 'facet_ns1': facet_ns1, + 'facet_ns2': facet_ns2, + 'facet_name': facet_name, + 'facet_name_lc': facet_name_lc, + 'facet_hpp_fname': facet_hpp_fname, + #'name': facet_name, + 'idl_fname': idl_fname, + # + 'abstract_facet_hpp_j2': 'abstract_facet.hpp.j2', + 'abstract_facet': abstract_facet, + 'abstract_facet_fname': abstract_facet_fname, + 'abstract_facet_doc': facet_doc, + # + 'iface_facet': iface_facet, + 'iface_facet_impltype': iface_facet_impltype, + # + 'iface_facet_any': iface_facet_any, + 'iface_facet_any_hpp_j2': 'iface_facet_any.hpp.j2', + '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, + # + 'const_methods': const_methods, + # + 'nonconst_methods': nonconst_methods, + + # ---------------------------------------------------------------- + # vars for IFacet_DRepr + # ---------------------------------------------------------------- + + 'repr_ns1': repr_ns1, + 'repr_ns2': repr_ns2, + # + 'data_repr': data_repr, + 'data_repr_lc': data_repr_lc, + 'data_repr_hpp_fname': data_repr_hpp_fname, + # + 'iface_facet_repr': iface_facet_repr, + 'iface_facet_repr_hpp_j2': 'iface_facet_repr.hpp.j2', + 'iface_facet_repr_hpp_fname': iface_facet_repr_hpp_fname, + 'iface_facet_repr_cpp_j2': 'iface_facet_repr.cpp.j2', + 'iface_facet_repr_cpp_fname': iface_facet_repr_cpp_fname, + # + + } + + # generate .hpp files + + templates = {} + templates[iface_facet_repr_hpp_fname] = [output_hpp_dir, + context['iface_facet_repr_hpp_j2']] + templates[iface_facet_repr_cpp_fname] = [output_cpp_dir, + context['iface_facet_repr_cpp_j2']] + +# templates[facet_hpp_fname] = [output_hpp_dir, +# context['facet_hpp_j2']] +# templates[abstract_facet_fname] = [output_impl_hpp_dir, +# context['abstract_facet_hpp_j2']] +# templates[iface_facet_any_hpp_fname] = [output_impl_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_impl_hpp_dir, +# context['iface_facet_xfer_hpp_j2']] +# templates[router_facet_hpp_fname] = [output_impl_hpp_dir, +# context['router_facet_hpp_j2']] + + 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) + + (out_dir / out_file).write_text(content) + print(f"Generated {out_dir}/{out_file}") + +def main(): + parser = argparse.ArgumentParser() + parser.add_argument('--input', required=True, help='input IDL JSON5 file') + # --output-impl-hpp: putting this in .json5, will be able to drop this. + parser.add_argument('--output-impl-hpp', required=True, help='.hpp detail subdir') + 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_hpp_dir = Path(args.output_hpp) + output_hpp_dir.mkdir(parents=False, exist_ok=True) + + # TODO: output_impl_hpp_subdir: use idl['detail_subdir'] instead + output_impl_hpp_subdir = Path(args.output_impl_hpp) + output_impl_hpp_dir = Path(args.output_hpp) / output_impl_hpp_subdir + output_impl_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(args.templates) + template_dir = Path(__file__).parent + #template_dir = Path(__file__).parent / 'codegen' + + print(f'template_dir: [{template_dir}]') + + env = Environment(loader = FileSystemLoader(template_dir), + trim_blocks = True, + lstrip_blocks = True) + + # custom filters. + # A filter 'foo' provides ability to write '{{var | foo}}' to expand + # j2 variable 'var' to 'filters[foo](var)' + # + env.filters['qualifiers'] = format_method_qualifiers + env.filters['staticqual'] = format_method_staticqual + env.filters['args'] = format_args + env.filters['argtypes'] = format_args_nonames + env.filters['argnames'] = format_arg_names + env.filters['argnamesnodata'] = format_arg_names_nodata + env.filters['argsnodata'] = format_args_nodata + env.filters['argrouting'] = format_args_routing + env.filters['argimpl'] = format_args_impl + + if idl['mode'] == 'facet': + gen_facet(env, + idl_fname, + idl, + output_hpp_dir, + output_impl_hpp_dir, + output_cpp_dir) + elif idl['mode'] == 'implementation': + facet_idl_fname = idl['facet_idl'] + facet_idl = load_idl(facet_idl_fname) + + gen_facet_impl(env, + idl_fname, + idl, + facet_idl, + output_hpp_dir, + output_impl_hpp_dir, + output_cpp_dir) + if __name__ == '__main__': main() diff --git a/xo-facet/codegen/iface_facet_repr.cpp.j2 b/xo-facet/codegen/iface_facet_repr.cpp.j2 new file mode 100644 index 00000000..ce3e87be --- /dev/null +++ b/xo-facet/codegen/iface_facet_repr.cpp.j2 @@ -0,0 +1,34 @@ +/** @file {{iface_facet_repr_cpp_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 }}] +**/ + +#include "{{iface_facet_repr_hpp_fname}}" + +namespace {{repr_ns1}} { + namespace {{repr_ns2}} { + {% for md in const_methods %} + auto + {{iface_facet_repr}}::{{md.name}}({{md.args | argimpl(data_repr)}}){{md | staticqual}} -> {{md.return_type}} + { + {% if md.return_type == "void" %} + self.{{md.name}}({{md.args | argnamesnodata}}); + {% else %} + return self.{{md.name}}({{md.args | argnamesnodata}}); + {% endif %} + } + + {% endfor %} + + } /*namespace {{repr_ns2}}*/ +} /*namespace {{repr_ns1}}*/ + +/* end {{iface_facet_repr_cpp_fname}} */ diff --git a/xo-facet/codegen/iface_facet_repr.hpp.j2 b/xo-facet/codegen/iface_facet_repr.hpp.j2 new file mode 100644 index 00000000..479fd50b --- /dev/null +++ b/xo-facet/codegen/iface_facet_repr.hpp.j2 @@ -0,0 +1,70 @@ +/** @file {{iface_facet_repr_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 "{{facet_hpp_fname}}" +#include "{{facet_detail_subdir}}/{{iface_facet_xfer_hpp_fname}}" +#include "{{data_repr_hpp_fname}}" + +namespace {{repr_ns1}} { namespace {{repr_ns2}} { class {{iface_facet_repr}}; } } + +namespace xo { + namespace facet { + template <> + struct FacetImplementation<{{facet_ns1}}::{{facet_ns2}}::{{abstract_facet}}, + {{repr_ns1}}::{{repr_ns2}}::{{data_repr}}> + { + using ImplType = {{facet_ns1}}::{{facet_ns2}}::{{iface_facet_xfer}} + <{{repr_ns1}}::{{repr_ns2}}::{{data_repr}}, + {{repr_ns1}}::{{repr_ns2}}::{{iface_facet_repr}}>; + }; + } +} + +namespace {{repr_ns1}} { + namespace {{repr_ns2}} { + /** @class {{iface_facet_repr}} + **/ + class {{iface_facet_repr}} { + public: + {% if using_dox %} + /** @defgroup {{repr_ns2}}-{{facet_name_lc}}-{{data_repr_lc}}-type-traits **/ + ///@{ + {% endif %} + {% for ty in types %} + using {{ty.name}} = {{abstract_facet}}::{{ty.name}}; + {% endfor %} + {% if using_dox %} + ///@} + /** @defgroup {{repr_ns2}}-{{facet_name_lc}}-{{data_repr_lc}}-methods **/ + ///@{ + {% endif %} + {% for md in const_methods %} + /** {{md.doc}} **/ + static {{md.return_type}} {{md.name}}({{md.args | argimpl(data_repr)}}){{md | staticqual}}; + {% endfor %} + + {% for md in methods %} + /** {{md.doc}} **/ + static {{md.return_type}} {{md.name}}({{md.args | argimpl(data_repr)}}){{md | staticqual}}; + {% endfor %} + {% if using_dox %} + ///@} + {% endif %} + }; + + } /*namespace {{repr_ns2}}*/ +} /*namespace {{repr_ns1}}*/ + +/* end */ \ No newline at end of file diff --git a/xo-gc/include/xo/gc/detail/ACollector.hpp b/xo-gc/include/xo/gc/detail/ACollector.hpp index 24bd219e..5a41f913 100644 --- a/xo-gc/include/xo/gc/detail/ACollector.hpp +++ b/xo-gc/include/xo/gc/detail/ACollector.hpp @@ -5,7 +5,7 @@ #pragma once -#include "IGCObject_Any.hpp" +//#include "IGCObject_Any.hpp" #include #include @@ -22,6 +22,7 @@ namespace xo { using Copaque = const void *; using Opaque = void *; + struct AGCObject; struct IGCObject_Any; // see IGCObject_Any.hpp /** @class ACollector @@ -53,10 +54,12 @@ namespace xo { virtual void install_type(Opaque d, int32_t tseq, IGCObject_Any & iface) = 0; virtual void add_gc_root(Opaque d, int32_t tseq, Opaque * root) = 0; - /** evacuate @p *lhs to to-space and replace with forwarding pointer + /** evacuate @p *lhs, that refers to state with interface @p lhs_iface, + * to collector @p d's to-space. Replace *lhs_data with forwarding pointer + * * Require: gc in progress **/ - virtual void forward_inplace(Opaque d, obj * lhs) = 0; + virtual void forward_inplace(Opaque d, AGCObject * lhs_iface, void ** lhs_data) = 0; }; } diff --git a/xo-gc/include/xo/gc/detail/AGCObject.hpp b/xo-gc/include/xo/gc/detail/AGCObject.hpp index 1e0a6d45..ae2b8a08 100644 --- a/xo-gc/include/xo/gc/detail/AGCObject.hpp +++ b/xo-gc/include/xo/gc/detail/AGCObject.hpp @@ -17,6 +17,8 @@ namespace xo { using Copaque = const void *; using Opaque = void *; + struct ACollector; + /** @class AObject * @brief Abstract facet for collector-eligible data * @@ -30,9 +32,10 @@ namespace xo { virtual int32_t _typeseq() const noexcept = 0; virtual size_type shallow_size(Copaque d) const noexcept = 0; - virtual Opaque * shallow_copy(Copaque d, - obj mm) const noexcept = 0; - virtual size_type forward_children(Opaque d) const noexcept = 0; + virtual Opaque shallow_copy(Copaque d, + obj mm) const noexcept = 0; + virtual size_type forward_children(Opaque d, + obj) const noexcept = 0; }; // implementation IGCObject_DRepr of AGCObject for state DRepr diff --git a/xo-gc/include/xo/gc/detail/ICollector_Any.hpp b/xo-gc/include/xo/gc/detail/ICollector_Any.hpp index c9779687..b4836f66 100644 --- a/xo-gc/include/xo/gc/detail/ICollector_Any.hpp +++ b/xo-gc/include/xo/gc/detail/ICollector_Any.hpp @@ -36,7 +36,7 @@ namespace xo { // non-const methods [[noreturn]] void install_type(Opaque, int32_t, IGCObject_Any &) noexcept override { _fatal(); } [[noreturn]] void add_gc_root(Opaque, int32_t, Opaque *) override { _fatal(); } - [[noreturn]] void forward_inplace(Opaque, obj *) override { _fatal(); } + [[noreturn]] void forward_inplace(Opaque, AGCObject *, void **) override { _fatal(); } private: [[noreturn]] static void _fatal(); diff --git a/xo-gc/include/xo/gc/detail/ICollector_DX1Collector.hpp b/xo-gc/include/xo/gc/detail/ICollector_DX1Collector.hpp index 9bc6e129..c531ae13 100644 --- a/xo-gc/include/xo/gc/detail/ICollector_DX1Collector.hpp +++ b/xo-gc/include/xo/gc/detail/ICollector_DX1Collector.hpp @@ -44,7 +44,7 @@ namespace xo { static void install_type(DX1Collector & d, int32_t seq, IGCObject_Any & iface); static void add_gc_root(DX1Collector & d, int32_t tseq, Opaque * root); - static void forward_inplace(DX1Collector & d, obj * lhs); + static void forward_inplace(DX1Collector & d, AGCObject * lhs_iface, void ** lhs_data); static int32_t s_typeseq; static bool _valid; diff --git a/xo-gc/include/xo/gc/detail/ICollector_Xfer.hpp b/xo-gc/include/xo/gc/detail/ICollector_Xfer.hpp index 2177b63a..c44bd3ca 100644 --- a/xo-gc/include/xo/gc/detail/ICollector_Xfer.hpp +++ b/xo-gc/include/xo/gc/detail/ICollector_Xfer.hpp @@ -49,8 +49,8 @@ namespace xo { void add_gc_root(Opaque d, int32_t tseq, Opaque * root) override { I::add_gc_root(_dcast(d), tseq, root); } - void forward_inplace(Opaque d, obj * lhs) override { - I::forward_inplace(_dcast(d), lhs); + void forward_inplace(Opaque d, AGCObject * lhs_iface, void ** lhs_data) override { + I::forward_inplace(_dcast(d), lhs_iface, lhs_data); } private: diff --git a/xo-gc/include/xo/gc/detail/IGCObject_Any.hpp b/xo-gc/include/xo/gc/detail/IGCObject_Any.hpp index 039a1259..b387b9b9 100644 --- a/xo-gc/include/xo/gc/detail/IGCObject_Any.hpp +++ b/xo-gc/include/xo/gc/detail/IGCObject_Any.hpp @@ -6,6 +6,7 @@ #pragma once #include "AGCObject.hpp" +#include "Collector.hpp" #include namespace xo { @@ -31,9 +32,10 @@ namespace xo { int32_t _typeseq() const noexcept override { return s_typeseq; } [[noreturn]] size_type shallow_size(Copaque) const noexcept override { _fatal(); } - [[noreturn]] Opaque * shallow_copy(Copaque, - obj) const noexcept override { _fatal(); } - [[noreturn]] size_type forward_children(Opaque) const noexcept override { _fatal(); } + [[noreturn]] Opaque shallow_copy(Copaque, + obj) const noexcept override { _fatal(); } + [[noreturn]] size_type forward_children(Opaque, + obj) const noexcept override { _fatal(); } private: [[noreturn]] static void _fatal(); diff --git a/xo-gc/include/xo/gc/detail/IGCObject_Xfer.hpp b/xo-gc/include/xo/gc/detail/IGCObject_Xfer.hpp index 75f78fd6..95e20ff1 100644 --- a/xo-gc/include/xo/gc/detail/IGCObject_Xfer.hpp +++ b/xo-gc/include/xo/gc/detail/IGCObject_Xfer.hpp @@ -6,6 +6,7 @@ #pragma once #include "AGCObject.hpp" +#include "ACollector.hpp" namespace xo { namespace mm { @@ -28,16 +29,17 @@ namespace xo { int32_t _typeseq() const noexcept override { return s_typeseq; } size_type shallow_size(Copaque d) const noexcept override { - return I::shallow_copy(_dcast(d)); + return I::shallow_size(_dcast(d)); } - Opaque * shallow_copy(Copaque d, obj mm) const noexcept override { - return I::shallow_size(_dcast(d), mm); + Opaque shallow_copy(Copaque d, obj mm) const noexcept override { + return I::shallow_copy(_dcast(d), mm); } // non-const methods - size_type forward_children(Opaque d) const noexcept override { - return I::forward_children(d); + size_type forward_children(Opaque d, + obj gc) const noexcept override { + return I::forward_children(_dcast(d), gc); } private: diff --git a/xo-gc/include/xo/gc/detail/RCollector.hpp b/xo-gc/include/xo/gc/detail/RCollector.hpp index 753af3c7..47e9c43b 100644 --- a/xo-gc/include/xo/gc/detail/RCollector.hpp +++ b/xo-gc/include/xo/gc/detail/RCollector.hpp @@ -30,7 +30,7 @@ namespace xo { void install_type(int32_t tseq, IGCObject_Any & iface) { return O::iface()->install_type(O::data(), tseq, iface); } void add_gc_root(int32_t tseq, Opaque * root) { O::iface()->add_gc_root(O::data(), tseq, root); } - void forward_inplace(obj * lhs) { O::iface()->forward_inplace(O::data(), lhs); } + void forward_inplace(AGCObject * lhs_iface, void ** lhs_data) { O::iface()->forward_inplace(O::data(), lhs_iface, lhs_data); } static bool _valid; }; diff --git a/xo-gc/include/xo/gc/detail/RGCObject.hpp b/xo-gc/include/xo/gc/detail/RGCObject.hpp index 054b995e..29bebf15 100644 --- a/xo-gc/include/xo/gc/detail/RGCObject.hpp +++ b/xo-gc/include/xo/gc/detail/RGCObject.hpp @@ -25,7 +25,7 @@ namespace xo { int32_t _typeseq() const noexcept { return O::iface()->_typeseq(); } size_type shallow_size() const noexcept { O::iface()->shallow_size(O::data()); } - Opaque * shallow_copy(obj mm) const noexcept { O::iface()->shallow_copy(O::data(), mm); } + Opaque shallow_copy(obj mm) const noexcept { O::iface()->shallow_copy(O::data(), mm); } size_type forward_children() noexcept { O::iface()->forward_children(O::data()); } static bool _valid; diff --git a/xo-gc/src/gc/ICollector_DX1Collector.cpp b/xo-gc/src/gc/ICollector_DX1Collector.cpp index 41e05f9d..b4d8f24d 100644 --- a/xo-gc/src/gc/ICollector_DX1Collector.cpp +++ b/xo-gc/src/gc/ICollector_DX1Collector.cpp @@ -73,8 +73,10 @@ namespace xo { void ICollector_DX1Collector::forward_inplace(DX1Collector & d, - obj * lhs) + AGCObject * lhs_iface, + void ** lhs_data) { + (void)lhs_iface; assert(d.runstate_.is_running()); /* @@ -90,7 +92,7 @@ namespace xo { * +----------+ */ - void * object_data = (byte *)(*lhs).opaque_data(); + void * object_data = (byte *)lhs_data; if (!d.contains(role::from_space(), object_data)) { /* *lhs isn't in GC-allocated space. @@ -143,7 +145,7 @@ namespace xo { void * dest = *(void**)object_data; /* update *lhs in-place */ - (*lhs).reset_opaque(dest); + *lhs_data = dest; } else if (check_move_policy(d, alloc_hdr, object_data)) { /* copy object *lhs + replace with forwarding pointer */ diff --git a/xo-object2/CMakeLists.txt b/xo-object2/CMakeLists.txt index 7fcc9808..4dabb209 100644 --- a/xo-object2/CMakeLists.txt +++ b/xo-object2/CMakeLists.txt @@ -27,6 +27,16 @@ xo_add_genfacet( OUTPUT_CPP_DIR src/object2 ) +xo_add_genfacetimpl( + TARGET xo-object2-facetimpl-sequence-list + FACET Sequence + REPR List + INPUT idl/ISequence_DList.json5 + OUTPUT_HPP_DIR include/xo/object2 + OUTPUT_IMPL_SUBDIR sequence + OUTPUT_CPP_DIR src/object2 +) + # ---------------------------------------------------------------- # must complete definition of expression lib before configuring examples diff --git a/xo-object2/idl/ISequence_DList.json5 b/xo-object2/idl/ISequence_DList.json5 new file mode 100644 index 00000000..30c0b262 --- /dev/null +++ b/xo-object2/idl/ISequence_DList.json5 @@ -0,0 +1,12 @@ +{ + mode: "implementation", + includes: [], + namespace1: "xo", + namespace2: "scm", + facet_idl: "idl/Sequence.json5", + brief: "provide ASequence interface for DList state", + using_doxygen: true, + repr: "DList", + doc: [ "doc for something or other" + ], +} \ No newline at end of file diff --git a/xo-object2/idl/Sequence.json5 b/xo-object2/idl/Sequence.json5 index 433d3ca1..2ee1a204 100644 --- a/xo-object2/idl/Sequence.json5 +++ b/xo-object2/idl/Sequence.json5 @@ -1,8 +1,10 @@ { + mode: "facet", includes: [""], namespace1: "xo", namespace2: "scm", facet: "Sequence", + detail_subdir: "sequence", brief: "an ordered collection of variants", using_doxygen: true, doc: [ diff --git a/xo-object2/include/xo/object2/DList.hpp b/xo-object2/include/xo/object2/DList.hpp index 9710defb..79cc84f7 100644 --- a/xo-object2/include/xo/object2/DList.hpp +++ b/xo-object2/include/xo/object2/DList.hpp @@ -11,13 +11,23 @@ namespace xo { namespace scm { struct DList { + using size_type = std::size_t; using AGCObject = xo::mm::AGCObject; DList(xo::obj h, - xo::obj r) : head_{h}, rest_{r} {} + DList * r) : head_{h}, rest_{r} {} + + /** DList length is at least 1 **/ + bool is_empty() const noexcept { return false; }; + /** DList models a finite sequence **/ + bool is_finite() const noexcept { return true; }; + /** return number of elements in this DList **/ + size_type size() const noexcept; + /** return element at 0-based index @p ix **/ + obj at(size_type ix) const; obj head_; - obj rest_; + DList * rest_ = nullptr; }; } /*namespace scm*/ diff --git a/xo-object2/include/xo/object2/IGCObject_DFloat.hpp b/xo-object2/include/xo/object2/IGCObject_DFloat.hpp index a6c5c17e..3ccf40d8 100644 --- a/xo-object2/include/xo/object2/IGCObject_DFloat.hpp +++ b/xo-object2/include/xo/object2/IGCObject_DFloat.hpp @@ -5,6 +5,7 @@ #pragma once +#include #include #include #include diff --git a/xo-object2/include/xo/object2/IGCObject_DInteger.hpp b/xo-object2/include/xo/object2/IGCObject_DInteger.hpp index 1f1f220c..c53a79f5 100644 --- a/xo-object2/include/xo/object2/IGCObject_DInteger.hpp +++ b/xo-object2/include/xo/object2/IGCObject_DInteger.hpp @@ -5,6 +5,7 @@ #pragma once +#include #include "xo/alloc2/alloc/AAllocator.hpp" #include #include diff --git a/xo-object2/include/xo/object2/IGCObject_DList.hpp b/xo-object2/include/xo/object2/IGCObject_DList.hpp index 8ba91a61..c469d17b 100644 --- a/xo-object2/include/xo/object2/IGCObject_DList.hpp +++ b/xo-object2/include/xo/object2/IGCObject_DList.hpp @@ -13,6 +13,19 @@ #include "DList.hpp" namespace xo { + namespace scm { struct IGCObject_DList; } + + namespace facet { + template <> + struct FacetImplementation + { + using ImplType = xo::mm::IGCObject_Xfer + ; + }; + } + namespace scm { /* changes here coordinate with: * IGCObject_XFer diff --git a/xo-object2/include/xo/object2/ISequence_DList.hpp b/xo-object2/include/xo/object2/ISequence_DList.hpp new file mode 100644 index 00000000..5f67a3ff --- /dev/null +++ b/xo-object2/include/xo/object2/ISequence_DList.hpp @@ -0,0 +1,61 @@ +/** @file ISequence_DList.hpp + * + * Generated automagically from ingredients: + * 1. code generator: + * [/Users/roland/proj/xo-umbrella2/xo-facet/codegen/genfacet] + * arguments: + * --input [idl/ISequence_DList.json5] + * 2. jinja2 template for abstract facet .hpp file: + * [iface_facet_any.hpp.j2] + * 3. idl for facet methods + * [idl/ISequence_DList.json5] + **/ + +#pragma once + +#include "Sequence.hpp" +#include "sequence/ISequence_Xfer.hpp" +#include "DList.hpp" + +namespace xo { namespace scm { class ISequence_DList; } } + +namespace xo { + namespace facet { + template <> + struct FacetImplementation + { + using ImplType = xo::scm::ISequence_Xfer + ; + }; + } +} + +namespace xo { + namespace scm { + /** @class ISequence_DList + **/ + class ISequence_DList { + public: + /** @defgroup scm-sequence-dlist-type-traits **/ + ///@{ + using size_type = ASequence::size_type; + using AGCObject = ASequence::AGCObject; + ///@} + /** @defgroup scm-sequence-dlist-methods **/ + ///@{ + /** true iff sequence is empty **/ + static bool is_empty(const DList & self) noexcept; + /** true iff sequence is finite **/ + static bool is_finite(const DList & self) noexcept; + /** return element @p index of this sequence **/ + static obj at(const DList & self, size_type index); + + ///@} + }; + + } /*namespace scm*/ +} /*namespace xo*/ + +/* end */ \ No newline at end of file diff --git a/xo-object2/src/object2/CMakeLists.txt b/xo-object2/src/object2/CMakeLists.txt index d7df7235..dd76874e 100644 --- a/xo-object2/src/object2/CMakeLists.txt +++ b/xo-object2/src/object2/CMakeLists.txt @@ -6,9 +6,12 @@ set(SELF_SRCS IGCObject_DInteger.cpp IGCObject_DList.cpp ISequence_Any.cpp + ISequence_DList.cpp + DList.cpp ) xo_add_shared_library4(${SELF_LIB} ${PROJECT_NAME}Targets ${PROJECT_VERSION} 1 ${SELF_SRCS}) # note: deps here must also appear in cmake/xo_alloc2Config.cmake.in xo_dependency(${SELF_LIB} xo_gc) #xo_dependency(${SELF_LIB} indentlog) +#add_dependencies(${SELF_LIB} xo-object2-facetimpl-sequence-list) diff --git a/xo-object2/src/object2/DList.cpp b/xo-object2/src/object2/DList.cpp new file mode 100644 index 00000000..2377d182 --- /dev/null +++ b/xo-object2/src/object2/DList.cpp @@ -0,0 +1,54 @@ +/** @file DList.cpp + * + * @author Roland Conybeare, Dec 2025 + **/ + +#include "DList.hpp" +#include + +namespace xo { + namespace scm { + auto + DList::size() const noexcept -> size_type + { + const DList * l = this; + + size_type z = 0; + + while (l) { + ++z; + l = l->rest_; + } + + return z; + } + + auto + DList::at(size_type index) const -> obj + { + size_type ix = index; + const DList * l = this; + + while (l->rest_ && (ix > 0)) { + --ix; + l = l->rest_; + } + + if (ix > 0) { + assert(l == nullptr); + + throw std::runtime_error + (tostr("DList::at: out-of-range index where [0..z) expected", + xtag("index", index), + xtag("z", this->size()))); + } + + assert(l); + + return l->head_; + } + + } /*namespace scm*/ +} /*namespace xo*/ + +/* end DList.cpp */ diff --git a/xo-object2/src/object2/IGCObject_DList.cpp b/xo-object2/src/object2/IGCObject_DList.cpp index 104358e8..d4355a29 100644 --- a/xo-object2/src/object2/IGCObject_DList.cpp +++ b/xo-object2/src/object2/IGCObject_DList.cpp @@ -6,7 +6,9 @@ #include "IGCObject_DList.hpp" namespace xo { + using xo::mm::AGCObject; using xo::mm::AAllocator; + using xo::facet::with_facet; using xo::facet::obj; using std::size_t; @@ -33,8 +35,11 @@ namespace xo { IGCObject_DList::forward_children(DList & src, obj gc) noexcept { - gc.forward_inplace(&src.head_); - gc.forward_inplace(&src.rest_); + gc.forward_inplace(src.head_.iface(), (void **)&(src.head_.data_)); + + //auto rest = with_facet::mkobj(src.rest_); + xo::facet::FacetImplementation::ImplType iface; + gc.forward_inplace(&iface, (void **)(&src.rest_)); return shallow_size(src); } diff --git a/xo-object2/src/object2/ISequence_DList.cpp b/xo-object2/src/object2/ISequence_DList.cpp new file mode 100644 index 00000000..22d5bde5 --- /dev/null +++ b/xo-object2/src/object2/ISequence_DList.cpp @@ -0,0 +1,40 @@ +/** @file ISequence_DList.cpp + * + * Generated automagically from ingredients: + * 1. code generator: + * [/Users/roland/proj/xo-umbrella2/xo-facet/codegen/genfacet] + * arguments: + * --input [idl/ISequence_DList.json5] + * 2. jinja2 template for abstract facet .hpp file: + * [iface_facet_any.hpp.j2] + * 3. idl for facet methods + * [idl/ISequence_DList.json5] +**/ + +#include "ISequence_DList.hpp" + +namespace xo { + namespace scm { + auto + ISequence_DList::is_empty(const DList & self) noexcept -> bool + { + return self.is_empty(); + } + + auto + ISequence_DList::is_finite(const DList & self) noexcept -> bool + { + return self.is_finite(); + } + + auto + ISequence_DList::at(const DList & self, size_type index) -> obj + { + return self.at(index); + } + + + } /*namespace scm*/ +} /*namespace xo*/ + +/* end ISequence_DList.cpp */ \ No newline at end of file