diff --git a/xo-cmake/cmake/xo_macros/xo_cxx.cmake b/xo-cmake/cmake/xo_macros/xo_cxx.cmake index 2e4ed18e..d491d686 100644 --- a/xo-cmake/cmake/xo_macros/xo_cxx.cmake +++ b/xo-cmake/cmake/xo_macros/xo_cxx.cmake @@ -1619,3 +1619,49 @@ endmacro() macro(xo_pybind11_header_dependency target dep) xo_dependency_helper(${target} PUBLIC ${dep}) endmacro() + +# ---------------------------------------------------------------- +# use this to streamline generating .hpp / .cpp scaffolding +# for faceted object model +# + +macro(xo_add_genfacet) + # Parse arguments + set(options "") + set(oneValueArgs + TARGET # Name for this generation target + FACET # facet 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}) + + # 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 + COMMAND ${CMAKE_SOURCE_DIR}/xo-facet/codegen/genfacet + --input ${GF_INPUT} + --output-hpp ${GF_OUTPUT_HPP_DIR} + --output-impl-hpp ${GF_OUTPUT_IMPL_SUBDIR} + --output-cpp ${GF_OUTPUT_CPP_DIR} + --templates ${CMAKE_SOURCE_DIR}/xo-facet/codegen + 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 ${GF_GENERATED_FILES} + ) +endmacro() diff --git a/xo-facet/CMakeLists.txt b/xo-facet/CMakeLists.txt index 60a67b5c..e1804f25 100644 --- a/xo-facet/CMakeLists.txt +++ b/xo-facet/CMakeLists.txt @@ -30,6 +30,23 @@ xo_export_cmake_config(${PROJECT_NAME} ${PROJECT_VERSION} ${PROJECT_NAME}Targets # ---------------------------------------------------------------- +# Install the generator script +install( + PROGRAMS codegen/genfacet + DESTINATION share/xo-facet/codegen + COMPONENT codegen +) + +# Install all .j2 template files +install( + DIRECTORY codegen/ + DESTINATION share/xo-facet/codegen + COMPONENT codegen + FILES_MATCHING PATTERN "*.j2" +) + +# ---------------------------------------------------------------- + # docs targets depend on other library/utest/exec targets above, # --> must come after them. # diff --git a/xo-facet/codegen/facet.hpp b/xo-facet/codegen/facet.hpp deleted file mode 100644 index e69de29b..00000000 diff --git a/xo-facet/codegen/genfacet.py b/xo-facet/codegen/genfacet similarity index 97% rename from xo-facet/codegen/genfacet.py rename to xo-facet/codegen/genfacet index d45dc703..6af2f4a6 100755 --- a/xo-facet/codegen/genfacet.py +++ b/xo-facet/codegen/genfacet @@ -1,6 +1,5 @@ #! /usr/bin/env python3 # -# genfacet.py import json5 import argparse @@ -54,6 +53,7 @@ def format_args_routing(args): def main(): parser = argparse.ArgumentParser() + parser.add_argument('--templates', required=True, help='.j2 template directory') 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') @@ -75,7 +75,8 @@ def main(): output_cpp_dir.mkdir(parents=False, exist_ok=True) # setup jinja2 - template_dir = Path(__file__).parent + template_dir = Path(args.templates) + #template_dir = Path(__file__).parent #template_dir = Path(__file__).parent / 'codegen' print(f'template_dir: [{template_dir}]') diff --git a/xo-facet/codegen/iface_facet_any.cpp.j2 b/xo-facet/codegen/iface_facet_any.cpp.j2 index 2f11e38b..603686c9 100644 --- a/xo-facet/codegen/iface_facet_any.cpp.j2 +++ b/xo-facet/codegen/iface_facet_any.cpp.j2 @@ -2,7 +2,7 @@ * **/ -#include "{{iface_facet_any_hpp_fname}}" +#include "{{impl_hpp_subdir}}/{{iface_facet_any_hpp_fname}}" #include namespace {{facet_ns1}} { diff --git a/xo-object2/CMakeLists.txt b/xo-object2/CMakeLists.txt index 7d3a714e..7fcc9808 100644 --- a/xo-object2/CMakeLists.txt +++ b/xo-object2/CMakeLists.txt @@ -18,6 +18,17 @@ add_definitions(${PROJECT_CXX_FLAGS}) # ---------------------------------------------------------------- +xo_add_genfacet( + TARGET xo-object2-facet-sequence + FACET Sequence + INPUT idl/Sequence.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 add_subdirectory(src/object2) #add_subdirectory(utest) diff --git a/xo-object2/include/xo/object2/Sequence.hpp b/xo-object2/include/xo/object2/Sequence.hpp new file mode 100644 index 00000000..22f67397 --- /dev/null +++ b/xo-object2/include/xo/object2/Sequence.hpp @@ -0,0 +1,21 @@ +/** @file Sequence.hpp + * + * Generated automagically from ingredients: + * 1. code generator: + * [/Users/roland/proj/xo-umbrella2/xo-object2/../xo-facet/codegen/genfacet] + * arguments: + * --input [./idl/Sequence.json5] + * 2. jinja2 template for facet .hpp file: + * [facet.hpp.j2] + * 3. idl for facet methods + * [./idl/Sequence.json5] + **/ + +#pragma once + +#include "sequence/ASequence.hpp" +#include "sequence/ISequence_Any.hpp" +#include "sequence/ISequence_Xfer.hpp" +#include "sequence/RSequence.hpp" + +/* end Sequence.hpp */ \ No newline at end of file diff --git a/xo-object2/include/xo/object2/sequence/ASequence.hpp b/xo-object2/include/xo/object2/sequence/ASequence.hpp new file mode 100644 index 00000000..332e7cff --- /dev/null +++ b/xo-object2/include/xo/object2/sequence/ASequence.hpp @@ -0,0 +1,75 @@ +/** @file ASequence.hpp + * + * Generated automagically from ingredients: + * 1. code generator: + * [/Users/roland/proj/xo-umbrella2/xo-object2/../xo-facet/codegen/genfacet] + * arguments: + * --input [./idl/Sequence.json5] + * 2. jinja2 template for abstract facet .hpp file: + * [abstract_facet.hpp.j2] + * 3. idl for facet methods + * [./idl/Sequence.json5] + **/ + +#pragma once + +// 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(Copaque data) const noexcept = 0; + /** true iff sequence is finite **/ + virtual bool is_finite(Copaque data) const noexcept = 0; + /** return element @p index of this sequence **/ + 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 diff --git a/xo-object2/include/xo/object2/sequence/ISequence_Any.hpp b/xo-object2/include/xo/object2/sequence/ISequence_Any.hpp new file mode 100644 index 00000000..ebb172d5 --- /dev/null +++ b/xo-object2/include/xo/object2/sequence/ISequence_Any.hpp @@ -0,0 +1,87 @@ +/** @file ISequence_Any.hpp + * + * Generated automagically from ingredients: + * 1. code generator: + * [/Users/roland/proj/xo-umbrella2/xo-object2/../xo-facet/codegen/genfacet] + * arguments: + * --input [./idl/Sequence.json5] + * 2. jinja2 template for abstract facet .hpp file: + * [iface_facet_any.hpp.j2] + * 3. idl for facet methods + * [./idl/Sequence.json5] + **/ + +#pragma once + +#include "ASequence.hpp" +#include + +namespace xo { namespace scm { class ISequence_Any; } } + +namespace xo { +namespace facet { + +template <> +struct FacetImplementation +{ + using ImplType = xo::scm::ISequence_Any; +}; + +} +} + +namespace xo { +namespace scm { + + /** @class ISequence_Any + * @brief ASequence implementation for empty variant instance + **/ + class ISequence_Any : public ASequence { + public: + /** @defgroup scm-sequence-any-type-traits **/ + ///@{ + + using size_type = ASequence::size_type; + using AGCObject = ASequence::AGCObject; + + ///@} + /** @defgroup scm-sequence-any-methods **/ + ///@{ + + const ASequence * iface() const { return std::launder(this); } + + // from ASequence + + // const methods + int32_t _typeseq() const noexcept override { return s_typeseq; } + [[noreturn]] bool is_empty(Copaque) const noexcept override { _fatal(); } + [[noreturn]] bool is_finite(Copaque) const noexcept override { _fatal(); } + [[noreturn]] obj at(Copaque, size_type) const override { _fatal(); } + + // nonconst methods + + ///@} + + private: + /** @defgraoup scm-sequence-any-private-methods **/ + ///@{ + + [[noreturn]] static void _fatal(); + + ///@} + + public: + /** @defgraoup scm-sequence-any-member-vars **/ + ///@{ + + static int32_t s_typeseq; + static bool _valid; + + ///@} + }; + +} /*namespace scm */ +} /*namespace xo */ + +/* ISequence_Any.hpp */ \ No newline at end of file diff --git a/xo-object2/include/xo/object2/sequence/ISequence_Xfer.hpp b/xo-object2/include/xo/object2/sequence/ISequence_Xfer.hpp new file mode 100644 index 00000000..18a5a616 --- /dev/null +++ b/xo-object2/include/xo/object2/sequence/ISequence_Xfer.hpp @@ -0,0 +1,85 @@ +/** @file ISequence_Xfer.hpp + * + * Generated automagically from ingredients: + * 1. code generator: + * [/Users/roland/proj/xo-umbrella2/xo-object2/../xo-facet/codegen/genfacet] + * arguments: + * --input [./idl/Sequence.json5] + * 2. jinja2 template for abstract facet .hpp file: + * [iface_facet_any.hpp.j2] + * 3. idl for facet methods + * [./idl/Sequence.json5] + **/ + +#pragma once + +#include "ASequence.hpp" + +namespace xo { +namespace scm { + /** @class ISequence_Xfer + **/ + template + class ISequence_Xfer : public ASequence { + public: + /** @defgroup scm-sequence-xfer-type-traits **/ + ///@{ + using Impl = ISequence_DRepr; + using size_type = ASequence::size_type; + using AGCObject = ASequence::AGCObject; + ///@} + + /** @defgroup scm-sequence-xfer-methods **/ + ///@{ + + static const DRepr & _dcast(Copaque d) { return *(const DRepr *)d; } + static DRepr & _dcast(Opaque d) { return *(DRepr *)d; } + + // from ASequence + + // const methods + int32_t _typeseq() const noexcept override { return s_typeseq; } + bool is_empty(Copaque data) const noexcept override { + return I::is_empty(_dcast(data)); + } + bool is_finite(Copaque data) const noexcept override { + return I::is_finite(_dcast(data)); + } + obj at(Copaque data, size_type index) const override { + return I::at(_dcast(data), index); + } + + // non-const methods + + ///@} + + private: + using I = Impl; + + public: + /** @defgraoup scm-sequence-xfer-member-vars **/ + ///@{ + + /** typeseq for template parameter DRepr **/ + static int32_t s_typeseq; + /** true iff satisfies facet implementation **/ + static bool _valid; + + ///@} + }; + + template + int32_t + ISequence_Xfer::s_typeseq + = xo::facet::typeseq::id(); + + template + bool + ISequence_Xfer::_valid + = xo::facet::valid_facet_implementation(); + +} /*namespace scm */ +} /*namespace xo*/ + +/* end ISequence_Xfer.hpp */ \ No newline at end of file diff --git a/xo-object2/include/xo/object2/sequence/RSequence.hpp b/xo-object2/include/xo/object2/sequence/RSequence.hpp new file mode 100644 index 00000000..a63ca8a0 --- /dev/null +++ b/xo-object2/include/xo/object2/sequence/RSequence.hpp @@ -0,0 +1,85 @@ +/** @file RSequence.hpp + * + * Generated automagically from ingredients: + * 1. code generator: + * [/Users/roland/proj/xo-umbrella2/xo-object2/../xo-facet/codegen/genfacet] + * arguments: + * --input [./idl/Sequence.json5] + * 2. jinja2 template for abstract facet .hpp file: + * [iface_facet_any.hpp.j2] + * 3. idl for facet methods + * [./idl/Sequence.json5] + **/ + +#pragma once + +#include "ASequence.hpp" + +namespace xo { +namespace scm { + +/** @class RSequence + **/ +template +class RSequence : public Object { +private: + using O = Object; + +public: + /** @defgroup scm-sequence-router-type-traits **/ + ///@{ + using ObjectType = Object; + using DataPtr = Object::DataPtr; + using size_type = ASequence::size_type; + using AGCObject = ASequence::AGCObject; + ///@} + + /** @defgroup scm-sequence-router-ctors **/ + ///@{ + RSequence() {} + RSequence(Object::DataPtr data) : Object{std::move(data)} {} + + ///@} + /** @defgroup scm-sequence-router-methods **/ + ///@{ + + // const methods + int32_t _typeseq() const noexcept { return O::iface()->_typeseq(); } + bool is_empty() const noexcept override { + return O::iface()->is_empty(O::data()); + } + bool is_finite() const noexcept override { + return O::iface()->is_finite(O::data()); + } + obj at(size_type index) const override { + return O::iface()->at(O::data(), index); + } + + // non-const methods + // << do something for non-const methods >> + // + + ///@} + /** @defgroup scm-sequence-member-vars **/ + ///@{ + + static bool _valid; + + ///@} +}; + +template +bool +RSequence::_valid = xo::facet::valid_object_router(); + +} /*namespace scm*/ +} /*namespace xo*/ + +namespace xo { namespace facet { + template + struct RoutingFor { + using RoutingType = xo::scm::RSequence; + }; +} } + +/* end RSequence.hpp */ \ No newline at end of file diff --git a/xo-object2/src/object2/ISequence_Any.cpp b/xo-object2/src/object2/ISequence_Any.cpp new file mode 100644 index 00000000..9eabc9c4 --- /dev/null +++ b/xo-object2/src/object2/ISequence_Any.cpp @@ -0,0 +1,38 @@ +/** @file ISequence_Any.cpp + * + **/ + +#include "sequence/ISequence_Any.hpp" +#include + +namespace xo { +namespace scm { + +using xo::facet::DVariantPlaceholder; +using xo::facet::typeseq; +using xo::facet::valid_facet_implementation; + +void +ISequence_Any::_fatal() +{ + /* control here on uninitialized IAllocator_Any. + * Initialized instance will have specific implementation type + */ + std::cerr << "fatal" + << ": attempt to call uninitialized" + << " ISequence_Any method" + << std::endl; + std::terminate(); +} + +int32_t +ISequence_Any::s_typeseq = typeseq::id(); + +bool +ISequence_Any::_valid + = valid_facet_implementation(); + +} /*namespace scm*/ +} /*namespace xo*/ + +/* end ISequence_Any.cpp */