diff --git a/xo-object2/.gitrepo b/xo-object2/.gitrepo new file mode 100644 index 00000000..b4ce5365 --- /dev/null +++ b/xo-object2/.gitrepo @@ -0,0 +1,12 @@ +; DO NOT EDIT (unless you know what you are doing) +; +; This subdirectory is a git "subrepo", and this file is maintained by the +; git-subrepo command. See https://github.com/ingydotnet/git-subrepo#readme +; +[subrepo] + remote = git@github.com:Rconybea/xo-object2.git + branch = main + commit = 8156e5149ab93714465429b9f76f905243401036 + parent = 2a287cf7724534f70c844c93a6bd012434f9caf4 + method = merge + cmdver = 0.4.9 diff --git a/xo-object2/CMakeLists.txt b/xo-object2/CMakeLists.txt new file mode 100644 index 00000000..b4ef253f --- /dev/null +++ b/xo-object2/CMakeLists.txt @@ -0,0 +1,191 @@ +# xo-object2/CMakeLists.txt + +cmake_minimum_required(VERSION 3.10) + +project(xo_object2 VERSION 0.1) + +include(GNUInstallDirs) +include(cmake/xo-bootstrap-macros.cmake) + +xo_cxx_toplevel_options3() + +# ---------------------------------------------------------------- +# c++ settings + +set(PROJECT_CXX_FLAGS "") +#set(PROJECT_CXX_FLAGS "-fconcepts-diagnostics-depth=2") # gcc-only! +add_definitions(${PROJECT_CXX_FLAGS}) + +# ---------------------------------------------------------------- + +# note: manual target; generated code committed to git +xo_add_genfacet( + TARGET xo-object2-facet-sequence + FACET Sequence + INPUT idl/Sequence.json5 +) + +# ---------------------------------------------------------------- + +# note: manual target; generated code committed to git +xo_add_genfacetimpl( + TARGET xo-object2-facetimpl-sequence-list + FACET_PKG xo_object2 + INPUT idl/ISequence_DList.json5 +) + +# note: manual target; generated code committed to git +xo_add_genfacetimpl( + TARGET xo-object2-facetimpl-printable-list + FACET_PKG xo_printable2 +# REPR List + INPUT idl/IPrintable_DList.json5 +) + +# note: manual target; generated code committed to git +xo_add_genfacetimpl( + TARGET xo-object2-facetimpl-gcobject-list + FACET_PKG xo_alloc2 +# REPR List + INPUT idl/IGCObject_DList.json5 +) + +# ---------------------------------------------------------------- + +# note: manual target; generated code committed to git +xo_add_genfacetimpl( + TARGET xo-object2-facetimpl-printable-boolean + FACET_PKG xo_printable2 +# REPR Boolean + INPUT idl/IPrintable_DBoolean.json5 +) + +# note: manual target; generated code committed to git +xo_add_genfacetimpl( + TARGET xo-object2-facetimpl-gcobject-boolean + FACET_PKG xo_alloc2 +# REPR Boolean + INPUT idl/IGCObject_DBoolean.json5 +) + +# ---------------------------------------------------------------- + +# note: manual target; generated code committed to git +xo_add_genfacetimpl( + TARGET xo-object2-facetimpl-printable-float + FACET_PKG xo_printable2 +# REPR Float + INPUT idl/IPrintable_DFloat.json5 +) + +# note: manual target; generated code committed to git +xo_add_genfacetimpl( + TARGET xo-object2-facetimpl-gcobject-float + FACET_PKG xo_alloc2 +# REPR Float + INPUT idl/IGCObject_DFloat.json5 +) + +# ---------------------------------------------------------------- + +# note: manual target; generated code committed to git +xo_add_genfacetimpl( + TARGET xo-object2-facetimpl-printable-integer + FACET_PKG xo_printable2 +# REPR Integer + INPUT idl/IPrintable_DInteger.json5 +) + +# note: manual target; generated code committed to git +xo_add_genfacetimpl( + TARGET xo-object2-facetimpl-gcobject-integer + FACET_PKG xo_alloc2 +# REPR Integer + INPUT idl/IGCObject_DInteger.json5 +) + +# ---------------------------------------------------------------- + +# note: manual target; generated code committed to git +xo_add_genfacetimpl( + TARGET xo-object2-facetimpl-sequence-array + FACET_PKG xo_object2 +# REPR Array + INPUT idl/ISequence_DArray.json5 +) + +# note: manual target; generated code committed to git +xo_add_genfacetimpl( + TARGET xo-object2-facetimpl-printable-array + FACET_PKG xo_printable2 +# REPR Array + INPUT idl/IPrintable_DArray.json5 +) + +# note: manual target; generated code committed to git +xo_add_genfacetimpl( + TARGET xo-object2-facetimpl-gcobject-array + FACET_PKG xo_alloc2 +# REPR Array + INPUT idl/IGCObject_DArray.json5 +) + +# ---------------------------------------------------------------- + +# note: manual target; generated code committed to git +xo_add_genfacetimpl( + TARGET xo-object2-facetimpl-printable-dictionary + FACET_PKG xo_printable2 +# REPR Dictionary + INPUT idl/IPrintable_DDictionary.json5 + ) + +# note: manual target; generated code committed to git +xo_add_genfacetimpl( + TARGET xo-object2-facetimpl-gcobject-dictionary + FACET_PKG xo_alloc2 +# REPR Dictionary + INPUT idl/IGCObject_DDictionary.json5 +) + +# ---------------------------------------------------------------- + +# note: manual target; generated code committed to git +xo_add_genfacetimpl( + TARGET xo-object2-facetimpl-printable-runtimeerror + FACET_PKG xo_printable2 +# REPR RuntimeError + INPUT idl/IPrintable_DRuntimeError.json5 + ) + +# note: manual target; generated code committed to git +xo_add_genfacetimpl( + TARGET xo-object2-facetimpl-gcobject-runtimeerror + FACET_PKG xo_alloc2 +# REPR RuntimeError + INPUT idl/IGCObject_DRuntimeError.json5 +) + +# ---------------------------------------------------------------- + +xo_add_genfacet_all(xo-object2-genfacet-all) + +# ---------------------------------------------------------------- + +# must complete definition of expression lib before configuring examples +add_subdirectory(src/object2) +add_subdirectory(utest) + +install(DIRECTORY idl/ + DESTINATION share/${PROJECT_NAME}/idl + FILES_MATCHING PATTERN "*.json5") + +xo_export_cmake_config(${PROJECT_NAME} ${PROJECT_VERSION} ${PROJECT_NAME}Targets) + +# ---------------------------------------------------------------- +# docs targets depend on other library/utest/exec targets above, +# --> must come after them. +# +#add_subdirectory(docs) + +# end CMakeLists.txt diff --git a/xo-object2/README.md b/xo-object2/README.md new file mode 100644 index 00000000..d77f60ba --- /dev/null +++ b/xo-object2/README.md @@ -0,0 +1 @@ +# xo-object2 diff --git a/xo-object2/cmake/xo-bootstrap-macros.cmake b/xo-object2/cmake/xo-bootstrap-macros.cmake new file mode 100644 index 00000000..aba31169 --- /dev/null +++ b/xo-object2/cmake/xo-bootstrap-macros.cmake @@ -0,0 +1,35 @@ +# ---------------------------------------------------------------- +# for example: +# $ PREFIX=/usr/local # for example +# $ cmake -DCMAKE_MODULE_PATH=prefix -DCMAKE_INSTALL_PREFIX=$PREFIX -B .build +# +# will get +# CMAKE_MODULE_PATH +# from xo-cmake-config --cmake-module-path +# +# and expect .cmake macros in +# CMAKE_MODULE_PATH/xo_macros/xo_cxx.cmake +# ---------------------------------------------------------------- + +find_program(XO_CMAKE_CONFIG_EXECUTABLE NAMES xo-cmake-config REQUIRED) + +if ("${XO_CMAKE_CONFIG_EXECUTABLE}" STREQUAL "XO_CMAKE_CONFIG_EXECUTABLE-NOT_FOUND") + message(FATAL "could not find xo-cmake-config executable") +endif() + +message(STATUS "XO_CMAKE_CONFIG_EXECUTABLE=${XO_CMAKE_CONFIG_EXECUTABLE}") + +if (NOT XO_SUBMODULE_BUILD) + if (("${CMAKE_MODULE_PATH}" STREQUAL "") OR ("${CMAKE_MODULE_PATH}" STREQUAL prefix)) + # default to typical install location for xo-project-macros + execute_process(COMMAND ${XO_CMAKE_CONFIG_EXECUTABLE} --cmake-module-path OUTPUT_VARIABLE CMAKE_MODULE_PATH) + message(STATUS "CMAKE_MODULE_PATH=${CMAKE_MODULE_PATH}") + endif() +endif() + +# needs to have been installed somewhere on CMAKE_MODULE_PATH, +# (e.g. from xo-cmake with the same value for CMAKE_INSTALL_PREFIX) +# +include(xo_macros/xo_cxx) + +xo_cxx_bootstrap_message() diff --git a/xo-object2/cmake/xo_object2Config.cmake.in b/xo-object2/cmake/xo_object2Config.cmake.in new file mode 100644 index 00000000..b34f76ff --- /dev/null +++ b/xo-object2/cmake/xo_object2Config.cmake.in @@ -0,0 +1,12 @@ +@PACKAGE_INIT@ + +include(CMakeFindDependencyMacro) +find_dependency(reflect) +find_dependency(xo_stringtable2) +find_dependency(xo_alloc2) +find_dependency(xo_printable2) +find_dependency(subsys) +find_dependency(indentlog) +include("${CMAKE_CURRENT_LIST_DIR}/@PROJECT_NAME@Targets.cmake") +include("${CMAKE_CURRENT_LIST_DIR}/@PROJECT_NAME@Share.cmake") +check_required_components("@PROJECT_NAME@") diff --git a/xo-object2/doc/glossary.rst b/xo-object2/doc/glossary.rst new file mode 100644 index 00000000..4cabbbd5 --- /dev/null +++ b/xo-object2/doc/glossary.rst @@ -0,0 +1 @@ +gco = gc-aware object diff --git a/xo-object2/idl/IGCObject_DArray.json5 b/xo-object2/idl/IGCObject_DArray.json5 new file mode 100644 index 00000000..4d7187b9 --- /dev/null +++ b/xo-object2/idl/IGCObject_DArray.json5 @@ -0,0 +1,18 @@ +{ + mode: "implementation", + output_cpp_dir: "src/object2", + output_hpp_dir: "include/xo/object2", + output_impl_subdir: "array", + includes: [ +// "", +// "" + ], + local_types: [ ], + namespace1: "xo", + namespace2: "scm", + facet_idl: "idl/GCObject.json5", + brief: "provide AGCObject interface for DArray", + using_doxygen: true, + repr: "DArray", + doc: [ "implement AGCObject for DArray" ], +} diff --git a/xo-object2/idl/IGCObject_DBoolean.json5 b/xo-object2/idl/IGCObject_DBoolean.json5 new file mode 100644 index 00000000..c739ccda --- /dev/null +++ b/xo-object2/idl/IGCObject_DBoolean.json5 @@ -0,0 +1,18 @@ +{ + mode: "implementation", + output_cpp_dir: "src/object2", + output_hpp_dir: "include/xo/object2", + output_impl_subdir: "boolean", + includes: [ +// "", +// "" + ], + local_types: [ ], + namespace1: "xo", + namespace2: "scm", + facet_idl: "idl/GCObject.json5", + brief: "provide AGCObject interface for DBoolean", + using_doxygen: true, + repr: "DBoolean", + doc: [ "implement AGCObject for DBoolean" ], +} diff --git a/xo-object2/idl/IGCObject_DDictionary.json5 b/xo-object2/idl/IGCObject_DDictionary.json5 new file mode 100644 index 00000000..07a171c5 --- /dev/null +++ b/xo-object2/idl/IGCObject_DDictionary.json5 @@ -0,0 +1,18 @@ +{ + mode: "implementation", + output_cpp_dir: "src/object2", + output_hpp_dir: "include/xo/object2", + output_impl_subdir: "dictionary", + includes: [ +// "", +// "" + ], + local_types: [ ], + namespace1: "xo", + namespace2: "scm", + facet_idl: "idl/GCObject.json5", + brief: "provide AGCObject interface for DDictionary", + using_doxygen: true, + repr: "DDictionary", + doc: [ "implement AGCObject for DDictionary" ], +} diff --git a/xo-object2/idl/IGCObject_DFloat.json5 b/xo-object2/idl/IGCObject_DFloat.json5 new file mode 100644 index 00000000..c1f12815 --- /dev/null +++ b/xo-object2/idl/IGCObject_DFloat.json5 @@ -0,0 +1,19 @@ +{ + mode: "implementation", + output_cpp_dir: "src/object2", + output_hpp_dir: "include/xo/object2", + output_impl_subdir: "number", + includes: [ + "", +// "", +// "" + ], + local_types: [ ], + namespace1: "xo", + namespace2: "scm", + facet_idl: "idl/GCObject.json5", + brief: "provide AGCObject interface for DFloat", + using_doxygen: true, + repr: "DFloat", + doc: [ "implement AGCObject for DFloat" ], +} diff --git a/xo-object2/idl/IGCObject_DInteger.json5 b/xo-object2/idl/IGCObject_DInteger.json5 new file mode 100644 index 00000000..cb318ee1 --- /dev/null +++ b/xo-object2/idl/IGCObject_DInteger.json5 @@ -0,0 +1,18 @@ +{ + mode: "implementation", + output_cpp_dir: "src/object2", + output_hpp_dir: "include/xo/object2", + output_impl_subdir: "number", + includes: [ +// "", +// "" + ], + local_types: [ ], + namespace1: "xo", + namespace2: "scm", + facet_idl: "idl/GCObject.json5", + brief: "provide AGCObject interface for DInteger", + using_doxygen: true, + repr: "DInteger", + doc: [ "implement AGCObject for DInteger" ], +} diff --git a/xo-object2/idl/IGCObject_DList.json5 b/xo-object2/idl/IGCObject_DList.json5 new file mode 100644 index 00000000..83d1838b --- /dev/null +++ b/xo-object2/idl/IGCObject_DList.json5 @@ -0,0 +1,16 @@ +{ + mode: "implementation", + output_cpp_dir: "src/object2", + output_hpp_dir: "include/xo/object2", + output_impl_subdir: "list", + includes: [ + ], + local_types: [ ], + namespace1: "xo", + namespace2: "scm", + facet_idl: "idl/GCObject.json5", + brief: "provide AGCObject interface for DList", + using_doxygen: true, + repr: "DList", + doc: [ "implement AGCObject for DList" ], +} diff --git a/xo-object2/idl/IGCObject_DRuntimeError.json5 b/xo-object2/idl/IGCObject_DRuntimeError.json5 new file mode 100644 index 00000000..a0e15042 --- /dev/null +++ b/xo-object2/idl/IGCObject_DRuntimeError.json5 @@ -0,0 +1,18 @@ +{ + mode: "implementation", + output_cpp_dir: "src/object2", + output_hpp_dir: "include/xo/object2", + output_impl_subdir: "error", + includes: [ +// "", +// "" + ], + local_types: [ ], + namespace1: "xo", + namespace2: "scm", + facet_idl: "idl/GCObject.json5", + brief: "provide AGCObject interface for DRuntimeError", + using_doxygen: true, + repr: "DRuntimeError", + doc: [ "implement AGCObject for DRuntimeError" ], +} diff --git a/xo-object2/idl/IPrintable_DArray.json5 b/xo-object2/idl/IPrintable_DArray.json5 new file mode 100644 index 00000000..b9bde4f4 --- /dev/null +++ b/xo-object2/idl/IPrintable_DArray.json5 @@ -0,0 +1,16 @@ +{ + mode: "implementation", + output_cpp_dir: "src/object2", + output_hpp_dir: "include/xo/object2", + output_impl_subdir: "array", + includes: [ "", + "" ], + local_types: [ ], + namespace1: "xo", + namespace2: "scm", + facet_idl: "idl/Printable.json5", + brief: "provide APrintable interface for DArray", + using_doxygen: true, + repr: "DArray", + doc: [ "implement APrintable for DArray" ], +} diff --git a/xo-object2/idl/IPrintable_DBoolean.json5 b/xo-object2/idl/IPrintable_DBoolean.json5 new file mode 100644 index 00000000..db949258 --- /dev/null +++ b/xo-object2/idl/IPrintable_DBoolean.json5 @@ -0,0 +1,16 @@ +{ + mode: "implementation", + output_cpp_dir: "src/object2", + output_hpp_dir: "include/xo/object2", + output_impl_subdir: "boolean", + includes: [ "", + "" ], + local_types: [ ], + namespace1: "xo", + namespace2: "scm", + facet_idl: "idl/Printable.json5", + brief: "provide APrintable interface for DBoolean", + using_doxygen: true, + repr: "DBoolean", + doc: [ "implement APrintable for DBoolean" ], +} diff --git a/xo-object2/idl/IPrintable_DDictionary.json5 b/xo-object2/idl/IPrintable_DDictionary.json5 new file mode 100644 index 00000000..ad1fda52 --- /dev/null +++ b/xo-object2/idl/IPrintable_DDictionary.json5 @@ -0,0 +1,16 @@ +{ + mode: "implementation", + output_cpp_dir: "src/object2", + output_hpp_dir: "include/xo/object2", + output_impl_subdir: "dictionary", + includes: [ "", + "" ], + local_types: [ ], + namespace1: "xo", + namespace2: "scm", + facet_idl: "idl/Printable.json5", + brief: "provide APrintable interface for DDictionary", + using_doxygen: true, + repr: "DDictionary", + doc: [ "implement APrintable for DDictionary" ], +} diff --git a/xo-object2/idl/IPrintable_DFloat.json5 b/xo-object2/idl/IPrintable_DFloat.json5 new file mode 100644 index 00000000..d28680f0 --- /dev/null +++ b/xo-object2/idl/IPrintable_DFloat.json5 @@ -0,0 +1,16 @@ +{ + mode: "implementation", + output_cpp_dir: "src/object2", + output_hpp_dir: "include/xo/object2", + output_impl_subdir: "number", + includes: [ "", + "" ], + local_types: [ ], + namespace1: "xo", + namespace2: "scm", + facet_idl: "idl/Printable.json5", + brief: "provide APrintable interface for DFloat", + using_doxygen: true, + repr: "DFloat", + doc: [ "implement APrintable for DFloat" ], +} diff --git a/xo-object2/idl/IPrintable_DInteger.json5 b/xo-object2/idl/IPrintable_DInteger.json5 new file mode 100644 index 00000000..478da579 --- /dev/null +++ b/xo-object2/idl/IPrintable_DInteger.json5 @@ -0,0 +1,16 @@ +{ + mode: "implementation", + output_cpp_dir: "src/object2", + output_hpp_dir: "include/xo/object2", + output_impl_subdir: "number", + includes: [ "", + "" ], + local_types: [ ], + namespace1: "xo", + namespace2: "scm", + facet_idl: "idl/Printable.json5", + brief: "provide APrintable interface for DInteger", + using_doxygen: true, + repr: "DInteger", + doc: [ "implement APrintable for DInteger" ], +} diff --git a/xo-object2/idl/IPrintable_DList.json5 b/xo-object2/idl/IPrintable_DList.json5 new file mode 100644 index 00000000..a7a6bfb6 --- /dev/null +++ b/xo-object2/idl/IPrintable_DList.json5 @@ -0,0 +1,16 @@ +{ + mode: "implementation", + output_cpp_dir: "src/object2", + output_hpp_dir: "include/xo/object2", + output_impl_subdir: "list", + includes: [ "", + "" ], + local_types: [ ], + namespace1: "xo", + namespace2: "scm", + facet_idl: "idl/Printable.json5", + brief: "provide APrintable interface for DList", + using_doxygen: true, + repr: "DList", + doc: [ "implement APrintable for DList" ], +} diff --git a/xo-object2/idl/IPrintable_DRuntimeError.json5 b/xo-object2/idl/IPrintable_DRuntimeError.json5 new file mode 100644 index 00000000..a8404925 --- /dev/null +++ b/xo-object2/idl/IPrintable_DRuntimeError.json5 @@ -0,0 +1,16 @@ +{ + mode: "implementation", + output_cpp_dir: "src/object2", + output_hpp_dir: "include/xo/object2", + output_impl_subdir: "error", + includes: [ "", + "" ], + local_types: [ ], + namespace1: "xo", + namespace2: "scm", + facet_idl: "idl/Printable.json5", + brief: "provide APrintable interface for DRuntimeError", + using_doxygen: true, + repr: "DRuntimeError", + doc: [ "implement APrintable for DRuntimeError" ], +} diff --git a/xo-object2/idl/ISequence_DArray.json5 b/xo-object2/idl/ISequence_DArray.json5 new file mode 100644 index 00000000..265c3795 --- /dev/null +++ b/xo-object2/idl/ISequence_DArray.json5 @@ -0,0 +1,15 @@ +{ + mode: "implementation", + output_cpp_dir: "src/object2", + output_hpp_dir: "include/xo/object2", + output_impl_subdir: "array", + includes: [ ], + local_types: [ ], + namespace1: "xo", + namespace2: "scm", + facet_idl: "idl/Sequence.json5", + brief: "provide ASequence interface for DArray state", + using_doxygen: true, + repr: "DArray", + doc: [ "implement ASequence for DArray" ], +} diff --git a/xo-object2/idl/ISequence_DList.json5 b/xo-object2/idl/ISequence_DList.json5 new file mode 100644 index 00000000..2ff69f04 --- /dev/null +++ b/xo-object2/idl/ISequence_DList.json5 @@ -0,0 +1,15 @@ +{ + mode: "implementation", + output_cpp_dir: "src/object2", + output_hpp_dir: "include/xo/object2", + output_impl_subdir: "list", + includes: [ "" ], + local_types: [ ], + namespace1: "xo", + namespace2: "scm", + facet_idl: "idl/Sequence.json5", + brief: "provide ASequence interface for DList state", + using_doxygen: true, + repr: "DList", + doc: [ "implement ASequence for DList" ], +} \ No newline at end of file diff --git a/xo-object2/idl/Sequence.json5 b/xo-object2/idl/Sequence.json5 new file mode 100644 index 00000000..0b022f0b --- /dev/null +++ b/xo-object2/idl/Sequence.json5 @@ -0,0 +1,74 @@ +{ + mode: "facet", + output_cpp_dir: "src/object2", + output_hpp_dir: "include/xo/object2", + output_impl_subdir: "sequence", + includes: [""], + // extra includes in Sequence.hpp, if any + user_hpp_includes: [], + namespace1: "xo", + namespace2: "scm", + // text after includes, before ASequence + pretext: [ "// {pretext} here" ], + facet: "Sequence", + detail_subdir: "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" + ], + types: [ + // using size_type = std::size_t + { + name: "size_type", + doc: ["type for length of a sequence"], + definition: "std::size_t", + }, + // using AGCObject = xo::mm::AGCObject + { + name: "AGCObject", + doc: ["facet for types with GC support"], + definition: "xo::mm::AGCObject", + } + ], + const_methods: [ + // bool is_empty() const noexcept + { + name: "is_empty", + doc: ["true iff sequence is empty"], + return_type: "bool", + args: [], + const: true, + noexcept: true, + attributes: [], + }, + + // bool is_finite() const noexcept + { + name: "is_finite", + doc: ["true iff sequence is finite"], + return_type: "bool", + args: [], + const: true, + noexcept: true, + attributes: [], + }, + + // obj at(size_type index) const; + { + name: "at", + doc: ["return element @p index of this sequence"], + return_type: "obj", + args: [ + {type: "size_type", name: "index"}, + ], + const: true, + noexcept: false, + attributes: [], + }, + ], + nonconst_methods: [ + ], + router_facet_explicit_content: [] +} diff --git a/xo-object2/include/xo/object2/Array.hpp b/xo-object2/include/xo/object2/Array.hpp new file mode 100644 index 00000000..12c6eaa5 --- /dev/null +++ b/xo-object2/include/xo/object2/Array.hpp @@ -0,0 +1,14 @@ +/** @file Array.hpp + * + * @author Roland Conybeare, Feb 2026 + **/ + +#pragma once + +#include "DArray.hpp" +#include "array/ISequence_DArray.hpp" +#include "array/IGCObject_DArray.hpp" +#include "array/IPrintable_DArray.hpp" + + +/* end Array.hpp */ diff --git a/xo-object2/include/xo/object2/Boolean.hpp b/xo-object2/include/xo/object2/Boolean.hpp new file mode 100644 index 00000000..a246ffc0 --- /dev/null +++ b/xo-object2/include/xo/object2/Boolean.hpp @@ -0,0 +1,12 @@ +/** @file Boolean.hpp + * + * @author Roland Conybeare, Feb 2026 + **/ + +#pragma once + +#include "DBoolean.hpp" +#include "boolean/IGCObject_DBoolean.hpp" +#include "boolean/IPrintable_DBoolean.hpp" + +/* end Boolean.hpp */ diff --git a/xo-object2/include/xo/object2/DArray.hpp b/xo-object2/include/xo/object2/DArray.hpp new file mode 100644 index 00000000..5f571333 --- /dev/null +++ b/xo-object2/include/xo/object2/DArray.hpp @@ -0,0 +1,250 @@ +/** @file DArray.hpp +* + * @author Roland Conybeare, Jan 2026 + **/ + +#pragma once + +#include +#include +#include +#include +#include +#include + +namespace xo { + namespace scm { + class DArray; + + namespace detail { + /** null base case **/ + static inline bool do_array_push_back(DArray *, + obj) + { + return true; + } + + template + requires (std::convertible_to>) + static bool do_array_push_back(DArray * lhs, + obj mm, + A arg1, + Rest... rest); + } + + /** @class DArray + * @brief Polymorphic array implementation with gc hooks + * + * 1D Array implementation for Schematika + * Like DString, this implementation has max capacity + * fixed at construction time, but not part of type. + * Can reallocate to change + **/ + class DArray { + public: + /** @defgroup darray-types type traits **/ + ///@{ + + /** type for array size **/ + using size_type = std::uint32_t; + using AAllocator = xo::mm::AAllocator; + //using ACollector = xo::mm::ACollector; + using AGCObject = xo::mm::AGCObject; + /** gc-centric object visitor **/ + using AGCObjectVisitor = xo::mm::AGCObjectVisitor; + /** hint for object visitor **/ + using VisitReason = xo::mm::VisitReason; + /** pretty-printer state for APrintable **/ + using ppindentinfo = xo::print::ppindentinfo; + + ///@} + /** @defgroup darray-ctors constructors **/ + ///@{ + + /** default ctor. zero capacity sentinel **/ + DArray() = default; + + /** not simply copyable because of flexible array. + * Need allocator. See @ref clone + **/ + DArray(const DArray &) = delete; + + /** create empty array with space for @p cap elements + * using memory from allocator @p mm. + * Nullptr if space exhausted + **/ + static DArray * _empty(obj mm, + size_type cap); + + /** ofp version of _empty(mm,cap) **/ + template + static obj empty(obj mm, + size_type cap); + + /** create copy of @p src using memory from @p mm + * with capacity for @p new_cap elements + **/ + static DArray * copy(obj mm, + DArray * src, + size_type new_cap); + + /** create array containing elements @p args, using memory from @p mm. + * Nullptr if space exhausted. + * + * Use: + * Darray * v = DArray::array(mm, e1, e2, e3); + **/ + template + requires (std::convertible_to> && ...) + static DArray * array(obj mm, Args... args); + + ///@} + /** @defgroup darray-access access methods **/ + ///@{ + + /** create fop for this instance **/ + template + obj ref() { return obj(this); } + + /** true iff array is empty **/ + bool is_empty() const noexcept { return size_ == 0; } + /** only support finite arrays :-) **/ + bool is_finite() const noexcept { return true; } + /** array capacity **/ + size_type capacity() const noexcept { return capacity_; } + /** current array size (number of elements) **/ + size_type size() const noexcept { return size_; } + /** return element @p index of this array (0-based) **/ + obj at(size_type index) const; + + const obj & operator[](size_type index) const noexcept { return elts_[index]; } + + ///@} + /** @defgroup darray-iterators iterators **/ + ///@{ + + ///@} + /** @defgroup darray-assign assignment **/ + ///@{ + + /** store @p elt at position @p index. + * true on success, false otherwise + **/ + bool assign_at(obj mm, size_type index, obj elt) noexcept; + + /** append @p elt at the end of array. + * true on success, false otherwise. + * on failure array is unaltered + **/ + bool push_back(obj mm, obj elt) noexcept; + + template + requires (std::convertible_to> && ...) + bool push_back_all(obj mm, Args... args) noexcept; + + /** store last element in array into @p elt and decrement array size. + * true on success; false on failure (implies array was empty) + **/ + bool pop_back(obj * p_elt = nullptr) noexcept; + + ///@} + /** @defgroup darray-general general methods **/ + ///@{ + + /** resize to @p new_size. @p new_size may not be larger than capacity + * Return true if resize was accomplished; false otherwise. + **/ + bool resize(size_type new_size) noexcept; + + /** reduce array capacity to current array size + * + * note: with X1Collector, capacity is reduced but memory not recycled + * until next collection + **/ + void shrink_to_fit() noexcept; + + ///@} + /** @defgroup darray-conversion-operators conversion operators **/ + ///@{ + + ///@} + /** @defgroup darray-sequence-methods **/ + ///@{ + + ///@} + /** @defgroup darray-printable-methods **/ + ///@{ + + /** pretty-printing support **/ + bool pretty(const ppindentinfo & ppii) const; + + ///@} + /** @defgroup darray-gcobject-methods **/ + ///@{ + /** move to new address, mandated by @p gc **/ + DArray * gco_shallow_move(obj gc) noexcept; + /** forward elements to @p gc to-space; replace originals with forarding pointers **/ + void visit_gco_children(VisitReason reason, obj gc) noexcept; + ///@} + + private: + /** @defgroup darray-instance-variables instance variables **/ + ///@{ + + /** extent of @ref elts_ array **/ + size_type capacity_ = 0; + /** array size + * Invariant: size_ <= capacity_ + **/ + size_type size_ = 0; + /** array elements, using flexible array **/ + obj elts_[]; + + ///@} + }; + + template + obj + DArray::empty(obj mm, DArray::size_type cap) + { + DArray * retval = _empty(mm, cap); + + return obj(retval); + } + + template + requires (std::convertible_to> && ...) + DArray * + DArray::array(obj mm, Args... args) + { + DArray * result = _empty(mm, sizeof...(args)); + if (result) { + detail::do_array_push_back(result, mm, args...); + } + return result; + } + + namespace detail { + template + requires (std::convertible_to>) + static bool do_array_push_back(DArray * lhs, + obj mm, + A arg1, + Rest... rest) + { + return (lhs->push_back(mm, arg1) + && do_array_push_back(lhs, mm, rest...)); + } + } + + template + requires (std::convertible_to> && ...) + bool + DArray::push_back_all(obj mm, Args... args) noexcept { + return detail::do_array_push_back(this, mm, args...); + } + + } /*namespace scm*/ +} /*namespace xo*/ + +/* end DArray.hpp */ diff --git a/xo-object2/include/xo/object2/DBoolean.hpp b/xo-object2/include/xo/object2/DBoolean.hpp new file mode 100644 index 00000000..7be4c073 --- /dev/null +++ b/xo-object2/include/xo/object2/DBoolean.hpp @@ -0,0 +1,58 @@ +/** @file DBoolean.hpp + * + * @author Roland Conybeare, Dec 2025 + **/ + +#pragma once + +#include +#include +#include +#include +#include + +namespace xo { + namespace scm { + struct DBoolean { + using AAllocator = xo::mm::AAllocator; + using AGCObjectVisitor = xo::mm::AGCObjectVisitor; + using AGCObject = xo::mm::AGCObject; + using VisitReason = xo::mm::VisitReason; + using ppindentinfo = xo::print::ppindentinfo; + using value_type = long; + + explicit DBoolean(bool x) : value_{x} {} + + /** will likely want this to default to ANumeric, once we have it **/ + template + static obj box(obj mm, bool x); + + /** allocate boxed value @p x using memory from @p mm **/ + static DBoolean * _box(obj mm, bool x); + + bool value() const noexcept { return value_; } + + bool pretty(const ppindentinfo & ppii) const; + + operator bool() const noexcept { return value_; } + + // GCObject facet + + DBoolean * gco_shallow_move(obj gc) noexcept; + void visit_gco_children(VisitReason reason, obj gc) noexcept; + + private: + /** boxed boolean value **/ + bool value_ = false; + }; + + template + obj + DBoolean::box(obj mm, bool x) { + return obj(_box(mm, x)); + } + + } /*nmaespace obj*/ +} /*namespace xo*/ + +/* end DBoolean.hpp */ diff --git a/xo-object2/include/xo/object2/DDictionary.hpp b/xo-object2/include/xo/object2/DDictionary.hpp new file mode 100644 index 00000000..3fad8ece --- /dev/null +++ b/xo-object2/include/xo/object2/DDictionary.hpp @@ -0,0 +1,247 @@ +/** @file DDictionary.hpp + * + * @author Roland Conybeare, Jan 2026 + **/ + +#pragma once + +#include "DArray.hpp" +#include "DString.hpp" +#include +#include +#include +#include +#include +#include +#include + +namespace xo { + namespace scm { + /** @class DStruct + * @brief Polymorphic in-memory key-value store with gc hooks + * + * Small dictionary implementation for Schematika. + * O(n) lookup, at least for now. Not typed. Keys are strings, + * so functionally equivalent to python dictionaries. + **/ + class DDictionary { + public: + /** @defgroup ddictionary-types type traits **/ + ///@{ + + /** type for array size **/ + using size_type = std::uint32_t; + /** xo allocator facet **/ + using AAllocator = xo::mm::AAllocator; + /** gc-centric object visitor **/ + using AGCObjectVisitor = xo::mm::AGCObjectVisitor; + /** gc-aware object facet **/ + using AGCObject = xo::mm::AGCObject; + /** color for gco visitor **/ + using VisitReason = xo::mm::VisitReason; + /** pretty-printer state for APrintable **/ + using ppindentinfo = xo::print::ppindentinfo; + /** canonical type representing a key-value pair **/ + using pair_type = std::pair>; + + /** shim to represent result of expression like @c dict[key] + **/ + template + class LValue { + public: + LValue(DictPtr d, const DString * key) : dict_{d}, key_{key} {} + + bool is_sentinel() const noexcept { return dict_ == nullptr; } + bool is_valid() const noexcept { return dict_ != nullptr; } + + obj & operator=(obj & rvalue) { + return dict_->upsert(key_, rvalue); + } + + operator std::optional>() const noexcept { + return dict_->lookup(key_); + } + + private: + /** sentinel LValue represented by null ptr here **/ + DictPtr dict_ = nullptr; + /** sentinel LValue has null ptr here **/ + const DString * key_ = nullptr; + }; + + ///@} + /** @defgroup ddictionary-ctors constructors **/ + ///@{ + + /** default ctor. zero capacity sentinel **/ + DDictionary(DArray * keys, DArray * values); + + /** create empty array with space for @p cap elements + * using memory from allocator @p mm. + * Nullptr if space exhausted + **/ + static DDictionary * empty(obj mm, + size_type cap); + + /** create copy of @p src using memory from @p mm + * with capacity for @p new_cap elements + **/ + static DDictionary * copy(obj mm, + DDictionary * src, + size_type new_cap); + + /** create dictionary containing elements @p kv_pairs, using memory from @p mm. + * Nullptr if space exhausted. + * + * Use: + * auto kv1 = std::make_pair>(...); + * auto kv2 = std::make_pair>(...); + * Ddictionary * v = DDictionary::make(mm, kv1, kv2, ..); + **/ + template + requires (std::same_as>> && ...) + static DDictionary * make(obj mm, Args... args); + + ///@} + /** @defgroup ddictionary-access acecss methods **/ + ///@{ + /** true iff array is empty **/ + bool is_empty() const noexcept { return keys_->size() == 0; } + /** array capacity **/ + size_type capacity() const noexcept { return keys_->capacity(); } + /** current dictionary size (number of key-value pairs) **/ + size_type size() const noexcept { return keys_->size(); } + + /** return value associated with @p key, if key is present **/ + std::optional> lookup(const DString * key) const noexcept; + /** return value associated with @p key, if key is present **/ + std::optional> lookup_cstr(const char * key) const noexcept; + + /** return element @p key-value pair at position @p index (0-based) **/ + std::pair> at_index(size_type index) const; + /** return @p i'th key. O(1) **/ + const DString * key_at_index(size_type i) const; + /** return @p i'th value. O(1) **/ + obj value_at_index(size_type i) const; + + + auto operator[](const DString * key) const noexcept { return LValue(this, key); } + auto operator[](const DString * key) noexcept { return LValue(this, key); } + + ///@} + /** @defgroup ddictionary-iterators iterators **/ + ///@{ + + ///@} + /** @defgroup ddictionary-assign assignment **/ + ///@{ + + /** update key-value pair @p kvpair in-place, + * provide key is already present. + * + * @return true if key-value pair updated; false if key not found + **/ + bool try_update(obj mm, const pair_type & kvpair); + + /** update key-value pair for existing @p key to map to @p value. + * false if @p key not already present. + **/ + bool try_update_cstr(obj gc, const char * key, obj value); + + /** convenience method: + * try_upsert pair (k, @p value), after boxing c-style string @p key with @p mm to get k + **/ + bool try_upsert_cstr(obj mm, const char * key, obj value); + + /** convenience method: + * upsert pair (k, @p value), after boxing c-style string @p key with @p mm to get k + **/ + bool upsert_cstr(obj mm, const char * key, obj value); + + /** upsert key-value pair @p kvpair into dictionary. + * If key kvpair.first not already present, add it. + * In either case replace/establish associated value with kvpair.second. + * + * False if dictionary already at capacity + **/ + bool try_upsert(obj gc, const pair_type & kvpair); + + /** upsert key-value pair @p kvpair into dictionary. + * If at capacity, expand capacity, getting new memory from @p mm. + * + * False iff upsert failed because allocator memory exhausted + **/ + bool upsert(obj mm, const pair_type & kvpair); + + ///@} + /** @defgroup ddictionary-general general methods **/ + ///@{ + + /** reduce array capacity to current array size + * + * note: with X1Collector, capacity is reduced but memory not recycled + * until next collection + **/ + void shrink_to_fit() noexcept; + + ///@} + /** @defgroup ddictionary-conversion-operators conversion operators **/ + ///@{ + + ///@} + /** @defgroup ddictionary-sequence-methods **/ + ///@{ + + ///@} + /** @defgroup ddictionary-printable-methods **/ + ///@{ + + /** pretty-printing support **/ + bool pretty(const ppindentinfo & ppii) const; + + ///@} + /** @defgroup ddictionary-gcobject-methods **/ + ///@{ + /** return shallow copy of this array, using memory from @p mm **/ + DDictionary * gco_shallow_move(obj gc) noexcept; + /** forward elements to @p gc to-space; replace originals with forwarding pointers **/ + void visit_gco_children(VisitReason reason, obj gc) noexcept; + ///@} + + private: + /** @defgroup ddictionary-impl-methods implementation methods **/ + ///@{ + /** append {key, value} pair @p kv_pair to this dictionary + * Require: @p kv_pair.first not already present in @ref keys_ + **/ + bool _append_kv_aux(obj mm, const pair_type & kv_pair); + ///@} + + private: + /** @defgroup ddictionary-instance-variables instance variables **/ + ///@{ + + /** dictionary keys. These will be strings **/ + DArray * keys_; + /** dictionary values. values_[i] associates with keys_[i] **/ + DArray * values_; + + ///@} + }; + + template + requires (std::same_as>> && ...) + DDictionary * + DDictionary::make(obj mm, Args... args) + { + DDictionary * result = empty(mm, sizeof...(args)); + if (result) { + (result->upsert(mm, args), ...); + } + return result; + } + + } /*namespace scm*/ +} /*namespace xo*/ + +/* end DDictionary.hpp */ diff --git a/xo-object2/include/xo/object2/DFloat.hpp b/xo-object2/include/xo/object2/DFloat.hpp new file mode 100644 index 00000000..54ffe41f --- /dev/null +++ b/xo-object2/include/xo/object2/DFloat.hpp @@ -0,0 +1,55 @@ +/** @file DFloat.hpp + * + * @author Roland Conybeare, Dec 2025 + **/ + +#pragma once + +#include +#include +#include +#include + +namespace xo { + namespace scm { + struct DFloat { + using AAllocator = xo::mm::AAllocator; + using AGCObjectVisitor = xo::mm::AGCObjectVisitor; + using VisitReason = xo::mm::VisitReason; + using ppindentinfo = xo::print::ppindentinfo; + using value_type = double; + + explicit DFloat(double x) : value_{x} {} + + /** probably want default = ANumeric, once we introduce it **/ + template + static obj box(obj mm, double x); + + /** allocate boxed value @p x using memory from @p mm **/ + static DFloat * _box(obj mm, double x); + + double value() const noexcept { return value_; } + + operator double() const noexcept { return value_; } + + bool pretty(const ppindentinfo & ppii) const; + + // GCObject facet + DFloat * gco_shallow_move(obj gc) noexcept; + void visit_gco_children(VisitReason reason, obj gc) noexcept; + + private: + + /** boxed floating-oint value **/ + double value_; + }; + + template + obj + DFloat::box(obj mm, double x) { + return obj(DFloat::_box(mm, x)); + } + } /*nmaespace scm*/ +} /*namespace xo*/ + +/* end DFloat.hpp */ diff --git a/xo-object2/include/xo/object2/DInteger.hpp b/xo-object2/include/xo/object2/DInteger.hpp new file mode 100644 index 00000000..8bf881a9 --- /dev/null +++ b/xo-object2/include/xo/object2/DInteger.hpp @@ -0,0 +1,60 @@ +/** @file DInteger.hpp + * + * @author Roland Conybeare, Dec 2025 + **/ + +#pragma once + +#include +#include +#include +#include +#include + +namespace xo { + namespace scm { + struct DInteger { + using AAllocator = xo::mm::AAllocator; + using AGCObjectVisitor = xo::mm::AGCObjectVisitor; + using AGCObject = xo::mm::AGCObject; + using VisitReason = xo::mm::VisitReason; + using ppindentinfo = xo::print::ppindentinfo; + using value_type = long; + + explicit DInteger(long x) : value_{x} {} + + /** will likely want this to default to ANumeric, once we have it **/ + template + static obj box(obj mm, long x); + + /** allocate boxed value @p x using memory from @p mm **/ + static DInteger * _box(obj mm, long x); + + long value() const noexcept { return value_; } + + bool pretty(const ppindentinfo & ppii) const; + + operator long() const noexcept { return value_; } + + void assign_value(long x) noexcept { this->value_ = x; } + + // GCObject facet + + DInteger * gco_shallow_move(obj gc) noexcept; + void visit_gco_children(VisitReason reason, obj gc) noexcept; + + private: + /** boxed integer value **/ + long value_; + }; + + template + obj + DInteger::box(obj mm, long x) { + return obj(_box(mm, x)); + } + + } /*nmaespace obj*/ +} /*namespace xo*/ + +/* end DInteger.hpp */ diff --git a/xo-object2/include/xo/object2/DList.hpp b/xo-object2/include/xo/object2/DList.hpp new file mode 100644 index 00000000..fbc64784 --- /dev/null +++ b/xo-object2/include/xo/object2/DList.hpp @@ -0,0 +1,92 @@ +/** @file DList.hpp + * + * @author Roland Conybeare, Dec 2025 + **/ + +#pragma once + +#include +#include +#include +#include + +namespace xo { + namespace scm { + + // TODO: consider renaming to DCons + // See also ListOps in ListOps.hpp + // + struct DList { + using size_type = std::size_t; + using AGCObject = xo::mm::AGCObject; + using AAllocator = xo::mm::AAllocator; + using ACollector = xo::mm::ACollector; + using AGCObjectVisitor = xo::mm::AGCObjectVisitor; + using VisitReason = xo::mm::VisitReason; + using ppindentinfo = xo::print::ppindentinfo; + + public: + DList(xo::obj h, + DList * r) : head_{h}, rest_{r} {} + + /** sentinel for null list. Idempotent. + * Application code may prefer ListOps::nil() + **/ + static DList * _nil(); + + /** like _nil(), but retrn fop wrapper **/ + static obj nil(); + + /** list with first element @p car, + * followed by contents of list @p cdr. + * Shares structure with @p cdr + * Application code may prefer ListOps::cons() + **/ + static DList * _cons(obj mm, + obj car, + DList * cdr); + + /** like @c _cons(mm,car,cdr), but return fop wrapper **/ + static obj cons(obj mm, + obj car, + DList * cdr); + + obj head() const noexcept { return head_; } + DList * rest() const noexcept { return rest_; } + + /** DList length is at least 1 **/ + bool is_empty() const noexcept; + /** 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; + + /** assign head **/ + void assign_head(obj mm, obj h); + void assign_head_gc(obj gc, obj h); + /** assign rest-pointer. Caller responsible for preserving acyclic property! **/ + void _assign_rest(obj mm, DList * r); + + /** pretty-printing driver; combine layout+printing **/ + bool pretty(const ppindentinfo & ppii) const; + + // GCObject facet + + /** @defgroup xo-scm-list-gcobject-facet gcobject facet **/ + ///@{ + DList * gco_shallow_move(obj gc) noexcept; + void visit_gco_children(VisitReason reason, obj gc) noexcept; + ///@} + + /** first member of list **/ + obj head_; + /** remainder of list **/ + DList * rest_ = nullptr; + }; + + } /*namespace scm*/ +} /*namespace xo*/ + +/* end DList.hpp */ diff --git a/xo-object2/include/xo/object2/DRuntimeError.hpp b/xo-object2/include/xo/object2/DRuntimeError.hpp new file mode 100644 index 00000000..e65b2883 --- /dev/null +++ b/xo-object2/include/xo/object2/DRuntimeError.hpp @@ -0,0 +1,72 @@ +/** @file DRuntimeError.hpp + * + * @author Roland Conybeare, Feb 2026 + **/ + +#pragma once + +#include "String.hpp" +#include +#include + +namespace xo { + namespace scm { + + /** @brief representation for runtime errors + **/ + class DRuntimeError { + public: + using AGCObject = xo::mm::AGCObject; + //using ACollector = xo::mm::ACollector; + using AGCObjectVisitor = xo::mm::AGCObjectVisitor; + using VisitReason = xo::mm::VisitReason; + using AAllocator = xo::mm::AAllocator; + using ppindentinfo = xo::print::ppindentinfo; + + public: + /** convenience shortcut.**/ + static obj make(obj mm, + const char * src_fn, + const char * error_descr); + + /** create instance using memory from allocator @p mm + * @p src_fn identifies the (c++) function/method in which + * error detercted. + * @p error_descr contains human-readable error message; + * will be copied by this function. + **/ + static DRuntimeError * _make(obj mm, + DString * src_fn, + DString * error_descr); + + DString * src_function() const noexcept { return src_function_; } + DString * error_descr() const noexcept { return error_descr_; } + + /** @defgroup scm-runtimeerror-printable-facet printable facet **/ + ///@{ + + bool pretty(const ppindentinfo & ppii) const; + + ///@} + /** @defgroup scm-runtimeerror-gcobject-facet gcobject facet **/ + ///@{ + + DRuntimeError * gco_shallow_move(obj gc) noexcept; + void visit_gco_children(VisitReason reason, obj gc) noexcept; + + ///@} + + private: + DRuntimeError(DString * src_fn, DString * error_descr); + + private: + /** source location at which error identified **/ + DString * src_function_ = nullptr; + /** error description (allocated from ErrorArena) **/ + DString * error_descr_ = nullptr; + }; + + } /*namespace scm*/ +} /*namespace xo*/ + +/* end DRuntimeError.hpp */ diff --git a/xo-object2/include/xo/object2/DStruct.hpp b/xo-object2/include/xo/object2/DStruct.hpp new file mode 100644 index 00000000..3776e376 --- /dev/null +++ b/xo-object2/include/xo/object2/DStruct.hpp @@ -0,0 +1,181 @@ +/** @file DStruct.hpp +* + * @author Roland Conybeare, Jan 2026 + **/ + +#pragma once + +#include "DArray.hpp" +#include +#include +#include +#include +#include +#include +#include + +namespace xo { + namespace scm { + /** @class DStruct + * @brief Polymorphic in-memory key-value store with gc hooks + * + * Small dictionary implementation for Schematika. + * O(n) lookup, at least for now. Keys are unique strings. + * Intended to have key-space fixed at comptime. + * Relevant since keys are immortal DUniqueStrings. + **/ + class DStruct { + public: + /** @defgroup dstruct-types type traits **/ + ///@{ + + /** type for array size **/ + using size_type = std::uint32_t; + /** xo allocator facet **/ + using AAllocator = xo::mm::AAllocator; + /** garbage collector facet **/ + using ACollector = xo::mm::ACollector; + /** gc-aware object facet **/ + using AGCObject = xo::mm::AGCObject; + /** pretty-printer state for APrintable **/ + using ppindentinfo = xo::print::ppindentinfo; + + ///@} + /** @defgroup dstruct-ctors constructors **/ + ///@{ + + /** default ctor. zero capacity sentinel **/ + DStruct() = default; + + /** not simply copyable because of flexible array. + * Need allocator. See @ref clone + **/ + DStruct(const DStruct &) = delete; + + /** create empty array with space for @p cap elements + * using memory from allocator @p mm. + * Nullptr if space exhausted + **/ + static DStruct * empty(obj mm, + size_type cap); + + /** create copy of @p src using memory from @p mm + * with capacity for @p new_cap elements + **/ + static DStruct * copy(obj mm, + DStruct * src, + size_type new_cap); + + /** create array containing elements @p args, using memory from @p mm. + * Nullptr if space exhausted. + * + * Use: + * Dstruct * v = DStruct::array(mm, e1, e2, e3); + **/ + template + requires (std::same_as> && ...) + static DStruct * array(obj mm, Args... args); + + ///@} + /** @defgroup dstruct-access acecss methods **/ + ///@{ + /** true iff array is empty **/ + bool is_empty() const noexcept { return size_ == 0; } + /** only support finite arrays :-) **/ + bool is_finite() const noexcept { return true; } + /** array capacity **/ + size_type capacity() const noexcept { return capacity_; } + /** current array size (number of elements) **/ + size_type size() const noexcept { return size_; } + /** return element @p index of this array (0-based) **/ + obj at(size_type index) const; + + const obj & operator[](size_type index) const noexcept { return elts_[index]; } + obj & operator[](size_type index) noexcept { return elts_[index]; } + + ///@} + /** @defgroup dstruct-iterators iterators **/ + ///@{ + + ///@} + /** @defgroup dstruct-assign assignment **/ + ///@{ + /** append @p elt at the end of array. + * true on success, false otherwise + **/ + bool push_back(obj elt) noexcept; + + ///@} + /** @defgroup dstruct-general general methods **/ + ///@{ + + /** resize to @p new_size. @p new_size may not be larger than capacity + * Return true if resize was accomplished; false otherwise. + **/ + bool resize(size_type new_size) noexcept; + + /** reduce array capacity to current array size + * + * note: with X1Collector, capacity is reduced but memory not recycled + * until next collection + **/ + void shrink_to_fit() noexcept; + + ///@} + /** @defgroup dstruct-conversion-operators conversion operators **/ + ///@{ + + ///@} + /** @defgroup dstruct-sequence-methods **/ + ///@{ + + ///@} + /** @defgroup dstruct-printable-methods **/ + ///@{ + + /** pretty-printing support **/ + bool pretty(const ppindentinfo & ppii) const; + + ///@} + /** @defgroup dstruct-gcobject-methods **/ + ///@{ + /** shallow memory consumption. Excludes child objects **/ + AAllocator::size_type shallow_size() const noexcept; + /** forward elements to @p gc to-space; replace originals with forarding pointers **/ + AAllocator::size_type forward_children(obj gc) noexcept; + ///@} + + private: + /** @defgroup dstruct-instance-variables instance variables **/ + ///@{ + + /** extent of @ref elts_ array **/ + size_type capacity_ = 0; + /** array size + * Invariant: size_ <= capacity_ + **/ + size_type size_ = 0; + /** struct keys. These will be unique strings **/ + DArray * keys_ = nullptr; + /** struct member values **/ + DArray * values_ = nullptr; + + ///@} + }; + + template + requires (std::same_as> && ...) + DStruct * + DStruct::array(obj mm, Args... args) + { + DStruct * result = empty(mm, sizeof...(args)); + if (result) { + (result->push_back(args), ...); + } + return result; + } + + } /*namespace scm*/ +} /*namespace xo*/ + +/* end DStruct.hpp */ diff --git a/xo-object2/include/xo/object2/Dictionary.hpp b/xo-object2/include/xo/object2/Dictionary.hpp new file mode 100644 index 00000000..6eaf7c24 --- /dev/null +++ b/xo-object2/include/xo/object2/Dictionary.hpp @@ -0,0 +1,12 @@ +/** @file Dictionary.hpp + * + * @author Roland Conybeare, Mar 2026 + **/ + +#pragma once + +#include "DDictionary.hpp" +#include "dictionary/IGCObject_DDictionary.hpp" +#include "dictionary/IPrintable_DDictionary.hpp" + +/* end Dictionary.hpp */ diff --git a/xo-object2/include/xo/object2/Float.hpp b/xo-object2/include/xo/object2/Float.hpp new file mode 100644 index 00000000..94751ecf --- /dev/null +++ b/xo-object2/include/xo/object2/Float.hpp @@ -0,0 +1,12 @@ +/** @file Float.hpp + * + * @author Roland Conybeare, Feb 2026 + **/ + +#pragma once + +#include "DFloat.hpp" +#include "number/IGCObject_DFloat.hpp" +#include "number/IPrintable_DFloat.hpp" + +/* end Float.hpp */ diff --git a/xo-object2/include/xo/object2/GCObjectConverter.hpp b/xo-object2/include/xo/object2/GCObjectConverter.hpp new file mode 100644 index 00000000..bf244f48 --- /dev/null +++ b/xo-object2/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/xo-object2/include/xo/object2/Integer.hpp b/xo-object2/include/xo/object2/Integer.hpp new file mode 100644 index 00000000..7279f97d --- /dev/null +++ b/xo-object2/include/xo/object2/Integer.hpp @@ -0,0 +1,12 @@ +/** @file Integer.hpp + * + * @author Roland Conybeare, Feb 2026 + **/ + +#pragma once + +#include "DInteger.hpp" +#include "number/IGCObject_DInteger.hpp" +#include "number/IPrintable_DInteger.hpp" + +/* end Integer.hpp */ diff --git a/xo-object2/include/xo/object2/List.hpp b/xo-object2/include/xo/object2/List.hpp new file mode 100644 index 00000000..872956ce --- /dev/null +++ b/xo-object2/include/xo/object2/List.hpp @@ -0,0 +1,13 @@ +/** @file List.hpp + * + * @author Roland Conybeare, Mar 2026 + **/ + +#pragma once + +#include "DList.hpp" +#include "list/IGCObject_DList.hpp" +#include "list/IPrintable_DList.hpp" +#include "list/ISequence_DList.hpp" + +/* end List.hpp */ diff --git a/xo-object2/include/xo/object2/ListOps.hpp b/xo-object2/include/xo/object2/ListOps.hpp new file mode 100644 index 00000000..25ddf77f --- /dev/null +++ b/xo-object2/include/xo/object2/ListOps.hpp @@ -0,0 +1,83 @@ +/** @file ListOps.hpp + * + * @author Roland Conybeare, Jan 2026 + **/ + +#pragma once + +#include "List.hpp" + +namespace xo { + namespace scm { + /** @brief list functions + * + * note: separate from DList, to avoid problems with deps needed + * to compile functions that return obj + **/ + struct ListOps { + using AGCObject = xo::mm::AGCObject; + using AAllocator = xo::mm::AAllocator; + + template + static obj nil(); + + /** shortcut for + * cons(mm, cdr, cdr.data()) + **/ + template + static obj cons(obj mm, + obj car, + obj cdr); + + /** list with one element @p e1, allocated from @p mm **/ + template + static obj list(obj mm, + obj e1); + + /** list with two element @p e1, @p e2, allocated from @p mm **/ + template + static obj list(obj mm, + obj e1, + obj e2); + + }; + + template + obj + ListOps::nil() + { + return obj(DList::_nil()); + } + + template + obj + ListOps::cons(obj mm, + obj car, + obj cdr) + { + return obj(DList::_cons(mm, car, cdr.data())); + } + + template + obj + ListOps::list(obj mm, + obj e1) + { + // clang 15 doesn't like nil() here. + + return cons(mm, e1, nil()); + } + + template + obj + ListOps::list(obj mm, + obj e1, + obj e2) + { + return cons(mm, e1, list(mm, e2)); + } + + } /*namespace scm*/ +} /*namespace xo*/ + +/* end ListOps.hpp */ diff --git a/xo-object2/include/xo/object2/RuntimeError.hpp b/xo-object2/include/xo/object2/RuntimeError.hpp new file mode 100644 index 00000000..c2a5f65d --- /dev/null +++ b/xo-object2/include/xo/object2/RuntimeError.hpp @@ -0,0 +1,12 @@ +/** @file RuntimeError.hpp + * + * @author Roland Conybeare, Feb 2026 + **/ + +#pragma once + +#include "DRuntimeError.hpp" +#include "error/IGCObject_DRuntimeError.hpp" +#include "error/IPrintable_DRuntimeError.hpp" + +/* end RuntimeError.hpp */ diff --git a/xo-object2/include/xo/object2/Sequence.hpp b/xo-object2/include/xo/object2/Sequence.hpp new file mode 100644 index 00000000..0478fa8b --- /dev/null +++ b/xo-object2/include/xo/object2/Sequence.hpp @@ -0,0 +1,22 @@ +/** @file Sequence.hpp + * + * Generated automagically from ingredients: + * 1. code generator: + * [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 */ diff --git a/xo-object2/include/xo/object2/SetupObject2.hpp b/xo-object2/include/xo/object2/SetupObject2.hpp new file mode 100644 index 00000000..7e6e3453 --- /dev/null +++ b/xo-object2/include/xo/object2/SetupObject2.hpp @@ -0,0 +1,23 @@ +/** @file SetupObject2.hpp + * + * @author Roland Conybeare, Jan 2026 + **/ + +#pragma once + +#include + +namespace xo { + namespace scm { + struct SetupObject2 { + public: + using ACollector = xo::mm::ACollector; + + public: + static bool register_facets(); + static bool register_types(obj gc); + }; + } +} + +/* end object2_register_facets.hpp */ diff --git a/xo-object2/include/xo/object2/array/IGCObject_DArray.hpp b/xo-object2/include/xo/object2/array/IGCObject_DArray.hpp new file mode 100644 index 00000000..31ab5742 --- /dev/null +++ b/xo-object2/include/xo/object2/array/IGCObject_DArray.hpp @@ -0,0 +1,67 @@ +/** @file IGCObject_DArray.hpp + * + * Generated automagically from ingredients: + * 1. code generator: + * [xo-facet/codegen/genfacet] + * arguments: + * --input [idl/IGCObject_DArray.json5] + * 2. jinja2 template for abstract facet .hpp file: + * [iface_facet_repr.hpp.j2] + * 3. idl for facet methods + * [idl/IGCObject_DArray.json5] + **/ + +#pragma once + +#include "GCObject.hpp" +#include "DArray.hpp" + +namespace xo { namespace scm { class IGCObject_DArray; } } + +namespace xo { + namespace facet { + template <> + struct FacetImplementation + { + using ImplType = xo::mm::IGCObject_Xfer + ; + }; + } +} + +namespace xo { + namespace scm { + /** @class IGCObject_DArray + **/ + class IGCObject_DArray { + public: + /** @defgroup scm-gcobject-darray-type-traits **/ + ///@{ + using size_type = xo::mm::AGCObject::size_type; + using AAllocator = xo::mm::AGCObject::AAllocator; + using AGCObjectVisitor = xo::mm::AGCObject::AGCObjectVisitor; + using VisitReason = xo::mm::AGCObject::VisitReason; + using Copaque = xo::mm::AGCObject::Copaque; + using Opaque = xo::mm::AGCObject::Opaque; + ///@} + /** @defgroup scm-gcobject-darray-methods **/ + ///@{ + // const methods + + // non-const methods + /** move instance using object visitor. +Arguably abusing the word 'visitor' here **/ + static Opaque gco_shallow_move(DArray & self, obj gc) noexcept; + /** Invoke fn.visit_child(iface,data) for each child GCObject pointer. +Context: provides address of data pointer so it can be updated in place +when @p fn invokes garbage collector reentry point **/ + static void visit_gco_children(DArray & self, VisitReason reason, obj fn) noexcept; + ///@} + }; + + } /*namespace scm*/ +} /*namespace xo*/ + +/* end */ \ No newline at end of file diff --git a/xo-object2/include/xo/object2/array/IPrintable_DArray.hpp b/xo-object2/include/xo/object2/array/IPrintable_DArray.hpp new file mode 100644 index 00000000..890cbab5 --- /dev/null +++ b/xo-object2/include/xo/object2/array/IPrintable_DArray.hpp @@ -0,0 +1,62 @@ +/** @file IPrintable_DArray.hpp + * + * Generated automagically from ingredients: + * 1. code generator: + * [xo-facet/codegen/genfacet] + * arguments: + * --input [idl/IPrintable_DArray.json5] + * 2. jinja2 template for abstract facet .hpp file: + * [iface_facet_repr.hpp.j2] + * 3. idl for facet methods + * [idl/IPrintable_DArray.json5] + **/ + +#pragma once + +#include "Printable.hpp" +#include +#include +#include "DArray.hpp" + +namespace xo { namespace scm { class IPrintable_DArray; } } + +namespace xo { + namespace facet { + template <> + struct FacetImplementation + { + using ImplType = xo::print::IPrintable_Xfer + ; + }; + } +} + +namespace xo { + namespace scm { + /** @class IPrintable_DArray + **/ + class IPrintable_DArray { + public: + /** @defgroup scm-printable-darray-type-traits **/ + ///@{ + using ppindentinfo = xo::print::APrintable::ppindentinfo; + using Copaque = xo::print::APrintable::Copaque; + using Opaque = xo::print::APrintable::Opaque; + ///@} + /** @defgroup scm-printable-darray-methods **/ + ///@{ + // const methods + /** Pretty-printing support for this object. +See [xo-indentlog/xo/indentlog/pretty.hpp] **/ + static bool pretty(const DArray & self, const ppindentinfo & ppii); + + // non-const methods + ///@} + }; + + } /*namespace scm*/ +} /*namespace xo*/ + +/* end */ \ No newline at end of file diff --git a/xo-object2/include/xo/object2/array/ISequence_DArray.hpp b/xo-object2/include/xo/object2/array/ISequence_DArray.hpp new file mode 100644 index 00000000..3b756b94 --- /dev/null +++ b/xo-object2/include/xo/object2/array/ISequence_DArray.hpp @@ -0,0 +1,64 @@ +/** @file ISequence_DArray.hpp + * + * Generated automagically from ingredients: + * 1. code generator: + * [xo-facet/codegen/genfacet] + * arguments: + * --input [idl/ISequence_DArray.json5] + * 2. jinja2 template for abstract facet .hpp file: + * [iface_facet_repr.hpp.j2] + * 3. idl for facet methods + * [idl/ISequence_DArray.json5] + **/ + +#pragma once + +#include "Sequence.hpp" +#include "DArray.hpp" + +namespace xo { namespace scm { class ISequence_DArray; } } + +namespace xo { + namespace facet { + template <> + struct FacetImplementation + { + using ImplType = xo::scm::ISequence_Xfer + ; + }; + } +} + +namespace xo { + namespace scm { + /** @class ISequence_DArray + **/ + class ISequence_DArray { + public: + /** @defgroup scm-sequence-darray-type-traits **/ + ///@{ + using size_type = xo::scm::ASequence::size_type; + using AGCObject = xo::scm::ASequence::AGCObject; + using Copaque = xo::scm::ASequence::Copaque; + using Opaque = xo::scm::ASequence::Opaque; + ///@} + /** @defgroup scm-sequence-darray-methods **/ + ///@{ + // const methods + /** true iff sequence is empty **/ + static bool is_empty(const DArray & self) noexcept; + /** true iff sequence is finite **/ + static bool is_finite(const DArray & self) noexcept; + /** return element @p index of this sequence **/ + static obj at(const DArray & self, size_type index); + + // non-const methods + ///@} + }; + + } /*namespace scm*/ +} /*namespace xo*/ + +/* end */ \ No newline at end of file diff --git a/xo-object2/include/xo/object2/boolean/IGCObject_DBoolean.hpp b/xo-object2/include/xo/object2/boolean/IGCObject_DBoolean.hpp new file mode 100644 index 00000000..a3cff7ca --- /dev/null +++ b/xo-object2/include/xo/object2/boolean/IGCObject_DBoolean.hpp @@ -0,0 +1,67 @@ +/** @file IGCObject_DBoolean.hpp + * + * Generated automagically from ingredients: + * 1. code generator: + * [xo-facet/codegen/genfacet] + * arguments: + * --input [idl/IGCObject_DBoolean.json5] + * 2. jinja2 template for abstract facet .hpp file: + * [iface_facet_repr.hpp.j2] + * 3. idl for facet methods + * [idl/IGCObject_DBoolean.json5] + **/ + +#pragma once + +#include "GCObject.hpp" +#include "DBoolean.hpp" + +namespace xo { namespace scm { class IGCObject_DBoolean; } } + +namespace xo { + namespace facet { + template <> + struct FacetImplementation + { + using ImplType = xo::mm::IGCObject_Xfer + ; + }; + } +} + +namespace xo { + namespace scm { + /** @class IGCObject_DBoolean + **/ + class IGCObject_DBoolean { + public: + /** @defgroup scm-gcobject-dboolean-type-traits **/ + ///@{ + using size_type = xo::mm::AGCObject::size_type; + using AAllocator = xo::mm::AGCObject::AAllocator; + using AGCObjectVisitor = xo::mm::AGCObject::AGCObjectVisitor; + using VisitReason = xo::mm::AGCObject::VisitReason; + using Copaque = xo::mm::AGCObject::Copaque; + using Opaque = xo::mm::AGCObject::Opaque; + ///@} + /** @defgroup scm-gcobject-dboolean-methods **/ + ///@{ + // const methods + + // non-const methods + /** move instance using object visitor. +Arguably abusing the word 'visitor' here **/ + static Opaque gco_shallow_move(DBoolean & self, obj gc) noexcept; + /** Invoke fn.visit_child(iface,data) for each child GCObject pointer. +Context: provides address of data pointer so it can be updated in place +when @p fn invokes garbage collector reentry point **/ + static void visit_gco_children(DBoolean & self, VisitReason reason, obj fn) noexcept; + ///@} + }; + + } /*namespace scm*/ +} /*namespace xo*/ + +/* end */ \ No newline at end of file diff --git a/xo-object2/include/xo/object2/boolean/IPrintable_DBoolean.hpp b/xo-object2/include/xo/object2/boolean/IPrintable_DBoolean.hpp new file mode 100644 index 00000000..b650c435 --- /dev/null +++ b/xo-object2/include/xo/object2/boolean/IPrintable_DBoolean.hpp @@ -0,0 +1,62 @@ +/** @file IPrintable_DBoolean.hpp + * + * Generated automagically from ingredients: + * 1. code generator: + * [xo-facet/codegen/genfacet] + * arguments: + * --input [idl/IPrintable_DBoolean.json5] + * 2. jinja2 template for abstract facet .hpp file: + * [iface_facet_repr.hpp.j2] + * 3. idl for facet methods + * [idl/IPrintable_DBoolean.json5] + **/ + +#pragma once + +#include "Printable.hpp" +#include +#include +#include "DBoolean.hpp" + +namespace xo { namespace scm { class IPrintable_DBoolean; } } + +namespace xo { + namespace facet { + template <> + struct FacetImplementation + { + using ImplType = xo::print::IPrintable_Xfer + ; + }; + } +} + +namespace xo { + namespace scm { + /** @class IPrintable_DBoolean + **/ + class IPrintable_DBoolean { + public: + /** @defgroup scm-printable-dboolean-type-traits **/ + ///@{ + using ppindentinfo = xo::print::APrintable::ppindentinfo; + using Copaque = xo::print::APrintable::Copaque; + using Opaque = xo::print::APrintable::Opaque; + ///@} + /** @defgroup scm-printable-dboolean-methods **/ + ///@{ + // const methods + /** Pretty-printing support for this object. +See [xo-indentlog/xo/indentlog/pretty.hpp] **/ + static bool pretty(const DBoolean & self, const ppindentinfo & ppii); + + // non-const methods + ///@} + }; + + } /*namespace scm*/ +} /*namespace xo*/ + +/* end */ \ No newline at end of file diff --git a/xo-object2/include/xo/object2/dictionary/IGCObject_DDictionary.hpp b/xo-object2/include/xo/object2/dictionary/IGCObject_DDictionary.hpp new file mode 100644 index 00000000..acaffdf4 --- /dev/null +++ b/xo-object2/include/xo/object2/dictionary/IGCObject_DDictionary.hpp @@ -0,0 +1,67 @@ +/** @file IGCObject_DDictionary.hpp + * + * Generated automagically from ingredients: + * 1. code generator: + * [xo-facet/codegen/genfacet] + * arguments: + * --input [idl/IGCObject_DDictionary.json5] + * 2. jinja2 template for abstract facet .hpp file: + * [iface_facet_repr.hpp.j2] + * 3. idl for facet methods + * [idl/IGCObject_DDictionary.json5] + **/ + +#pragma once + +#include "GCObject.hpp" +#include "DDictionary.hpp" + +namespace xo { namespace scm { class IGCObject_DDictionary; } } + +namespace xo { + namespace facet { + template <> + struct FacetImplementation + { + using ImplType = xo::mm::IGCObject_Xfer + ; + }; + } +} + +namespace xo { + namespace scm { + /** @class IGCObject_DDictionary + **/ + class IGCObject_DDictionary { + public: + /** @defgroup scm-gcobject-ddictionary-type-traits **/ + ///@{ + using size_type = xo::mm::AGCObject::size_type; + using AAllocator = xo::mm::AGCObject::AAllocator; + using AGCObjectVisitor = xo::mm::AGCObject::AGCObjectVisitor; + using VisitReason = xo::mm::AGCObject::VisitReason; + using Copaque = xo::mm::AGCObject::Copaque; + using Opaque = xo::mm::AGCObject::Opaque; + ///@} + /** @defgroup scm-gcobject-ddictionary-methods **/ + ///@{ + // const methods + + // non-const methods + /** move instance using object visitor. +Arguably abusing the word 'visitor' here **/ + static Opaque gco_shallow_move(DDictionary & self, obj gc) noexcept; + /** Invoke fn.visit_child(iface,data) for each child GCObject pointer. +Context: provides address of data pointer so it can be updated in place +when @p fn invokes garbage collector reentry point **/ + static void visit_gco_children(DDictionary & self, VisitReason reason, obj fn) noexcept; + ///@} + }; + + } /*namespace scm*/ +} /*namespace xo*/ + +/* end */ \ No newline at end of file diff --git a/xo-object2/include/xo/object2/dictionary/IPrintable_DDictionary.hpp b/xo-object2/include/xo/object2/dictionary/IPrintable_DDictionary.hpp new file mode 100644 index 00000000..abd79d7b --- /dev/null +++ b/xo-object2/include/xo/object2/dictionary/IPrintable_DDictionary.hpp @@ -0,0 +1,62 @@ +/** @file IPrintable_DDictionary.hpp + * + * Generated automagically from ingredients: + * 1. code generator: + * [xo-facet/codegen/genfacet] + * arguments: + * --input [idl/IPrintable_DDictionary.json5] + * 2. jinja2 template for abstract facet .hpp file: + * [iface_facet_repr.hpp.j2] + * 3. idl for facet methods + * [idl/IPrintable_DDictionary.json5] + **/ + +#pragma once + +#include "Printable.hpp" +#include +#include +#include "DDictionary.hpp" + +namespace xo { namespace scm { class IPrintable_DDictionary; } } + +namespace xo { + namespace facet { + template <> + struct FacetImplementation + { + using ImplType = xo::print::IPrintable_Xfer + ; + }; + } +} + +namespace xo { + namespace scm { + /** @class IPrintable_DDictionary + **/ + class IPrintable_DDictionary { + public: + /** @defgroup scm-printable-ddictionary-type-traits **/ + ///@{ + using ppindentinfo = xo::print::APrintable::ppindentinfo; + using Copaque = xo::print::APrintable::Copaque; + using Opaque = xo::print::APrintable::Opaque; + ///@} + /** @defgroup scm-printable-ddictionary-methods **/ + ///@{ + // const methods + /** Pretty-printing support for this object. +See [xo-indentlog/xo/indentlog/pretty.hpp] **/ + static bool pretty(const DDictionary & self, const ppindentinfo & ppii); + + // non-const methods + ///@} + }; + + } /*namespace scm*/ +} /*namespace xo*/ + +/* end */ \ No newline at end of file diff --git a/xo-object2/include/xo/object2/error/IGCObject_DRuntimeError.hpp b/xo-object2/include/xo/object2/error/IGCObject_DRuntimeError.hpp new file mode 100644 index 00000000..7f31367c --- /dev/null +++ b/xo-object2/include/xo/object2/error/IGCObject_DRuntimeError.hpp @@ -0,0 +1,67 @@ +/** @file IGCObject_DRuntimeError.hpp + * + * Generated automagically from ingredients: + * 1. code generator: + * [xo-facet/codegen/genfacet] + * arguments: + * --input [idl/IGCObject_DRuntimeError.json5] + * 2. jinja2 template for abstract facet .hpp file: + * [iface_facet_repr.hpp.j2] + * 3. idl for facet methods + * [idl/IGCObject_DRuntimeError.json5] + **/ + +#pragma once + +#include "GCObject.hpp" +#include "DRuntimeError.hpp" + +namespace xo { namespace scm { class IGCObject_DRuntimeError; } } + +namespace xo { + namespace facet { + template <> + struct FacetImplementation + { + using ImplType = xo::mm::IGCObject_Xfer + ; + }; + } +} + +namespace xo { + namespace scm { + /** @class IGCObject_DRuntimeError + **/ + class IGCObject_DRuntimeError { + public: + /** @defgroup scm-gcobject-druntimeerror-type-traits **/ + ///@{ + using size_type = xo::mm::AGCObject::size_type; + using AAllocator = xo::mm::AGCObject::AAllocator; + using AGCObjectVisitor = xo::mm::AGCObject::AGCObjectVisitor; + using VisitReason = xo::mm::AGCObject::VisitReason; + using Copaque = xo::mm::AGCObject::Copaque; + using Opaque = xo::mm::AGCObject::Opaque; + ///@} + /** @defgroup scm-gcobject-druntimeerror-methods **/ + ///@{ + // const methods + + // non-const methods + /** move instance using object visitor. +Arguably abusing the word 'visitor' here **/ + static Opaque gco_shallow_move(DRuntimeError & self, obj gc) noexcept; + /** Invoke fn.visit_child(iface,data) for each child GCObject pointer. +Context: provides address of data pointer so it can be updated in place +when @p fn invokes garbage collector reentry point **/ + static void visit_gco_children(DRuntimeError & self, VisitReason reason, obj fn) noexcept; + ///@} + }; + + } /*namespace scm*/ +} /*namespace xo*/ + +/* end */ \ No newline at end of file diff --git a/xo-object2/include/xo/object2/error/IPrintable_DRuntimeError.hpp b/xo-object2/include/xo/object2/error/IPrintable_DRuntimeError.hpp new file mode 100644 index 00000000..8b5a4d17 --- /dev/null +++ b/xo-object2/include/xo/object2/error/IPrintable_DRuntimeError.hpp @@ -0,0 +1,62 @@ +/** @file IPrintable_DRuntimeError.hpp + * + * Generated automagically from ingredients: + * 1. code generator: + * [xo-facet/codegen/genfacet] + * arguments: + * --input [idl/IPrintable_DRuntimeError.json5] + * 2. jinja2 template for abstract facet .hpp file: + * [iface_facet_repr.hpp.j2] + * 3. idl for facet methods + * [idl/IPrintable_DRuntimeError.json5] + **/ + +#pragma once + +#include "Printable.hpp" +#include +#include +#include "DRuntimeError.hpp" + +namespace xo { namespace scm { class IPrintable_DRuntimeError; } } + +namespace xo { + namespace facet { + template <> + struct FacetImplementation + { + using ImplType = xo::print::IPrintable_Xfer + ; + }; + } +} + +namespace xo { + namespace scm { + /** @class IPrintable_DRuntimeError + **/ + class IPrintable_DRuntimeError { + public: + /** @defgroup scm-printable-druntimeerror-type-traits **/ + ///@{ + using ppindentinfo = xo::print::APrintable::ppindentinfo; + using Copaque = xo::print::APrintable::Copaque; + using Opaque = xo::print::APrintable::Opaque; + ///@} + /** @defgroup scm-printable-druntimeerror-methods **/ + ///@{ + // const methods + /** Pretty-printing support for this object. +See [xo-indentlog/xo/indentlog/pretty.hpp] **/ + static bool pretty(const DRuntimeError & self, const ppindentinfo & ppii); + + // non-const methods + ///@} + }; + + } /*namespace scm*/ +} /*namespace xo*/ + +/* end */ \ No newline at end of file diff --git a/xo-object2/include/xo/object2/init_object2.hpp b/xo-object2/include/xo/object2/init_object2.hpp new file mode 100644 index 00000000..aa3dd510 --- /dev/null +++ b/xo-object2/include/xo/object2/init_object2.hpp @@ -0,0 +1,21 @@ +/** @file init_object2.hpp + * + * @author Roland Conybeare, Jan 2026 + **/ + +#pragma once + +#include + +namespace xo { + /* tag to represent the xo-expression2/ subsystem within ordered initialization */ + enum S_object2_tag {}; + + template <> + struct InitSubsys { + static void init(); + static InitEvidence require(); + }; +} /*namespace xo*/ + +/* end init_object2.hpp */ diff --git a/xo-object2/include/xo/object2/list/IGCObject_DList.hpp b/xo-object2/include/xo/object2/list/IGCObject_DList.hpp new file mode 100644 index 00000000..94de87d4 --- /dev/null +++ b/xo-object2/include/xo/object2/list/IGCObject_DList.hpp @@ -0,0 +1,67 @@ +/** @file IGCObject_DList.hpp + * + * Generated automagically from ingredients: + * 1. code generator: + * [xo-facet/codegen/genfacet] + * arguments: + * --input [idl/IGCObject_DList.json5] + * 2. jinja2 template for abstract facet .hpp file: + * [iface_facet_repr.hpp.j2] + * 3. idl for facet methods + * [idl/IGCObject_DList.json5] + **/ + +#pragma once + +#include "GCObject.hpp" +#include "DList.hpp" + +namespace xo { namespace scm { class IGCObject_DList; } } + +namespace xo { + namespace facet { + template <> + struct FacetImplementation + { + using ImplType = xo::mm::IGCObject_Xfer + ; + }; + } +} + +namespace xo { + namespace scm { + /** @class IGCObject_DList + **/ + class IGCObject_DList { + public: + /** @defgroup scm-gcobject-dlist-type-traits **/ + ///@{ + using size_type = xo::mm::AGCObject::size_type; + using AAllocator = xo::mm::AGCObject::AAllocator; + using AGCObjectVisitor = xo::mm::AGCObject::AGCObjectVisitor; + using VisitReason = xo::mm::AGCObject::VisitReason; + using Copaque = xo::mm::AGCObject::Copaque; + using Opaque = xo::mm::AGCObject::Opaque; + ///@} + /** @defgroup scm-gcobject-dlist-methods **/ + ///@{ + // const methods + + // non-const methods + /** move instance using object visitor. +Arguably abusing the word 'visitor' here **/ + static Opaque gco_shallow_move(DList & self, obj gc) noexcept; + /** Invoke fn.visit_child(iface,data) for each child GCObject pointer. +Context: provides address of data pointer so it can be updated in place +when @p fn invokes garbage collector reentry point **/ + static void visit_gco_children(DList & self, VisitReason reason, obj fn) noexcept; + ///@} + }; + + } /*namespace scm*/ +} /*namespace xo*/ + +/* end */ \ No newline at end of file diff --git a/xo-object2/include/xo/object2/list/IPrintable_DList.hpp b/xo-object2/include/xo/object2/list/IPrintable_DList.hpp new file mode 100644 index 00000000..77e7b1d3 --- /dev/null +++ b/xo-object2/include/xo/object2/list/IPrintable_DList.hpp @@ -0,0 +1,62 @@ +/** @file IPrintable_DList.hpp + * + * Generated automagically from ingredients: + * 1. code generator: + * [xo-facet/codegen/genfacet] + * arguments: + * --input [idl/IPrintable_DList.json5] + * 2. jinja2 template for abstract facet .hpp file: + * [iface_facet_repr.hpp.j2] + * 3. idl for facet methods + * [idl/IPrintable_DList.json5] + **/ + +#pragma once + +#include "Printable.hpp" +#include +#include +#include "DList.hpp" + +namespace xo { namespace scm { class IPrintable_DList; } } + +namespace xo { + namespace facet { + template <> + struct FacetImplementation + { + using ImplType = xo::print::IPrintable_Xfer + ; + }; + } +} + +namespace xo { + namespace scm { + /** @class IPrintable_DList + **/ + class IPrintable_DList { + public: + /** @defgroup scm-printable-dlist-type-traits **/ + ///@{ + using ppindentinfo = xo::print::APrintable::ppindentinfo; + using Copaque = xo::print::APrintable::Copaque; + using Opaque = xo::print::APrintable::Opaque; + ///@} + /** @defgroup scm-printable-dlist-methods **/ + ///@{ + // const methods + /** Pretty-printing support for this object. +See [xo-indentlog/xo/indentlog/pretty.hpp] **/ + static bool pretty(const DList & self, const ppindentinfo & ppii); + + // non-const methods + ///@} + }; + + } /*namespace scm*/ +} /*namespace xo*/ + +/* end */ \ No newline at end of file diff --git a/xo-object2/include/xo/object2/list/ISequence_DList.hpp b/xo-object2/include/xo/object2/list/ISequence_DList.hpp new file mode 100644 index 00000000..ac468764 --- /dev/null +++ b/xo-object2/include/xo/object2/list/ISequence_DList.hpp @@ -0,0 +1,65 @@ +/** @file ISequence_DList.hpp + * + * Generated automagically from ingredients: + * 1. code generator: + * [xo-facet/codegen/genfacet] + * arguments: + * --input [idl/ISequence_DList.json5] + * 2. jinja2 template for abstract facet .hpp file: + * [iface_facet_repr.hpp.j2] + * 3. idl for facet methods + * [idl/ISequence_DList.json5] + **/ + +#pragma once + +#include "Sequence.hpp" +#include +#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 = xo::scm::ASequence::size_type; + using AGCObject = xo::scm::ASequence::AGCObject; + using Copaque = xo::scm::ASequence::Copaque; + using Opaque = xo::scm::ASequence::Opaque; + ///@} + /** @defgroup scm-sequence-dlist-methods **/ + ///@{ + // const 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); + + // non-const methods + ///@} + }; + + } /*namespace scm*/ +} /*namespace xo*/ + +/* end */ \ No newline at end of file diff --git a/xo-object2/include/xo/object2/number/GCObjectConversion_DFloat.hpp b/xo-object2/include/xo/object2/number/GCObjectConversion_DFloat.hpp new file mode 100644 index 00000000..4cc47517 --- /dev/null +++ b/xo-object2/include/xo/object2/number/GCObjectConversion_DFloat.hpp @@ -0,0 +1,29 @@ +/** @file GCObjectConversion_DFloat.hpp + * + * @author Roland Conybeare, Jan 2026 + **/ + +#pragma once + +#include "DFloat.hpp" +#include "number/IGCObject_DFloat.hpp" +#include + +namespace xo { + namespace scm { + + template <> + struct GCObjectConversion { + static_assert(std::is_same_v); + + using AGCObject = xo::mm::AGCObject; + using AAllocator = xo::mm::AAllocator; + + static obj to_gco(obj mm, double x); + static double from_gco(obj mm, obj gco); + }; + + } /*namespace scm*/ +} /*namespace xo*/ + +/* end GCObjectConversion_DFloat.hpp */ diff --git a/xo-object2/include/xo/object2/number/GCObjectConversion_DInteger.hpp b/xo-object2/include/xo/object2/number/GCObjectConversion_DInteger.hpp new file mode 100644 index 00000000..5b01e571 --- /dev/null +++ b/xo-object2/include/xo/object2/number/GCObjectConversion_DInteger.hpp @@ -0,0 +1,29 @@ +/** @file GCObjectConversion_DInteger.hpp + * + * @author Roland Conybeare, Jan 2026 + **/ + +#pragma once + +#include "DInteger.hpp" +#include "number/IGCObject_DInteger.hpp" +#include + +namespace xo { + namespace scm { + + template <> + struct GCObjectConversion { + static_assert(std::is_same_v); + + using AGCObject = xo::mm::AGCObject; + using AAllocator = xo::mm::AAllocator; + + static obj to_gco(obj mm, long x); + static long from_gco(obj mm, obj gco); + }; + + } +} /*namespace xo*/ + +/* end GCObjectConversion_DInteger.hpp */ diff --git a/xo-object2/include/xo/object2/number/IGCObject_DFloat.hpp b/xo-object2/include/xo/object2/number/IGCObject_DFloat.hpp new file mode 100644 index 00000000..9383014f --- /dev/null +++ b/xo-object2/include/xo/object2/number/IGCObject_DFloat.hpp @@ -0,0 +1,68 @@ +/** @file IGCObject_DFloat.hpp + * + * Generated automagically from ingredients: + * 1. code generator: + * [xo-facet/codegen/genfacet] + * arguments: + * --input [idl/IGCObject_DFloat.json5] + * 2. jinja2 template for abstract facet .hpp file: + * [iface_facet_repr.hpp.j2] + * 3. idl for facet methods + * [idl/IGCObject_DFloat.json5] + **/ + +#pragma once + +#include "GCObject.hpp" +#include +#include "DFloat.hpp" + +namespace xo { namespace scm { class IGCObject_DFloat; } } + +namespace xo { + namespace facet { + template <> + struct FacetImplementation + { + using ImplType = xo::mm::IGCObject_Xfer + ; + }; + } +} + +namespace xo { + namespace scm { + /** @class IGCObject_DFloat + **/ + class IGCObject_DFloat { + public: + /** @defgroup scm-gcobject-dfloat-type-traits **/ + ///@{ + using size_type = xo::mm::AGCObject::size_type; + using AAllocator = xo::mm::AGCObject::AAllocator; + using AGCObjectVisitor = xo::mm::AGCObject::AGCObjectVisitor; + using VisitReason = xo::mm::AGCObject::VisitReason; + using Copaque = xo::mm::AGCObject::Copaque; + using Opaque = xo::mm::AGCObject::Opaque; + ///@} + /** @defgroup scm-gcobject-dfloat-methods **/ + ///@{ + // const methods + + // non-const methods + /** move instance using object visitor. +Arguably abusing the word 'visitor' here **/ + static Opaque gco_shallow_move(DFloat & self, obj gc) noexcept; + /** Invoke fn.visit_child(iface,data) for each child GCObject pointer. +Context: provides address of data pointer so it can be updated in place +when @p fn invokes garbage collector reentry point **/ + static void visit_gco_children(DFloat & self, VisitReason reason, obj fn) noexcept; + ///@} + }; + + } /*namespace scm*/ +} /*namespace xo*/ + +/* end */ \ No newline at end of file diff --git a/xo-object2/include/xo/object2/number/IGCObject_DInteger.hpp b/xo-object2/include/xo/object2/number/IGCObject_DInteger.hpp new file mode 100644 index 00000000..b116532f --- /dev/null +++ b/xo-object2/include/xo/object2/number/IGCObject_DInteger.hpp @@ -0,0 +1,67 @@ +/** @file IGCObject_DInteger.hpp + * + * Generated automagically from ingredients: + * 1. code generator: + * [xo-facet/codegen/genfacet] + * arguments: + * --input [idl/IGCObject_DInteger.json5] + * 2. jinja2 template for abstract facet .hpp file: + * [iface_facet_repr.hpp.j2] + * 3. idl for facet methods + * [idl/IGCObject_DInteger.json5] + **/ + +#pragma once + +#include "GCObject.hpp" +#include "DInteger.hpp" + +namespace xo { namespace scm { class IGCObject_DInteger; } } + +namespace xo { + namespace facet { + template <> + struct FacetImplementation + { + using ImplType = xo::mm::IGCObject_Xfer + ; + }; + } +} + +namespace xo { + namespace scm { + /** @class IGCObject_DInteger + **/ + class IGCObject_DInteger { + public: + /** @defgroup scm-gcobject-dinteger-type-traits **/ + ///@{ + using size_type = xo::mm::AGCObject::size_type; + using AAllocator = xo::mm::AGCObject::AAllocator; + using AGCObjectVisitor = xo::mm::AGCObject::AGCObjectVisitor; + using VisitReason = xo::mm::AGCObject::VisitReason; + using Copaque = xo::mm::AGCObject::Copaque; + using Opaque = xo::mm::AGCObject::Opaque; + ///@} + /** @defgroup scm-gcobject-dinteger-methods **/ + ///@{ + // const methods + + // non-const methods + /** move instance using object visitor. +Arguably abusing the word 'visitor' here **/ + static Opaque gco_shallow_move(DInteger & self, obj gc) noexcept; + /** Invoke fn.visit_child(iface,data) for each child GCObject pointer. +Context: provides address of data pointer so it can be updated in place +when @p fn invokes garbage collector reentry point **/ + static void visit_gco_children(DInteger & self, VisitReason reason, obj fn) noexcept; + ///@} + }; + + } /*namespace scm*/ +} /*namespace xo*/ + +/* end */ \ No newline at end of file diff --git a/xo-object2/include/xo/object2/number/IPrintable_DFloat.hpp b/xo-object2/include/xo/object2/number/IPrintable_DFloat.hpp new file mode 100644 index 00000000..9506055a --- /dev/null +++ b/xo-object2/include/xo/object2/number/IPrintable_DFloat.hpp @@ -0,0 +1,62 @@ +/** @file IPrintable_DFloat.hpp + * + * Generated automagically from ingredients: + * 1. code generator: + * [xo-facet/codegen/genfacet] + * arguments: + * --input [idl/IPrintable_DFloat.json5] + * 2. jinja2 template for abstract facet .hpp file: + * [iface_facet_repr.hpp.j2] + * 3. idl for facet methods + * [idl/IPrintable_DFloat.json5] + **/ + +#pragma once + +#include "Printable.hpp" +#include +#include +#include "DFloat.hpp" + +namespace xo { namespace scm { class IPrintable_DFloat; } } + +namespace xo { + namespace facet { + template <> + struct FacetImplementation + { + using ImplType = xo::print::IPrintable_Xfer + ; + }; + } +} + +namespace xo { + namespace scm { + /** @class IPrintable_DFloat + **/ + class IPrintable_DFloat { + public: + /** @defgroup scm-printable-dfloat-type-traits **/ + ///@{ + using ppindentinfo = xo::print::APrintable::ppindentinfo; + using Copaque = xo::print::APrintable::Copaque; + using Opaque = xo::print::APrintable::Opaque; + ///@} + /** @defgroup scm-printable-dfloat-methods **/ + ///@{ + // const methods + /** Pretty-printing support for this object. +See [xo-indentlog/xo/indentlog/pretty.hpp] **/ + static bool pretty(const DFloat & self, const ppindentinfo & ppii); + + // non-const methods + ///@} + }; + + } /*namespace scm*/ +} /*namespace xo*/ + +/* end */ \ No newline at end of file diff --git a/xo-object2/include/xo/object2/number/IPrintable_DInteger.hpp b/xo-object2/include/xo/object2/number/IPrintable_DInteger.hpp new file mode 100644 index 00000000..1b5df6c4 --- /dev/null +++ b/xo-object2/include/xo/object2/number/IPrintable_DInteger.hpp @@ -0,0 +1,62 @@ +/** @file IPrintable_DInteger.hpp + * + * Generated automagically from ingredients: + * 1. code generator: + * [xo-facet/codegen/genfacet] + * arguments: + * --input [idl/IPrintable_DInteger.json5] + * 2. jinja2 template for abstract facet .hpp file: + * [iface_facet_repr.hpp.j2] + * 3. idl for facet methods + * [idl/IPrintable_DInteger.json5] + **/ + +#pragma once + +#include "Printable.hpp" +#include +#include +#include "DInteger.hpp" + +namespace xo { namespace scm { class IPrintable_DInteger; } } + +namespace xo { + namespace facet { + template <> + struct FacetImplementation + { + using ImplType = xo::print::IPrintable_Xfer + ; + }; + } +} + +namespace xo { + namespace scm { + /** @class IPrintable_DInteger + **/ + class IPrintable_DInteger { + public: + /** @defgroup scm-printable-dinteger-type-traits **/ + ///@{ + using ppindentinfo = xo::print::APrintable::ppindentinfo; + using Copaque = xo::print::APrintable::Copaque; + using Opaque = xo::print::APrintable::Opaque; + ///@} + /** @defgroup scm-printable-dinteger-methods **/ + ///@{ + // const methods + /** Pretty-printing support for this object. +See [xo-indentlog/xo/indentlog/pretty.hpp] **/ + static bool pretty(const DInteger & self, const ppindentinfo & ppii); + + // non-const methods + ///@} + }; + + } /*namespace scm*/ +} /*namespace xo*/ + +/* end */ \ 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..fcb272bc --- /dev/null +++ b/xo-object2/include/xo/object2/sequence/ASequence.hpp @@ -0,0 +1,88 @@ +/** @file ASequence.hpp + * + * Generated automagically from ingredients: + * 1. code generator: + * [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 + +// {pretext} here + +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 + /** integer identifying a type **/ + using typeseq = xo::facet::typeseq; + using Copaque = const void *; + using Opaque = void *; + /** 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 + /** An uninitialized ASequence instance will have zero vtable pointer (per {linux,osx} abi). + * Use case for this is narrow. We go to some lengths to avoid null vtable pointers. For example + * obj will have non-null vtable (via IFacet_Any) with all methods terminating. + **/ + bool _has_null_vptr() const noexcept { return *reinterpret_cast(this) == nullptr; } + /** RTTI: unique id# for actual runtime data representation **/ + virtual typeseq _typeseq() const noexcept = 0; + /** destroy instance @p d; calls c++ dtor only for actual runtime type; does not recover memory **/ + virtual void _drop(Opaque d) 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*/ + +/* ASequence.hpp */ 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..e878f729 --- /dev/null +++ b/xo-object2/include/xo/object2/sequence/ISequence_Any.hpp @@ -0,0 +1,92 @@ +/** @file ISequence_Any.hpp + * + * Generated automagically from ingredients: + * 1. code generator: + * [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 **/ + ///@{ + + /** integer identifying a type **/ + using typeseq = xo::facet::typeseq; + 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 + + // builtin methods + typeseq _typeseq() const noexcept override { return s_typeseq; } + [[noreturn]] void _drop(Opaque) const noexcept override { _fatal(); } + + // const methods + [[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: + /** @defgroup scm-sequence-any-member-vars **/ + ///@{ + + static typeseq s_typeseq; + static bool _valid; + + ///@} + }; + +} /*namespace scm */ +} /*namespace xo */ + +/* ISequence_Any.hpp */ 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..a18ad124 --- /dev/null +++ b/xo-object2/include/xo/object2/sequence/ISequence_Xfer.hpp @@ -0,0 +1,99 @@ +/** @file ISequence_Xfer.hpp + * + * Generated automagically from ingredients: + * 1. code generator: + * [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] + * + * variables: + * {facet_hpp_fname} -> Sequence.hpp + * {impl_hpp_subdir} -> sequence + * {facet_ns1} -> xo + * {facet_detail_subdir} -> sequence + * {abstract_facet_fname} -> ASequence.hpp + **/ + +#pragma once + +#include "ASequence.hpp" +#include + +namespace xo { +namespace scm { + /** @class ISequence_Xfer + **/ + template + class ISequence_Xfer : public ASequence { + public: + /** @defgroup scm-sequence-xfer-type-traits **/ + ///@{ + /** actual implementation (not generated; often delegates to DRepr) **/ + using Impl = ISequence_DRepr; + /** integer identifying a type **/ + using typeseq = ASequence::typeseq; + 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 + + // builtin methods + typeseq _typeseq() const noexcept override { return s_typeseq; } + void _drop(Opaque d) const noexcept override { _dcast(d).~DRepr(); } + + // const methods + 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: + /** @defgroup scm-sequence-xfer-member-vars **/ + ///@{ + + /** typeseq for template parameter DRepr **/ + static typeseq s_typeseq; + /** true iff satisfies facet implementation **/ + static bool _valid; + + ///@} + }; + + template + xo::facet::typeseq + 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 */ 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..76f60059 --- /dev/null +++ b/xo-object2/include/xo/object2/sequence/RSequence.hpp @@ -0,0 +1,92 @@ +/** @file RSequence.hpp + * + * Generated automagically from ingredients: + * 1. code generator: + * [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 typeseq = xo::reflect::typeseq; + using size_type = ASequence::size_type; + using AGCObject = ASequence::AGCObject; + ///@} + + /** @defgroup scm-sequence-router-ctors **/ + ///@{ + RSequence() {} + RSequence(Object::DataPtr data) : Object{std::move(data)} {} + RSequence(const ASequence * iface, void * data) + requires std::is_same_v + : Object(iface, data) {} + + ///@} + /** @defgroup scm-sequence-router-methods **/ + ///@{ + + // explicit injected content + + // builtin methods + typeseq _typeseq() const noexcept { return O::iface()->_typeseq(); } + void _drop() const noexcept { O::iface()->_drop(O::data()); } + + // const methods + bool is_empty() const noexcept { + return O::iface()->is_empty(O::data()); + } + bool is_finite() const noexcept { + return O::iface()->is_finite(O::data()); + } + obj at(size_type index) const { + return O::iface()->at(O::data(), index); + } + + // non-const methods (still const in router!) + + ///@} + /** @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 */ diff --git a/xo-object2/src/object2/CMakeLists.txt b/xo-object2/src/object2/CMakeLists.txt new file mode 100644 index 00000000..77816186 --- /dev/null +++ b/xo-object2/src/object2/CMakeLists.txt @@ -0,0 +1,51 @@ +# object2/CMakeLists.txt + +set(SELF_LIB xo_object2) +set(SELF_SRCS + init_object2.cpp + SetupObject2.cpp + + GCObjectConversion_DFloat.cpp + GCObjectConversion_DInteger.cpp + + ISequence_Any.cpp + + DArray.cpp + ISequence_DArray.cpp + IGCObject_DArray.cpp + IPrintable_DArray.cpp + + DList.cpp + ISequence_DList.cpp + IGCObject_DList.cpp + IPrintable_DList.cpp + + DFloat.cpp + IGCObject_DFloat.cpp + IPrintable_DFloat.cpp + + DInteger.cpp + IGCObject_DInteger.cpp + IPrintable_DInteger.cpp + + DBoolean.cpp + IGCObject_DBoolean.cpp + IPrintable_DBoolean.cpp + + DDictionary.cpp + IGCObject_DDictionary.cpp + IPrintable_DDictionary.cpp + + DRuntimeError.cpp + IGCObject_DRuntimeError.cpp + IPrintable_DRuntimeError.cpp + ) + +xo_add_shared_library4(${SELF_LIB} ${PROJECT_NAME}Targets ${PROJECT_VERSION} 1 ${SELF_SRCS}) +# note: deps here must also appear in cmake/xo_object2Config.cmake.in +xo_dependency(${SELF_LIB} reflect) +xo_dependency(${SELF_LIB} xo_stringtable2) +xo_dependency(${SELF_LIB} xo_alloc2) +xo_dependency(${SELF_LIB} xo_printable2) +xo_dependency(${SELF_LIB} subsys) +xo_dependency(${SELF_LIB} indentlog) diff --git a/xo-object2/src/object2/DArray.cpp b/xo-object2/src/object2/DArray.cpp new file mode 100644 index 00000000..050f757d --- /dev/null +++ b/xo-object2/src/object2/DArray.cpp @@ -0,0 +1,235 @@ +/** @file DArray.cpp + * + * @author Roland Conybeare, Jan 2026 + **/ + +#include "DArray.hpp" +#include +#include +#include +#include +#include +#include + +namespace xo { + using xo::print::APrintable; + using xo::facet::FacetRegistry; + using xo::mm::AGCObject; + using xo::facet::typeseq; + + namespace scm { + // TODO: error reporting? + DArray * + DArray::_empty(obj mm, + size_type cap) + { + DArray * result = nullptr; + + void * mem = mm.alloc(typeseq::id(), + sizeof(DArray) + cap * sizeof(obj)); + + if (mem) [[likely]] { + result = new (mem) DArray(); + + assert(result); + + result->capacity_ = cap; + result->size_ = 0; + } + + return result; + } + + DArray * + DArray::copy(obj mm, + DArray * src, + size_type new_cap) + { + DArray * dest = _empty(mm, new_cap); + + if (dest) [[likely]] { + /** could just memcpy here **/ + for (size_type i = 0, n = src->size(); i < n; ++i) { + dest->elts_[i] = src->elts_[i]; + } + + dest->size_ = src->size(); + } + + return dest; + } + + obj + DArray::at(size_type ix) const + { + if (ix < size_) { + return elts_[ix]; + } else { + throw std::runtime_error(tostr("DArray::at: out-of-range index where [0..z) expected", + xtag("index", ix), + xtag("z", this->size()))); + return obj(); + } + } + + bool + DArray::assign_at(obj mm, size_type ix, obj x) noexcept + { + if (ix >= size_) + return false; + + mm.barrier_assign(this, &elts_[ix], x); + + return true; + } + + bool + DArray::push_back(obj mm, + obj elt) noexcept + { + if (size_ >= capacity_) { + return false; + } else { + static_assert(!std::is_trivially_constructible_v>); + + void * mem = &(elts_[size_]); + new (mem) obj(); + + mm.barrier_assign(this, &elts_[size_], elt); + + ++(this->size_); + + return true; + } + } + + bool + DArray::pop_back(obj * p_elt) noexcept + { + if (size_ > 0) { + --size_; + + obj & last = elts_[size_]; + + if (p_elt) + *p_elt = last; + + last.reset(); // hygiene + + return true; + } + + return false; + } + + bool + DArray::resize(size_type new_z) noexcept + { + if (new_z > capacity_) { + return false; + } else if (new_z > size_) { + // ensure new size is zeroed (we/re not zeroing if/when we shrink) + ::memset((std::byte *)(&elts_[size_]), 0, (std::byte *)(&elts_[new_z]) - (std::byte *)(&elts_[size_])); + } + + this->size_ = new_z; + return true; + } + + void + DArray::shrink_to_fit() noexcept + { + if (capacity_ > size_) { + this->capacity_ = size_; + } + } + + // printing support + + bool + DArray::pretty(const ppindentinfo & ppii) const + { + using xo::print::ppstate; + + ppstate * pps = ppii.pps(); + + if (ppii.upto()) { + /* perhaps print on one line */ + pps->write("["); + + for (size_t i = 0, n = this->size(); i < n; ++i ) { + if (i > 0) + pps->write(" "); + + obj elt + = FacetRegistry::instance().variant(this->at(i)); + + assert(elt.data()); + + if (!pps->print_upto(elt)) + return false; + } + + pps->write("]"); + return true; + } else { + pps->write("["); + + for (size_type i = 0, n = this->size(); i < n; ++i) { + if (i == 0) { + /* indent, but credit initial [ */ + pps->indent(std::max(pps->indent_width(), 1u) - 1); + } else { + /* indent after newline */ + pps->newline_indent(ppii.ci1()); + } + + obj elt = this->at(i).to_facet(); + + assert(elt.data()); + + pps->pretty(elt); + } + + pps->write("]"); + return false; + } + } + + // gc hooks for IGCObject_DArray + + DArray * + DArray::gco_shallow_move(obj gc) noexcept + { + // note: not using gc.std_move_for() here. + // flexible array -> compiler doesn't know actual DArray allocation size + + DArray * copy = (DArray *)gc.alloc_copy((std::byte *)this); + + if (copy) { + copy->capacity_ = capacity_; + copy->size_ = size_; + + constexpr auto c_obj_z = sizeof(obj); + + /* memcpy sufficient for obj */ + ::memcpy((void*)&(copy->elts_[0]), + (void*)&(elts_[0]), + capacity_ * c_obj_z); + } + + return copy; + } + + void + DArray::visit_gco_children(VisitReason reason, obj gc) noexcept + { + for (size_type i = 0; i < size_; ++i) { + obj & elt = elts_[i]; + + gc.visit_child(reason, &elt); + } + } + + } /*namespace scm*/ +} /*namespace xo*/ diff --git a/xo-object2/src/object2/DBoolean.cpp b/xo-object2/src/object2/DBoolean.cpp new file mode 100644 index 00000000..2e0bafa8 --- /dev/null +++ b/xo-object2/src/object2/DBoolean.cpp @@ -0,0 +1,48 @@ +/** @file DBoolean.cpp +* + * @author Roland Conybeare, Jan 2026 + **/ + +#include "DBoolean.hpp" +#include +#include + +namespace xo { + using xo::facet::typeseq; + using xo::print::ppdetail_atomic; + + namespace scm { + DBoolean * + DBoolean::_box(obj mm, bool x) + { + void * mem = mm.alloc(typeseq::id(), + sizeof(DBoolean)); + + return new (mem) DBoolean(x); + } + + bool + DBoolean::pretty(const ppindentinfo & ppii) const + { + return ppdetail_atomic::print_pretty + (ppii, + (value_ ? "true" : "false")); + } + + DBoolean * + DBoolean::gco_shallow_move(obj gc) noexcept + { + return gc.std_move_for(this); + } + + void + DBoolean::visit_gco_children(VisitReason, obj) noexcept + { + // no-op. childless + } + + + } /*namespace scm*/ +} /*namespace xo*/ + +/* end DBoolean.cpp */ diff --git a/xo-object2/src/object2/DDictionary.cpp b/xo-object2/src/object2/DDictionary.cpp new file mode 100644 index 00000000..9e05cfa9 --- /dev/null +++ b/xo-object2/src/object2/DDictionary.cpp @@ -0,0 +1,315 @@ +/** @file DDictionary.cpp + * + * @author Roland Conybeare, Mar 2026 + **/ + +#include "DDictionary.hpp" +#include "Array.hpp" +#include "String.hpp" +#include +#include + +namespace xo { + using xo::print::APrintable; + using xo::facet::FacetRegistry; + using xo::mm::AGCObject; + + namespace scm { + + DDictionary::DDictionary(DArray * keys, + DArray * values) + : keys_{keys}, values_{values} + {} + + DDictionary * + DDictionary::empty(obj mm, size_type cap) + { + void * mem = mm.alloc_for(); + + if (mem) { + if (cap <= 0) + cap = 1; + + DArray * keys = DArray::_empty(mm, cap); + DArray * values = DArray::_empty(mm, cap); + + if (keys && values) + return new (mem) DDictionary(keys, values); + } + + return nullptr; + } + + std::optional> + DDictionary::lookup(const DString * key) const noexcept + { + for (DArray::size_type i = 0, z = keys_->size(); i < z; ++i) { + auto i_key = obj::from(keys_->at(i)); + + assert(i_key); + + if (DString::compare(*key, *i_key.data()) == 0) + return values_->at(i); + } + + return {}; + } + + std::optional> + DDictionary::lookup_cstr(const char * key) const noexcept + { + for (DArray::size_type i = 0, z = keys_->size(); i < z; ++i) { + auto i_key = obj::from(keys_->at(i)); + + assert(i_key); + + if (strcmp(key, i_key->data()) == 0) + return values_->at(i); + } + + return {}; + } + + std::pair> + DDictionary::at_index(size_type ix) const + { + if (ix < keys_->size()) { +#ifndef NDEBUG + auto key_str = obj::from((*keys_)[ix]); + assert(key_str); +#endif + + return pair_type(this->key_at_index(ix), (*values_)[ix]); + } + + return pair_type(); + } + + const DString * + DDictionary::key_at_index(size_type ix) const + { + auto key_str = obj::from((*keys_)[ix]); + + assert(key_str); + + return key_str.data(); + } + + obj + DDictionary::value_at_index(size_type ix) const + { + if (ix < keys_->size()) { + assert(ix < values_->size()); + + return (*values_)[ix]; + } + + return obj(); + } + + bool + DDictionary::try_update(obj mm, const pair_type & kv_pair) + { + for (size_type i = 0, n = keys_->size(); i < n; ++i) { + auto key_i = obj::from((*keys_)[i]); + + assert(key_i); + + if (*(key_i.data()) == *(kv_pair.first)) { + values_->assign_at(mm, i, kv_pair.second); + return true; + } + } + + return false; + } + + bool + DDictionary::try_update_cstr(obj mm, const char * key, obj value) + { + for (size_type i = 0, n = keys_->size(); i < n; ++i) { + auto key_i = obj::from((*keys_)[i]); + + assert(key_i); + + if (strcmp(key, key_i->data()) == 0) { + values_->assign_at(mm, i, value); + + return true; + } + } + + return false; + } + + bool + DDictionary::try_upsert_cstr(obj mm, const char * key_cstr, obj value) + { + const DString * k1 = DString::from_cstr(mm, key_cstr); + + if (k1) { + return this->try_upsert(mm, std::make_pair(k1, value)); + } + + return false; + } + + bool + DDictionary::upsert_cstr(obj mm, const char * key_cstr, obj value) + { + const DString * k1 = DString::from_cstr(mm, key_cstr); + + if (k1) + return this->upsert(mm, std::make_pair(k1, value)); + + return false; + } + + bool + DDictionary::try_upsert(obj mm, const pair_type & kv_pair) + { + if (this->try_update(mm, kv_pair)) + return true; + + if (keys_->size() == keys_->capacity()) + return false; + + return this->_append_kv_aux(mm, kv_pair); + } + + bool + DDictionary::upsert(obj mm, const pair_type & kv_pair) + { + if (this->try_update(mm, kv_pair)) + return true; + + // key not present -> must expand {key array, value array} + + if (keys_->size() == keys_->capacity()) { + assert(keys_->capacity() > 0); + + size_type cap_2x = 2 * keys_->capacity(); + + DArray * keys_2x = DArray::copy(mm, keys_, cap_2x); + DArray * values_2x = DArray::copy(mm, values_, cap_2x); + + if (keys_2x && values_2x) { + this->keys_ = keys_2x; + this->values_ = values_2x; + } else { + return false; + } + } + + return this->_append_kv_aux(mm, kv_pair); + } + + bool + DDictionary::_append_kv_aux(obj mm, const pair_type & kv_pair) + { + DString * key = const_cast(kv_pair.first); + + bool ok + = keys_->push_back(mm, obj(key)); + + if (ok) { + ok = values_->push_back(mm, kv_pair.second); + + if (!ok) { + // since we couldn't insert value, also drop key + + keys_->pop_back(); + } + } + + return ok; + } + + void + DDictionary::shrink_to_fit() noexcept + { + keys_->shrink_to_fit(); + values_->shrink_to_fit(); + } + + // ----- printable facet ---- + + bool + DDictionary::pretty(const ppindentinfo & ppii) const + { + using xo::print::ppstate; + + ppstate * pps = ppii.pps(); + + if (ppii.upto()) { + pps->write("{"); + + for (size_type i = 0, n = this->size(); i < n; ++i) { + pps->write(" "); + + obj key + = FacetRegistry::instance().variant((*keys_)[i]); + obj value + = FacetRegistry::instance().variant((*values_)[i]); + + assert(key.data()); + assert(value.data()); + + if (!pps->print_upto(key)) + return false; + pps->write(": "); + + if (!pps->print_upto(value)) + return false; + pps->write(";"); + } + + pps->write(" }"); + return true; + } else { + pps->write("{"); + + for (size_type i = 0, n = this->size(); i < n; ++i) { + if (i == 0) { + /* indent, but credit initial {. using same line for first (key,value) */ + pps->indent(std::max(pps->indent_width(), 1u) - 1); + } else { + /* indent after newline */ + pps->newline_indent(ppii.ci1()); + } + + obj key + = FacetRegistry::instance().variant((*keys_)[i]); + obj value + = FacetRegistry::instance().variant((*values_)[i]); + + pps->pretty(key); + pps->write(": "); + pps->pretty(value); + pps->write(";"); + } + + pps->write(" }"); + return false; + } + } + + // ----- gcobject facet ----- + + DDictionary * + DDictionary::gco_shallow_move(obj gc) noexcept + { + return gc.std_move_for(this); + } + + void + DDictionary::visit_gco_children(VisitReason reason, obj gc) noexcept + { + gc.visit_child(reason, &keys_); + gc.visit_child(reason, &values_); + } + + } /*namespace scm*/ +} /*namespace xo*/ + +/* end DDictionary.cpp */ diff --git a/xo-object2/src/object2/DFloat.cpp b/xo-object2/src/object2/DFloat.cpp new file mode 100644 index 00000000..6141b283 --- /dev/null +++ b/xo-object2/src/object2/DFloat.cpp @@ -0,0 +1,45 @@ +/** @file DFloat.cpp + * + * @author Roland Conybeare, Dec 2025 + **/ + +#include "DFloat.hpp" +#include + +namespace xo { + using xo::facet::typeseq; + using xo::print::ppdetail_atomic; + using std::size_t; + + namespace scm { + DFloat * + DFloat::_box(obj mm, double x) + { + void * mem = mm.alloc(typeseq::id(), + sizeof(DFloat)); + + return new (mem) DFloat(x); + } + + bool + DFloat::pretty(const ppindentinfo & ppii) const + { + return ppdetail_atomic::print_pretty(ppii, value_); + } + + DFloat * + DFloat::gco_shallow_move(obj gc) noexcept + { + return gc.std_move_for(this); + } + + void + DFloat::visit_gco_children(VisitReason, obj) noexcept + { + // noop -- childless! + } + + } /*namespace scm*/ +} /*namespace xo*/ + +/* end DFloat.cpp */ diff --git a/xo-object2/src/object2/DInteger.cpp b/xo-object2/src/object2/DInteger.cpp new file mode 100644 index 00000000..2ff2d5b1 --- /dev/null +++ b/xo-object2/src/object2/DInteger.cpp @@ -0,0 +1,48 @@ +/** @file DInteger.cpp +* + * @author Roland Conybeare, Jan 2026 + **/ + +#include "DInteger.hpp" +#include +#include + +namespace xo { + using xo::facet::typeseq; + using xo::print::ppdetail_atomic; + + namespace scm { + DInteger * + DInteger::_box(obj mm, long x) + { + void * mem = mm.alloc(typeseq::id(), + sizeof(DInteger)); + + if (mem) + return new (mem) DInteger(x); + + return nullptr; + } + + bool + DInteger::pretty(const ppindentinfo & ppii) const + { + return ppdetail_atomic::print_pretty(ppii, value_); + } + + DInteger * + DInteger::gco_shallow_move(obj gc) noexcept + { + return gc.std_move_for(this); + } + + void + DInteger::visit_gco_children(VisitReason, obj) noexcept + { + // no-op. childless + } + + } /*namespace scm*/ +} /*namespace xo*/ + +/* end DInteger.cpp */ diff --git a/xo-object2/src/object2/DList.cpp b/xo-object2/src/object2/DList.cpp new file mode 100644 index 00000000..54315823 --- /dev/null +++ b/xo-object2/src/object2/DList.cpp @@ -0,0 +1,219 @@ +/** @file DList.cpp + * + * @author Roland Conybeare, Dec 2025 + **/ + +#include "DList.hpp" +#include "list/IPrintable_DList.hpp" +#include "list/IGCObject_DList.hpp" +#include +#include + +// need Collector for mm_do_assign() +#include +#include // for mm_do_assign() + +#include +#include +#include +#include +#include + +namespace xo { + using xo::print::APrintable; + using xo::mm::AGCObject; + using xo::facet::FacetRegistry; + //using xo::facet::typeseq; + + namespace scm { + static DList s_null(obj(), nullptr); + + DList * + DList::_nil() + { + return &s_null; + } + + obj + DList::nil() + { + return obj(_nil()); + } + + DList * + DList::_cons(obj mm, + obj car, + DList * cdr) + { + void * mem = mm.alloc_for(); + + return new (mem) DList(car, cdr); + } + + obj + DList::cons(obj mm, + obj car, + DList * cdr) + { + return obj(_cons(mm, car, cdr)); + } + +#ifdef OBSOLETE + DList * + DList::list(obj mm, + obj h1) + { + void * mem = mm.alloc(typeseq::id(), sizeof(DList)); + + return new (mem) DList(h1, DList::_nil()); + } + + DList * + DList::list(obj mm, + obj h1, + obj h2) + { + void * mem = mm.alloc(typeseq::id(), sizeof(DList)); + + return new (mem) DList(h1, DList::list(mm, h2)); + } +#endif + + bool + DList::is_empty() const noexcept + { + return this == &s_null; + } + + auto + DList::size() const noexcept -> size_type + { + const DList * l = this; + + size_type z = 0; + + while (l && l != &s_null) { + ++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_; + } + + void + DList::assign_head(obj mm, obj rhs) + { + scope log(XO_DEBUG(true), xtag("mm.data", mm.data_)); + + mm.barrier_assign(this, &head_, rhs); + + //mm.barrier_assign_aux(this, + // head_.iface(), head_.opaque_data_addr(), + // rhs.iface(), rhs.opaque_data()); + } + + // vestigial. used in MockCollector + void + DList::assign_head_gc(obj gc, obj rhs) + { + scope log(XO_DEBUG(true), xtag("gc.data", gc.data_)); + + gc.assign_member(this, &head_, rhs); + } + + void + DList::_assign_rest(obj mm, DList * rest) + { + obj rest_gco(rest); + + mm.barrier_assign_aux(this, + nullptr /*lhs iface unused*/, + (void**)&(this->rest_), + rest_gco.iface(), + rest); + } + + bool + DList::pretty(const ppindentinfo & ppii) const + { + /* adapted from ppstate.pretty_struct(), see also */ + + using xo::print::ppstate; + + ppstate * pps = ppii.pps(); + + if (ppii.upto()) { + /* perhaps print on one line */ + pps->write("("); + + /* TODO: probably use iterators here, when available */ + const DList * l = this; + + size_t i = 0; + while (!l->is_empty()) { + if (i > 0) + pps->write(" "); + + obj elt + = FacetRegistry::instance().variant(l->head_); + + assert(elt.data()); + + if (!pps->print_upto(elt)) + return false; + + l = l->rest_; + ++i; + } + + pps->write(")"); + return true; + } else { + pps->write("(...)"); + return false; + } + } + + // ----- GCObject facet ------ + + DList * + DList::gco_shallow_move(obj gc) noexcept + { + return gc.std_move_for(this); + } + + void + DList::visit_gco_children(VisitReason reason, obj gc) noexcept + { + gc.visit_child(reason, &head_); + gc.visit_child(reason, &rest_); + } + } /*namespace scm*/ +} /*namespace xo*/ + +/* end DList.cpp */ diff --git a/xo-object2/src/object2/DRuntimeError.cpp b/xo-object2/src/object2/DRuntimeError.cpp new file mode 100644 index 00000000..2d9518e6 --- /dev/null +++ b/xo-object2/src/object2/DRuntimeError.cpp @@ -0,0 +1,83 @@ +/** @file DRuntimeError.cpp +* + * @author Roland Conybeare, Feb 2026 + **/ + +#include "RuntimeError.hpp" + +namespace xo { + using xo::print::APrintable; + using xo::mm::AGCObject; + using xo::facet::typeseq; + + namespace scm { + + obj + DRuntimeError::make(obj mm, + const char * src_fn, + const char * error_descr) + { + DRuntimeError * err = DRuntimeError::_make(mm, nullptr, nullptr); + + // pedantic: allocate strings after allocating DRuntimeError instance + + DString * src = DString::from_cstr(mm, src_fn); + DString * err_descr = DString::from_cstr(mm, error_descr); + + err->src_function_ = src; + err->error_descr_ = err_descr; + + return obj(err); + } + + DRuntimeError * + DRuntimeError::_make(obj mm, + DString * src_fn, + DString * error_descr) + { + void * mem + = mm.alloc(typeseq::id(), + sizeof(DRuntimeError)); + + DRuntimeError * err + = new (mem) DRuntimeError(src_fn, error_descr); + + return err; + } + + DRuntimeError::DRuntimeError(DString * src_fn, + DString * error_descr) : src_function_{src_fn}, + error_descr_{error_descr} + {} + + // ----- GCObject facet ----- + + DRuntimeError * + DRuntimeError::gco_shallow_move(obj gc) noexcept + { + return gc.std_move_for(this); + } + + void + DRuntimeError::visit_gco_children(VisitReason reason, obj gc) noexcept + { + gc.visit_child(reason, &src_function_); + gc.visit_child(reason, &error_descr_); + } + + // ----- Printable facet ----- + + bool + DRuntimeError::pretty(const ppindentinfo & ppii) const + { + return ppii.pps()->pretty_struct + (ppii, + "DRuntimeError", + refrtag("src", obj(src_function_)), + refrtag("err", obj(error_descr_))); + } + + } /*namespace scm*/ +} /*namespace xo*/ + +/* end DRuntimeError.cpp */ diff --git a/xo-object2/src/object2/GCObjectConversion_DFloat.cpp b/xo-object2/src/object2/GCObjectConversion_DFloat.cpp new file mode 100644 index 00000000..794431d2 --- /dev/null +++ b/xo-object2/src/object2/GCObjectConversion_DFloat.cpp @@ -0,0 +1,41 @@ +/** @file GCObjectConversion_DFloat.cpp + * + * @author Roland Conybeare, Jan 2026 + **/ + +#include "number/GCObjectConversion_DFloat.hpp" +#include + +namespace xo { + using xo::mm::AGCObject; + + namespace scm { + + obj + GCObjectConversion::to_gco(obj mm, + double x) + { + return DFloat::box(mm, x); + } + + double + GCObjectConversion::from_gco(obj mm, + obj gco) + { + (void)mm; + + auto float_obj = obj::from(gco); + + if (!float_obj) { + throw std::runtime_error + (tostr("Object obj found where Float expected", + xtag("obj", gco))); + } + + return float_obj.data()->value(); + } + + } /*namespace scm*/ +} /*namespace xo*/ + +/* end GCObjectConversion_DFloat.cpp */ diff --git a/xo-object2/src/object2/GCObjectConversion_DInteger.cpp b/xo-object2/src/object2/GCObjectConversion_DInteger.cpp new file mode 100644 index 00000000..bdaf8a18 --- /dev/null +++ b/xo-object2/src/object2/GCObjectConversion_DInteger.cpp @@ -0,0 +1,41 @@ +/** @file GCObjectConversion_DInteger.cpp + * + * @author Roland Conybeare, Jan 2026 + **/ + +#include "number/GCObjectConversion_DInteger.hpp" +#include + +namespace xo { + using xo::mm::AGCObject; + + namespace scm { + + obj + GCObjectConversion::to_gco(obj mm, + long x) + { + return DInteger::box(mm, x); + } + + long + GCObjectConversion::from_gco(obj mm, + obj gco) + { + (void)mm; + + auto int_obj = obj::from(gco); + + if (!int_obj) { + throw std::runtime_error + (tostr("Object obj found where Integer expected", + xtag("obj", gco))); + } + + return int_obj.data()->value(); + } + + } /*namespace scm*/ +} /*namespace xo*/ + +/* end GCObjectConversion_DFloat.cpp */ diff --git a/xo-object2/src/object2/GCObjectConverter.cpp b/xo-object2/src/object2/GCObjectConverter.cpp new file mode 100644 index 00000000..6f3f5b4a --- /dev/null +++ b/xo-object2/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 */ diff --git a/xo-object2/src/object2/IGCObject_DArray.cpp b/xo-object2/src/object2/IGCObject_DArray.cpp new file mode 100644 index 00000000..e771e335 --- /dev/null +++ b/xo-object2/src/object2/IGCObject_DArray.cpp @@ -0,0 +1,32 @@ +/** @file IGCObject_DArray.cpp + * + * Generated automagically from ingredients: + * 1. code generator: + * [xo-facet/codegen/genfacet] + * arguments: + * --input [idl/IGCObject_DArray.json5] + * 2. jinja2 template for abstract facet .hpp file: + * [iface_facet_any.hpp.j2] + * 3. idl for facet methods + * [idl/IGCObject_DArray.json5] +**/ + +#include "array/IGCObject_DArray.hpp" + +namespace xo { + namespace scm { + auto + IGCObject_DArray::gco_shallow_move(DArray & self, obj gc) noexcept -> Opaque + { + return self.gco_shallow_move(gc); + } + auto + IGCObject_DArray::visit_gco_children(DArray & self, VisitReason reason, obj fn) noexcept -> void + { + self.visit_gco_children(reason, fn); + } + + } /*namespace scm*/ +} /*namespace xo*/ + +/* end IGCObject_DArray.cpp */ diff --git a/xo-object2/src/object2/IGCObject_DBoolean.cpp b/xo-object2/src/object2/IGCObject_DBoolean.cpp new file mode 100644 index 00000000..62b82ca7 --- /dev/null +++ b/xo-object2/src/object2/IGCObject_DBoolean.cpp @@ -0,0 +1,32 @@ +/** @file IGCObject_DBoolean.cpp + * + * Generated automagically from ingredients: + * 1. code generator: + * [xo-facet/codegen/genfacet] + * arguments: + * --input [idl/IGCObject_DBoolean.json5] + * 2. jinja2 template for abstract facet .hpp file: + * [iface_facet_any.hpp.j2] + * 3. idl for facet methods + * [idl/IGCObject_DBoolean.json5] +**/ + +#include "boolean/IGCObject_DBoolean.hpp" + +namespace xo { + namespace scm { + auto + IGCObject_DBoolean::gco_shallow_move(DBoolean & self, obj gc) noexcept -> Opaque + { + return self.gco_shallow_move(gc); + } + auto + IGCObject_DBoolean::visit_gco_children(DBoolean & self, VisitReason reason, obj fn) noexcept -> void + { + self.visit_gco_children(reason, fn); + } + + } /*namespace scm*/ +} /*namespace xo*/ + +/* end IGCObject_DBoolean.cpp */ diff --git a/xo-object2/src/object2/IGCObject_DDictionary.cpp b/xo-object2/src/object2/IGCObject_DDictionary.cpp new file mode 100644 index 00000000..ae6da864 --- /dev/null +++ b/xo-object2/src/object2/IGCObject_DDictionary.cpp @@ -0,0 +1,32 @@ +/** @file IGCObject_DDictionary.cpp + * + * Generated automagically from ingredients: + * 1. code generator: + * [xo-facet/codegen/genfacet] + * arguments: + * --input [idl/IGCObject_DDictionary.json5] + * 2. jinja2 template for abstract facet .hpp file: + * [iface_facet_any.hpp.j2] + * 3. idl for facet methods + * [idl/IGCObject_DDictionary.json5] +**/ + +#include "dictionary/IGCObject_DDictionary.hpp" + +namespace xo { + namespace scm { + auto + IGCObject_DDictionary::gco_shallow_move(DDictionary & self, obj gc) noexcept -> Opaque + { + return self.gco_shallow_move(gc); + } + auto + IGCObject_DDictionary::visit_gco_children(DDictionary & self, VisitReason reason, obj fn) noexcept -> void + { + self.visit_gco_children(reason, fn); + } + + } /*namespace scm*/ +} /*namespace xo*/ + +/* end IGCObject_DDictionary.cpp */ diff --git a/xo-object2/src/object2/IGCObject_DFloat.cpp b/xo-object2/src/object2/IGCObject_DFloat.cpp new file mode 100644 index 00000000..d6399b0b --- /dev/null +++ b/xo-object2/src/object2/IGCObject_DFloat.cpp @@ -0,0 +1,32 @@ +/** @file IGCObject_DFloat.cpp + * + * Generated automagically from ingredients: + * 1. code generator: + * [xo-facet/codegen/genfacet] + * arguments: + * --input [idl/IGCObject_DFloat.json5] + * 2. jinja2 template for abstract facet .hpp file: + * [iface_facet_any.hpp.j2] + * 3. idl for facet methods + * [idl/IGCObject_DFloat.json5] +**/ + +#include "number/IGCObject_DFloat.hpp" + +namespace xo { + namespace scm { + auto + IGCObject_DFloat::gco_shallow_move(DFloat & self, obj gc) noexcept -> Opaque + { + return self.gco_shallow_move(gc); + } + auto + IGCObject_DFloat::visit_gco_children(DFloat & self, VisitReason reason, obj fn) noexcept -> void + { + self.visit_gco_children(reason, fn); + } + + } /*namespace scm*/ +} /*namespace xo*/ + +/* end IGCObject_DFloat.cpp */ diff --git a/xo-object2/src/object2/IGCObject_DInteger.cpp b/xo-object2/src/object2/IGCObject_DInteger.cpp new file mode 100644 index 00000000..1acd0455 --- /dev/null +++ b/xo-object2/src/object2/IGCObject_DInteger.cpp @@ -0,0 +1,32 @@ +/** @file IGCObject_DInteger.cpp + * + * Generated automagically from ingredients: + * 1. code generator: + * [xo-facet/codegen/genfacet] + * arguments: + * --input [idl/IGCObject_DInteger.json5] + * 2. jinja2 template for abstract facet .hpp file: + * [iface_facet_any.hpp.j2] + * 3. idl for facet methods + * [idl/IGCObject_DInteger.json5] +**/ + +#include "number/IGCObject_DInteger.hpp" + +namespace xo { + namespace scm { + auto + IGCObject_DInteger::gco_shallow_move(DInteger & self, obj gc) noexcept -> Opaque + { + return self.gco_shallow_move(gc); + } + auto + IGCObject_DInteger::visit_gco_children(DInteger & self, VisitReason reason, obj fn) noexcept -> void + { + self.visit_gco_children(reason, fn); + } + + } /*namespace scm*/ +} /*namespace xo*/ + +/* end IGCObject_DInteger.cpp */ diff --git a/xo-object2/src/object2/IGCObject_DList.cpp b/xo-object2/src/object2/IGCObject_DList.cpp new file mode 100644 index 00000000..205c3e58 --- /dev/null +++ b/xo-object2/src/object2/IGCObject_DList.cpp @@ -0,0 +1,32 @@ +/** @file IGCObject_DList.cpp + * + * Generated automagically from ingredients: + * 1. code generator: + * [xo-facet/codegen/genfacet] + * arguments: + * --input [idl/IGCObject_DList.json5] + * 2. jinja2 template for abstract facet .hpp file: + * [iface_facet_any.hpp.j2] + * 3. idl for facet methods + * [idl/IGCObject_DList.json5] +**/ + +#include "list/IGCObject_DList.hpp" + +namespace xo { + namespace scm { + auto + IGCObject_DList::gco_shallow_move(DList & self, obj gc) noexcept -> Opaque + { + return self.gco_shallow_move(gc); + } + auto + IGCObject_DList::visit_gco_children(DList & self, VisitReason reason, obj fn) noexcept -> void + { + self.visit_gco_children(reason, fn); + } + + } /*namespace scm*/ +} /*namespace xo*/ + +/* end IGCObject_DList.cpp */ diff --git a/xo-object2/src/object2/IGCObject_DRuntimeError.cpp b/xo-object2/src/object2/IGCObject_DRuntimeError.cpp new file mode 100644 index 00000000..3efa863d --- /dev/null +++ b/xo-object2/src/object2/IGCObject_DRuntimeError.cpp @@ -0,0 +1,32 @@ +/** @file IGCObject_DRuntimeError.cpp + * + * Generated automagically from ingredients: + * 1. code generator: + * [xo-facet/codegen/genfacet] + * arguments: + * --input [idl/IGCObject_DRuntimeError.json5] + * 2. jinja2 template for abstract facet .hpp file: + * [iface_facet_any.hpp.j2] + * 3. idl for facet methods + * [idl/IGCObject_DRuntimeError.json5] +**/ + +#include "error/IGCObject_DRuntimeError.hpp" + +namespace xo { + namespace scm { + auto + IGCObject_DRuntimeError::gco_shallow_move(DRuntimeError & self, obj gc) noexcept -> Opaque + { + return self.gco_shallow_move(gc); + } + auto + IGCObject_DRuntimeError::visit_gco_children(DRuntimeError & self, VisitReason reason, obj fn) noexcept -> void + { + self.visit_gco_children(reason, fn); + } + + } /*namespace scm*/ +} /*namespace xo*/ + +/* end IGCObject_DRuntimeError.cpp */ diff --git a/xo-object2/src/object2/IPrintable_DArray.cpp b/xo-object2/src/object2/IPrintable_DArray.cpp new file mode 100644 index 00000000..b9248516 --- /dev/null +++ b/xo-object2/src/object2/IPrintable_DArray.cpp @@ -0,0 +1,28 @@ +/** @file IPrintable_DArray.cpp + * + * Generated automagically from ingredients: + * 1. code generator: + * [xo-facet/codegen/genfacet] + * arguments: + * --input [idl/IPrintable_DArray.json5] + * 2. jinja2 template for abstract facet .hpp file: + * [iface_facet_any.hpp.j2] + * 3. idl for facet methods + * [idl/IPrintable_DArray.json5] +**/ + +#include "array/IPrintable_DArray.hpp" + +namespace xo { + namespace scm { + auto + IPrintable_DArray::pretty(const DArray & self, const ppindentinfo & ppii) -> bool + { + return self.pretty(ppii); + } + + + } /*namespace scm*/ +} /*namespace xo*/ + +/* end IPrintable_DArray.cpp */ diff --git a/xo-object2/src/object2/IPrintable_DBoolean.cpp b/xo-object2/src/object2/IPrintable_DBoolean.cpp new file mode 100644 index 00000000..3b85aa27 --- /dev/null +++ b/xo-object2/src/object2/IPrintable_DBoolean.cpp @@ -0,0 +1,28 @@ +/** @file IPrintable_DBoolean.cpp + * + * Generated automagically from ingredients: + * 1. code generator: + * [xo-facet/codegen/genfacet] + * arguments: + * --input [idl/IPrintable_DBoolean.json5] + * 2. jinja2 template for abstract facet .hpp file: + * [iface_facet_any.hpp.j2] + * 3. idl for facet methods + * [idl/IPrintable_DBoolean.json5] +**/ + +#include "boolean/IPrintable_DBoolean.hpp" + +namespace xo { + namespace scm { + auto + IPrintable_DBoolean::pretty(const DBoolean & self, const ppindentinfo & ppii) -> bool + { + return self.pretty(ppii); + } + + + } /*namespace scm*/ +} /*namespace xo*/ + +/* end IPrintable_DBoolean.cpp */ diff --git a/xo-object2/src/object2/IPrintable_DDictionary.cpp b/xo-object2/src/object2/IPrintable_DDictionary.cpp new file mode 100644 index 00000000..059196ef --- /dev/null +++ b/xo-object2/src/object2/IPrintable_DDictionary.cpp @@ -0,0 +1,28 @@ +/** @file IPrintable_DDictionary.cpp + * + * Generated automagically from ingredients: + * 1. code generator: + * [xo-facet/codegen/genfacet] + * arguments: + * --input [idl/IPrintable_DDictionary.json5] + * 2. jinja2 template for abstract facet .hpp file: + * [iface_facet_any.hpp.j2] + * 3. idl for facet methods + * [idl/IPrintable_DDictionary.json5] +**/ + +#include "dictionary/IPrintable_DDictionary.hpp" + +namespace xo { + namespace scm { + auto + IPrintable_DDictionary::pretty(const DDictionary & self, const ppindentinfo & ppii) -> bool + { + return self.pretty(ppii); + } + + + } /*namespace scm*/ +} /*namespace xo*/ + +/* end IPrintable_DDictionary.cpp */ diff --git a/xo-object2/src/object2/IPrintable_DFloat.cpp b/xo-object2/src/object2/IPrintable_DFloat.cpp new file mode 100644 index 00000000..f1e8be6d --- /dev/null +++ b/xo-object2/src/object2/IPrintable_DFloat.cpp @@ -0,0 +1,28 @@ +/** @file IPrintable_DFloat.cpp + * + * Generated automagically from ingredients: + * 1. code generator: + * [xo-facet/codegen/genfacet] + * arguments: + * --input [idl/IPrintable_DFloat.json5] + * 2. jinja2 template for abstract facet .hpp file: + * [iface_facet_any.hpp.j2] + * 3. idl for facet methods + * [idl/IPrintable_DFloat.json5] +**/ + +#include "number/IPrintable_DFloat.hpp" + +namespace xo { + namespace scm { + auto + IPrintable_DFloat::pretty(const DFloat & self, const ppindentinfo & ppii) -> bool + { + return self.pretty(ppii); + } + + + } /*namespace scm*/ +} /*namespace xo*/ + +/* end IPrintable_DFloat.cpp */ diff --git a/xo-object2/src/object2/IPrintable_DInteger.cpp b/xo-object2/src/object2/IPrintable_DInteger.cpp new file mode 100644 index 00000000..7a9bbdaa --- /dev/null +++ b/xo-object2/src/object2/IPrintable_DInteger.cpp @@ -0,0 +1,28 @@ +/** @file IPrintable_DInteger.cpp + * + * Generated automagically from ingredients: + * 1. code generator: + * [xo-facet/codegen/genfacet] + * arguments: + * --input [idl/IPrintable_DInteger.json5] + * 2. jinja2 template for abstract facet .hpp file: + * [iface_facet_any.hpp.j2] + * 3. idl for facet methods + * [idl/IPrintable_DInteger.json5] +**/ + +#include "number/IPrintable_DInteger.hpp" + +namespace xo { + namespace scm { + auto + IPrintable_DInteger::pretty(const DInteger & self, const ppindentinfo & ppii) -> bool + { + return self.pretty(ppii); + } + + + } /*namespace scm*/ +} /*namespace xo*/ + +/* end IPrintable_DInteger.cpp */ diff --git a/xo-object2/src/object2/IPrintable_DList.cpp b/xo-object2/src/object2/IPrintable_DList.cpp new file mode 100644 index 00000000..a8f9b657 --- /dev/null +++ b/xo-object2/src/object2/IPrintable_DList.cpp @@ -0,0 +1,28 @@ +/** @file IPrintable_DList.cpp + * + * Generated automagically from ingredients: + * 1. code generator: + * [xo-facet/codegen/genfacet] + * arguments: + * --input [idl/IPrintable_DList.json5] + * 2. jinja2 template for abstract facet .hpp file: + * [iface_facet_any.hpp.j2] + * 3. idl for facet methods + * [idl/IPrintable_DList.json5] +**/ + +#include "list/IPrintable_DList.hpp" + +namespace xo { + namespace scm { + auto + IPrintable_DList::pretty(const DList & self, const ppindentinfo & ppii) -> bool + { + return self.pretty(ppii); + } + + + } /*namespace scm*/ +} /*namespace xo*/ + +/* end IPrintable_DList.cpp */ diff --git a/xo-object2/src/object2/IPrintable_DRuntimeError.cpp b/xo-object2/src/object2/IPrintable_DRuntimeError.cpp new file mode 100644 index 00000000..eaf084ca --- /dev/null +++ b/xo-object2/src/object2/IPrintable_DRuntimeError.cpp @@ -0,0 +1,28 @@ +/** @file IPrintable_DRuntimeError.cpp + * + * Generated automagically from ingredients: + * 1. code generator: + * [xo-facet/codegen/genfacet] + * arguments: + * --input [idl/IPrintable_DRuntimeError.json5] + * 2. jinja2 template for abstract facet .hpp file: + * [iface_facet_any.hpp.j2] + * 3. idl for facet methods + * [idl/IPrintable_DRuntimeError.json5] +**/ + +#include "error/IPrintable_DRuntimeError.hpp" + +namespace xo { + namespace scm { + auto + IPrintable_DRuntimeError::pretty(const DRuntimeError & self, const ppindentinfo & ppii) -> bool + { + return self.pretty(ppii); + } + + + } /*namespace scm*/ +} /*namespace xo*/ + +/* end IPrintable_DRuntimeError.cpp */ diff --git a/xo-object2/src/object2/ISequence_Any.cpp b/xo-object2/src/object2/ISequence_Any.cpp new file mode 100644 index 00000000..5e0583f0 --- /dev/null +++ b/xo-object2/src/object2/ISequence_Any.cpp @@ -0,0 +1,42 @@ +/** @file ISequence_Any.cpp + * + **/ + +#include "sequence/ISequence_Any.hpp" +#include +#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(); +} + +typeseq +ISequence_Any::s_typeseq = typeseq::id(); + +bool +ISequence_Any::_valid + = valid_facet_implementation(); + +// nonconst methods + + +} /*namespace scm*/ +} /*namespace xo*/ + +/* end ISequence_Any.cpp */ diff --git a/xo-object2/src/object2/ISequence_DArray.cpp b/xo-object2/src/object2/ISequence_DArray.cpp new file mode 100644 index 00000000..abeeaeee --- /dev/null +++ b/xo-object2/src/object2/ISequence_DArray.cpp @@ -0,0 +1,40 @@ +/** @file ISequence_DArray.cpp + * + * Generated automagically from ingredients: + * 1. code generator: + * [xo-facet/codegen/genfacet] + * arguments: + * --input [idl/ISequence_DArray.json5] + * 2. jinja2 template for abstract facet .hpp file: + * [iface_facet_any.hpp.j2] + * 3. idl for facet methods + * [idl/ISequence_DArray.json5] +**/ + +#include "array/ISequence_DArray.hpp" + +namespace xo { + namespace scm { + auto + ISequence_DArray::is_empty(const DArray & self) noexcept -> bool + { + return self.is_empty(); + } + + auto + ISequence_DArray::is_finite(const DArray & self) noexcept -> bool + { + return self.is_finite(); + } + + auto + ISequence_DArray::at(const DArray & self, size_type index) -> obj + { + return self.at(index); + } + + + } /*namespace scm*/ +} /*namespace xo*/ + +/* end ISequence_DArray.cpp */ diff --git a/xo-object2/src/object2/ISequence_DList.cpp b/xo-object2/src/object2/ISequence_DList.cpp new file mode 100644 index 00000000..2bc21862 --- /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: + * [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 "list/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 */ diff --git a/xo-object2/src/object2/SetupObject2.cpp b/xo-object2/src/object2/SetupObject2.cpp new file mode 100644 index 00000000..ff22a800 --- /dev/null +++ b/xo-object2/src/object2/SetupObject2.cpp @@ -0,0 +1,107 @@ +/** @file SetupObject2.cpp + * + * @author Roland Conybeare, Jan 2026 + **/ + +#include "SetupObject2.hpp" +#include "RuntimeError.hpp" + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +namespace xo { + using xo::print::APrintable; + using xo::mm::ACollector; + using xo::mm::AAllocator; + using xo::mm::AGCObject; + using xo::scm::DList; + using xo::scm::DBoolean; + using xo::scm::DFloat; + using xo::scm::DString; + using xo::scm::DArray; + using xo::facet::DVariantPlaceholder; + using xo::facet::FacetRegistry; + using xo::facet::impl_for; + using xo::facet::typeseq; + + namespace scm { + bool + SetupObject2::register_facets() + { + scope log(XO_DEBUG(true)); + + FacetRegistry::register_impl(); + FacetRegistry::register_impl(); + + FacetRegistry::register_impl(); + FacetRegistry::register_impl(); + + FacetRegistry::register_impl(); + FacetRegistry::register_impl(); + + FacetRegistry::register_impl(); + FacetRegistry::register_impl(); + + FacetRegistry::register_impl(); + FacetRegistry::register_impl(); + FacetRegistry::register_impl(); + + FacetRegistry::register_impl(); + FacetRegistry::register_impl(); + FacetRegistry::register_impl(); + + FacetRegistry::register_impl(); + FacetRegistry::register_impl(); + + FacetRegistry::register_impl(); + FacetRegistry::register_impl(); + + log && log(xtag("DVariantPlaceholder.tseq", typeseq::id())); + + log && log(xtag("DList.tseq", typeseq::id())); + log && log(xtag("DBoolean.tseq", typeseq::id())); + log && log(xtag("DFloat.tseq", typeseq::id())); + log && log(xtag("DInteger.tseq", typeseq::id())); + log && log(xtag("DArray.tseq", typeseq::id())); + log && log(xtag("DDictionary.tseq", typeseq::id())); + log && log(xtag("DRuntimeError.tseq", typeseq::id())); + + log && log(xtag("AAllocator.tseq", typeseq::id())); + log && log(xtag("APrintable.tseq", typeseq::id())); + log && log(xtag("AGCObject.tseq", typeseq::id())); + log && log(xtag("ASequence.tseq", typeseq::id())); + + return true; + } + + bool + SetupObject2::register_types(obj gc) + { + scope log(XO_DEBUG(true)); + + bool ok = true; + + ok &= gc.install_type(impl_for()); + ok &= gc.install_type(impl_for()); + ok &= gc.install_type(impl_for()); + ok &= gc.install_type(impl_for()); + ok &= gc.install_type(impl_for()); + ok &= gc.install_type(impl_for()); + ok &= gc.install_type(impl_for()); + + return ok; + } + } /*namespace scm*/ +} /*namespace xo*/ + +/* end SetupObject2.cpp */ diff --git a/xo-object2/src/object2/init_object2.cpp b/xo-object2/src/object2/init_object2.cpp new file mode 100644 index 00000000..1a2ed770 --- /dev/null +++ b/xo-object2/src/object2/init_object2.cpp @@ -0,0 +1,40 @@ +/** @file init_object2.cpp + * + * @author Roland Conybeare, Jan 2026 + **/ + +#include "init_object2.hpp" +#include "SetupObject2.hpp" +#include +#include +#include + +namespace xo { + using xo::scm::SetupObject2; + using xo::mm::CollectorTypeRegistry; + + void + InitSubsys::init() + { + SetupObject2::register_facets(); + + CollectorTypeRegistry::instance().register_types(&SetupObject2::register_types); + } + + InitEvidence + InitSubsys::require() + { + InitEvidence retval; + + /* direct subsystem deps for xo-object2/ */ + retval ^= InitSubsys::require(); + retval ^= InitSubsys::require(); + + /* xo-expression2/'s own initialization code */ + retval ^= Subsystem::provide("object2", &init); + + return retval; + } +} /*namespace xo*/ + +/* end init_object2.cpp */ diff --git a/xo-object2/utest/CMakeLists.txt b/xo-object2/utest/CMakeLists.txt new file mode 100644 index 00000000..f3bd90e4 --- /dev/null +++ b/xo-object2/utest/CMakeLists.txt @@ -0,0 +1,15 @@ +# built unittest xo-object2/utest + +set(UTEST_EXE utest.object2) +set(UTEST_SRCS + object2_utest_main.cpp + DArray.test.cpp +# DString.test.cpp +# StringOps.test.cpp +# X1Collector.test.cpp # moved to xo-gc/ +# Printable.test.cpp # moved to xo-gc/ +) + +xo_add_utest_executable(${UTEST_EXE} ${UTEST_SRCS}) +xo_self_dependency(${UTEST_EXE} xo_object2) +xo_external_target_dependency(${UTEST_EXE} Catch2 Catch2::Catch2) diff --git a/xo-object2/utest/DArray.test.cpp b/xo-object2/utest/DArray.test.cpp new file mode 100644 index 00000000..15da135e --- /dev/null +++ b/xo-object2/utest/DArray.test.cpp @@ -0,0 +1,208 @@ +/** @file DArray.test.cpp + * + * @author Roland Conybeare, Jan 2026 + **/ + +#include +#include +#include +#include +#include +#include + +namespace xo { + using xo::scm::ListOps; + using xo::scm::DArray; + using xo::scm::DInteger; + using xo::mm::ACollector; + using xo::mm::AAllocator; + using xo::mm::AGCObject; + using xo::mm::DArena; + using xo::mm::ArenaConfig; + using xo::facet::with_facet; + using xo::facet::obj; + + namespace ut { + TEST_CASE("DArray-nullctor", "[object2][DArray]") + { + DArray arr; + + REQUIRE(arr.size() == 0); + REQUIRE(arr.capacity() == 0); + + REQUIRE(arr.is_empty()); + + // null_mm: for no memory barrier + obj null_mm; + + REQUIRE(arr.push_back(null_mm, ListOps::nil()) == false); + } + + TEST_CASE("DArray-empty", "[object2][DArray]") + { + ArenaConfig cfg { .name_ = "testarena", + .size_ = 4*1024 }; + DArena arena = DArena::map(cfg); + auto alloc = with_facet::mkobj(&arena); + + DArray * arr = DArray::_empty(alloc, 16); + + REQUIRE(arr != nullptr); + REQUIRE(arr->capacity() == 16); + + REQUIRE(arr->is_empty() == true); + REQUIRE(arr->size() == 0); + REQUIRE(arr->is_finite() == true); + } + + TEST_CASE("DArray-push_back", "[object2][DArray]") + { + ArenaConfig cfg { .name_ = "testarena", + .size_ = 4*1024 }; + DArena arena = DArena::map(cfg); + auto alloc = with_facet::mkobj(&arena); + obj null_mm; + + REQUIRE(!null_mm.data()); + REQUIRE(!null_mm._has_null_vptr()); // any + + DArray * arr = DArray::_empty(alloc, 16); + REQUIRE(arr != nullptr); + REQUIRE(arr->capacity() == 16); + REQUIRE(arr->size() == 0); + + obj elt = DInteger::box(alloc, 42); + + bool ok = arr->push_back(null_mm, elt); + + REQUIRE(ok == true); + REQUIRE(arr->is_empty() == false); + REQUIRE(arr->size() == 1); + REQUIRE(arr->capacity() == 16); + } + + TEST_CASE("DArray-push_back-multiple", "[object2][DArray]") + { + ArenaConfig cfg { .name_ = "testarena", + .size_ = 4*1024 }; + DArena arena = DArena::map(cfg); + auto alloc = with_facet::mkobj(&arena); + obj null_mm; + + DArray * arr = DArray::_empty(alloc, 4); + REQUIRE(arr != nullptr); + REQUIRE(arr->capacity() == 4); + REQUIRE(arr->size() == 0); + + for (int i = 0; i < 4; ++i) { + REQUIRE(arr->capacity() == 4); + REQUIRE(arr->size() == i); + + obj elt = DInteger::box(alloc, 100 + i); + bool ok = arr->push_back(null_mm, elt); + REQUIRE(ok == true); + + REQUIRE(arr->capacity() == 4); + REQUIRE(arr->is_empty() == false); + REQUIRE(arr->size() == i+1); + } + } + + TEST_CASE("DArray-push_back-overflow", "[object2][DArray]") + { + ArenaConfig cfg { .name_ = "testarena", + .size_ = 4*1024 }; + DArena arena = DArena::map(cfg); + auto alloc = with_facet::mkobj(&arena); + + DArray * arr = DArray::_empty(alloc, 2); + obj null_mm; + + REQUIRE(arr != nullptr); + REQUIRE(arr->capacity() == 2); + REQUIRE(arr->size() == 0); + + obj e1 = DInteger::box(alloc, 1); + obj e2 = DInteger::box(alloc, 2); + obj e3 = DInteger::box(alloc, 3); + + REQUIRE(arr->push_back(null_mm, e1) == true); + REQUIRE(arr->size() == 1); + REQUIRE(arr->push_back(null_mm, e2) == true); + REQUIRE(arr->size() == 2); + REQUIRE(arr->push_back(null_mm, e3) == false); + REQUIRE(arr->size() == 2); + REQUIRE(arr->capacity() == 2); + } + + TEST_CASE("DArray-at", "[object2][DArray]") + { + ArenaConfig cfg { .name_ = "testarena", + .size_ = 4*1024 }; + DArena arena = DArena::map(cfg); + auto alloc = with_facet::mkobj(&arena); + + DArray * arr = DArray::_empty(alloc, 4); + obj null_mm; + + REQUIRE(arr != nullptr); + REQUIRE(arr->size() == 0); + REQUIRE(arr->capacity() == 4); + + obj e0 = DInteger::box(alloc, 100); + obj e1 = DInteger::box(alloc, 200); + obj e2 = DInteger::box(alloc, 300); + + arr->push_back(null_mm, e0); + arr->push_back(null_mm, e1); + arr->push_back(null_mm, e2); + + REQUIRE(arr->size() == 3); + + REQUIRE(arr->at(0).data() == e0.data()); + REQUIRE(arr->at(1).data() == e1.data()); + REQUIRE(arr->at(2).data() == e2.data()); + } + + TEST_CASE("DArray-array", "[object2][DArray]") + { + ArenaConfig cfg { .name_ = "testarena", + .size_ = 4*1024 }; + DArena arena = DArena::map(cfg); + auto alloc = with_facet::mkobj(&arena); + + obj e0 = DInteger::box(alloc, 10); + obj e1 = DInteger::box(alloc, 20); + obj e2 = DInteger::box(alloc, 30); + + DArray * arr = DArray::array(alloc, e0, e1, e2); + + REQUIRE(arr != nullptr); + REQUIRE(arr->size() == 3); + REQUIRE(arr->capacity() == 3); + REQUIRE(arr->is_empty() == false); + + REQUIRE(arr->at(0).data() == e0.data()); + REQUIRE(arr->at(1).data() == e1.data()); + REQUIRE(arr->at(2).data() == e2.data()); + } + + TEST_CASE("DArray-array-empty", "[object2][DArray]") + { + ArenaConfig cfg { .name_ = "testarena", + .size_ = 4*1024 }; + DArena arena = DArena::map(cfg); + auto alloc = with_facet::mkobj(&arena); + + DArray * arr = DArray::array(alloc); + + REQUIRE(arr != nullptr); + REQUIRE(arr->size() == 0); + REQUIRE(arr->capacity() == 0); + REQUIRE(arr->is_empty() == true); + } + + } /*namespace ut*/ +} /*namespace xo*/ + +/* end DArray.test.cpp */ diff --git a/xo-object2/utest/Printable.test.cpp b/xo-object2/utest/Printable.test.cpp new file mode 100644 index 00000000..289029e8 --- /dev/null +++ b/xo-object2/utest/Printable.test.cpp @@ -0,0 +1,35 @@ +/** @file Printable.test.cpp + * + * @author Roland Conybeare, Jan 2026 + **/ + +#include "ListOps.hpp" +#include "DList.hpp" +#include "SetupObject2.hpp" + +#include +#include +#include + +#include + +#include +#include + +#include + +//#include +//#include +//#include + +#include + +#include + +#include +#include + +#include + + +/* end Printable.test.cpp */ diff --git a/xo-object2/utest/X1Collector.test.cpp b/xo-object2/utest/X1Collector.test.cpp new file mode 100644 index 00000000..59565c1f --- /dev/null +++ b/xo-object2/utest/X1Collector.test.cpp @@ -0,0 +1,288 @@ +/** @file X1Collector.test.cpp + * + * @author Roland Conybeare, Dec 2025 + **/ + +#include "init_object2.hpp" +#include "ListOps.hpp" +#include "DFloat.hpp" +#include "DInteger.hpp" +#include "DList.hpp" +#include "DArray.hpp" + +#include "number/IGCObject_DFloat.hpp" +#include "number/IGCObject_DInteger.hpp" +#include "list/IGCObject_DList.hpp" + +#include +#include +//#include +//#include +//#include + +#include +#include + +#include + +#include +#include + +#include + +namespace ut { + using xo::S_object2_tag; + using xo::scm::ListOps; + using xo::scm::DList; + using xo::scm::DArray; + using xo::scm::DFloat; + using xo::scm::DInteger; + using xo::mm::CollectorTypeRegistry; + using xo::mm::AAllocator; + using xo::mm::ACollector; + using xo::mm::AllocHeader; + using xo::mm::AllocInfo; + using xo::mm::AGCObject; +// using xo::mm::DX1Collector; + using xo::mm::DArena; +// using xo::mm::X1CollectorConfig; + using xo::mm::ArenaConfig; + using xo::mm::Generation; + using xo::mm::role; + using xo::mm::padding; + using xo::facet::with_facet; + using xo::facet::typeseq; + using xo::Subsystem; + using xo::InitEvidence; + using xo::InitSubsys; + using xo::scope; + using xo::xtag; + + namespace { + struct testcase_x1 { + testcase_x1(std::size_t nz, + std::size_t tz, + std::size_t n_gct, + std::size_t t_gct) + : nursery_z_{nz}, + tenured_z_{tz}, + incr_gc_threshold_{n_gct}, + full_gc_threshold_{t_gct} {} + + std::size_t nursery_z_; + std::size_t tenured_z_; + std::size_t incr_gc_threshold_; + std::size_t full_gc_threshold_; + }; + + std::vector + s_testcase_v = { + // n_gct: nursery gc threshold + // t_gct: tenured gc threshold + // + // nz tz n_gct t_gct + testcase_x1(4096, 8192, 1024, 1024) + }; + } + + static InitEvidence s_init = (InitSubsys::require()); + + TEST_CASE("x1", "[gc][x1]") + { + // real purpose: ensure s_init survives static linking + REQUIRE(s_init.evidence()); + + /** + * This is a basic Collector test for xo-object2 data types + **/ + + constexpr bool c_debug_flag = false; + scope log(XO_DEBUG(c_debug_flag)); + + for (std::size_t i_tc = 0, n_tc = s_testcase_v.size(); i_tc < n_tc; ++i_tc) { + scope log(XO_DEBUG(true), xtag("i_tc", i_tc)); + + try { + const testcase_x1 & tc = s_testcase_v[i_tc]; + + X1CollectorConfig cfg{ .name_ = "x1_test", + .arena_config_ = ArenaConfig{ + .size_ = tc.tenured_z_, + .store_header_flag_ = true}, + .object_types_z_ = 16384, + .gc_trigger_v_{{ + tc.incr_gc_threshold_, + tc.full_gc_threshold_}}, + .debug_flag_ = c_debug_flag, + }; + + DX1Collector gc(cfg); + + DArena * to_0 = nullptr; + + /* verify initial collector state */ + { + REQUIRE(gc.name() == "x1_test"); + + const DArena * otypes = gc.get_object_types(); + + REQUIRE(otypes != nullptr); + REQUIRE(otypes->reserved() >= cfg.object_types_z_); + REQUIRE(otypes->reserved() < cfg.object_types_z_ + otypes->page_z_); + + const DX1Collector::RootSet * roots = gc.get_root_set(); + + REQUIRE(roots != nullptr); + REQUIRE(roots->store()->reserved() >= cfg.object_roots_z_); + REQUIRE(roots->store()->reserved() < cfg.object_roots_z_ + roots->store()->page_z_); + + const DArena * from_0 = gc.get_space(role::from_space(), Generation{0}); + + REQUIRE(from_0 != nullptr); + REQUIRE(from_0->reserved() >= tc.tenured_z_); + REQUIRE(from_0->reserved() < tc.tenured_z_ + from_0->page_z_); + REQUIRE(from_0->reserved() % from_0->page_z_ == 0); + REQUIRE(from_0->allocated() == 0); + + const DArena * from_1 = gc.get_space(role::from_space(), Generation{1}); + + REQUIRE(from_1 != nullptr); + REQUIRE(from_1->reserved() == from_0->reserved()); + REQUIRE(from_1->allocated() == 0); + + to_0 = gc.get_space(role::to_space(), Generation{0}); + + REQUIRE(to_0 != nullptr); + REQUIRE(to_0->reserved() == from_0->reserved()); + REQUIRE(to_0->allocated() == 0); + + const DArena * to_1 = gc.get_space(role::to_space(), Generation{1}); + + REQUIRE(to_1 != nullptr); + REQUIRE(to_1->reserved() == to_0->reserved()); + REQUIRE(to_1->allocated() == 0); + + const DArena * from_2 = gc.get_space(role::from_space(), Generation{2}); + + REQUIRE(from_2 == nullptr); + + const DArena * to_2 = gc.get_space(role::to_space(), Generation{2}); + + REQUIRE(to_2 == nullptr); + + REQUIRE(gc.reserved() + == otypes->reserved() + roots->store()->reserved() + 4 * from_0->reserved()); + + log && log(xtag("from_0", from_0->lo_), xtag("to_0", to_0->lo_)); + } + + /* attempt allocation */ + auto gc_o = with_facet::mkobj(&gc); + auto c_o = with_facet::mkobj(&gc); + + /* register object types */ + bool ok = CollectorTypeRegistry::instance().install_types(c_o); + + REQUIRE(ok); + + ok = c_o.is_type_installed(typeseq::id()); + REQUIRE(ok); + ok = c_o.is_type_installed(typeseq::id()); + REQUIRE(ok); + ok = c_o.is_type_installed(typeseq::id()); + REQUIRE(ok); + ok = c_o.is_type_installed(typeseq::id()); + REQUIRE(ok); + + auto x0_o = DFloat::box(gc_o, 3.1415927); + c_o.add_gc_root(&x0_o); + REQUIRE(to_0->allocated() == sizeof(AllocHeader) + sizeof(DFloat)); + + auto n1_o = DInteger::box(gc_o, 42); + c_o.add_gc_root(&n1_o); + REQUIRE(to_0->allocated() == (sizeof(AllocHeader) + sizeof(DFloat) + + sizeof(AllocHeader) + sizeof(DInteger))); + + //DList * l0 = DList::list(gc_o, x0_o); + //auto l0_o = with_facet::mkobj(l0); + auto l0_o = ListOps::list(gc_o, x0_o); + c_o.add_gc_root(&l0_o); + REQUIRE(to_0->allocated() == (sizeof(AllocHeader) + sizeof(DFloat) + + sizeof(AllocHeader) + sizeof(DInteger) + + sizeof(AllocHeader) + sizeof(DList))); + + { + { + REQUIRE(x0_o.iface() != nullptr); + REQUIRE(x0_o.data() != nullptr); + REQUIRE(gc.contains(role::to_space(), x0_o.data())); + + /* check alloc info for newly-allocated object */ + AllocInfo info = gc.alloc_info((std::byte *)x0_o.data()); + + REQUIRE(info.age() == 0); + REQUIRE(info.tseq() == typeseq::id().seqno()); + REQUIRE(info.size() >= sizeof(DFloat)); + REQUIRE(info.size() < sizeof(DFloat) + padding::c_alloc_alignment); + } + + { + REQUIRE(n1_o.iface() != nullptr); + REQUIRE(n1_o.data() != nullptr); + REQUIRE(gc.contains(role::to_space(), n1_o.data())); + + /* check alloc info for newly-allocated object */ + AllocInfo info = gc.alloc_info((std::byte *)n1_o.data()); + + REQUIRE(info.age() == 0); + REQUIRE(info.tseq() == typeseq::id().seqno()); + REQUIRE(info.size() >= sizeof(DInteger)); + REQUIRE(info.size() < sizeof(DInteger) + padding::c_alloc_alignment); + } + + { + REQUIRE(l0_o.iface() != nullptr); + REQUIRE(l0_o.data() != nullptr); + REQUIRE(gc.contains(role::to_space(), l0_o.data())); + + /* check alloc info for newly-allocated object */ + AllocInfo info = gc.alloc_info((std::byte *)l0_o.data()); + + REQUIRE(info.age() == 0); + REQUIRE(info.tseq() == typeseq::id().seqno()); + REQUIRE(info.size() >= sizeof(DList)); + REQUIRE(info.size() < sizeof(DList) + padding::c_alloc_alignment); + } + } + + /* no GC roots, so GC is trivial */ + c_o.request_gc(Generation{1}); + + log && log(xtag("l0_o.data()", l0_o.data())); + log && log(xtag("l0_o.data()->head_.data()", l0_o.data()->head_.data())); + log && log(xtag("x0_o.data()", x0_o.data())); + + REQUIRE(!gc.contains(role::from_space(), x0_o.data())); + REQUIRE(gc.contains(role::to_space(), x0_o.data())); + REQUIRE(x0_o.data()->value() == 3.1415927); + + REQUIRE(!gc.contains(role::from_space(), n1_o.data())); + REQUIRE(gc.contains(role::to_space(), n1_o.data())); + REQUIRE(n1_o.data()->value() == 42); + + REQUIRE(!gc.contains(role::from_space(), l0_o.data())); + REQUIRE(gc.contains(role::to_space(), l0_o.data())); + REQUIRE(l0_o.data()->is_empty() == false); + + REQUIRE((void*)l0_o.data()->head_.data() == (void*)x0_o.data()); + REQUIRE((void*)l0_o.data()->rest_ == (void*)DList::_nil()); + + } catch (std::exception & ex) { + std::cerr << "caught exception: " << ex.what() << std::endl; + REQUIRE(false); + } + } + } +} + +/* end X1Collector.test.cpp */ diff --git a/xo-object2/utest/object2_utest_main.cpp b/xo-object2/utest/object2_utest_main.cpp new file mode 100644 index 00000000..d868f233 --- /dev/null +++ b/xo-object2/utest/object2_utest_main.cpp @@ -0,0 +1,24 @@ +/* file object2_utest_main.cpp */ + +#include + +#define CATCH_CONFIG_RUNNER +#include "catch2/catch.hpp" + +int +main(int argc, char* argv[]) +{ + using xo::Subsystem; + + // Your custom initialization code here + Subsystem::initialize_all(); + + // Run Catch2's test session + int result = Catch::Session().run(argc, argv); + + // cleanup here, if any + + return result; +} + +/* end object2_utest_main.cpp */