From b8fd0873191f5071ca2a8724ba92439edd0c0a37 Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Wed, 18 Feb 2026 13:44:57 -0500 Subject: [PATCH] + xo-numeric/ [WIP] --- CMakeLists.txt | 42 ++++++++++ NumericDispatch.hpp | 44 +++++++++++ cmake/xo-bootstrap-macros.cmake | 41 ++++++++++ cmake/xo_numericConfig.cmake.in | 15 ++++ idl/Numeric.json5 | 75 ++++++++++++++++++ include/xo/numeric/Numeric.hpp | 22 ++++++ include/xo/numeric/NumericDispatch.hpp | 20 +++++ include/xo/numeric/NumericOps.hpp | 44 +++++++++++ include/xo/numeric/detail/ANumeric.hpp | 70 +++++++++++++++++ include/xo/numeric/detail/INumeric_Any.hpp | 87 +++++++++++++++++++++ include/xo/numeric/detail/INumeric_Xfer.hpp | 79 +++++++++++++++++++ include/xo/numeric/detail/RNumeric.hpp | 81 +++++++++++++++++++ src/numeric/INumeric_Any.cpp | 41 ++++++++++ 13 files changed, 661 insertions(+) create mode 100644 CMakeLists.txt create mode 100644 NumericDispatch.hpp create mode 100644 cmake/xo-bootstrap-macros.cmake create mode 100644 cmake/xo_numericConfig.cmake.in create mode 100644 idl/Numeric.json5 create mode 100644 include/xo/numeric/Numeric.hpp create mode 100644 include/xo/numeric/NumericDispatch.hpp create mode 100644 include/xo/numeric/NumericOps.hpp create mode 100644 include/xo/numeric/detail/ANumeric.hpp create mode 100644 include/xo/numeric/detail/INumeric_Any.hpp create mode 100644 include/xo/numeric/detail/INumeric_Xfer.hpp create mode 100644 include/xo/numeric/detail/RNumeric.hpp create mode 100644 src/numeric/INumeric_Any.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 00000000..c762fbfa --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,42 @@ +# xo-numeric/CMakeLists.txt + +cmake_minimum_required(VERSION 3.10) + +project(xo_numeric VERSION 1.0) +enable_language(CXX) + +include(GNUInstallDirs) +include(cmake/xo-bootstrap-macros.cmake) + +xo_cxx_toplevel_options3() + +# ---------------------------------------------------------------- +# c++ settings + +# one-time project-specific c++ flags. usually empty +set(PROJECT_CXX_FLAGS "") +add_definitions(${PROJECT_CXX_FLAGS}) + +# ---------------------------------------------------------------- +# output targets + +# note: manual target; generated code committed to git +xo_add_genfacet( + TARGET xo-numeric-facet-numeric + FACET Numeric + INPUT idl/Numeric.json5 + ) + +# ---------------------------------------------------------------- + +xo_add_genfacet_all(xo-numeric-genfacet-all) + +# ---------------------------------------------------------------- + +#add_subdirectory(src/numeric) # NOTE: will need cmake export here +#add_subdirectory(utest) + +# ---------------------------------------------------------------- +# cmake export + + diff --git a/NumericDispatch.hpp b/NumericDispatch.hpp new file mode 100644 index 00000000..a312c1c1 --- /dev/null +++ b/NumericDispatch.hpp @@ -0,0 +1,44 @@ +/** @file NumericDispatch.hpp + * + * @author Roland Conybeare, Feb 2026 + **/ + +#pragma once + +//#include // probably will need this at some point? +#include +#include + +namespace xo { + namespace scm { + + /** type-erased arithmetic dispatch. + **/ + struct NumericOps { + obj + }; + + class NumericDispatch { + public: + using KeyType = std::pair; + using MapType = xo::map::DArenaHashMap + + /** combine two typeseq's to get hash value **/ + struct KeyHash { + std::size_t operator()(const key_type & k) const noexcept { + // combine the two seqno values + std::size_t h1 = std::hash{}(k.first.seqno()); + std::size_t h2 = std::hash{}(k.second.seqno()); + return h1 ^ (h2 << 1); + } + }; + + + }; + + } /*namespace scm*/ +} /*namespace xo*/ + +/* end NumericDispqatch.hpp */ + + diff --git a/cmake/xo-bootstrap-macros.cmake b/cmake/xo-bootstrap-macros.cmake new file mode 100644 index 00000000..592272c0 --- /dev/null +++ b/cmake/xo-bootstrap-macros.cmake @@ -0,0 +1,41 @@ +# ---------------------------------------------------------------- +# 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 (XO_SUBMODULE_BUILD) + if (("${CMAKE_MODULE_PATH}" STREQUAL "") OR ("${CMAKE_MODULE_PATH}" STREQUAL prefix)) + # local version of xo-cmake macros + set(CMAKE_MODULE_PATH "${PROJECT_SOURCE_DIR}/xo-cmake/cmake") + message(STATUS "CMAKE_MODULE_PATH=${CMAKE_MODULE_PATH}") + endif() +else() + 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/cmake/xo_numericConfig.cmake.in b/cmake/xo_numericConfig.cmake.in new file mode 100644 index 00000000..4155d92e --- /dev/null +++ b/cmake/xo_numericConfig.cmake.in @@ -0,0 +1,15 @@ +@PACKAGE_INIT@ + +include(CMakeFindDependencyMacro) + +# note: changes to find_dependency() calls here +# must coordinate with xo_dependency() calls +# in CMakeLists.txt +# +#find_dependency(xo_gc) +find_dependency(xo_facet) +find_dependency(subsys) +#find_dependency(indentlog) + +include("${CMAKE_CURRENT_LIST_DIR}/@PROJECT_NAME@Targets.cmake") +check_required_components("@PROJECT_NAME@") diff --git a/idl/Numeric.json5 b/idl/Numeric.json5 new file mode 100644 index 00000000..4ddcc116 --- /dev/null +++ b/idl/Numeric.json5 @@ -0,0 +1,75 @@ +// can regenerate downstream .*pp files with either: +// cmake --build -- xo-numeric-facet-procedure +// cmake --build -- xo-numeric-genfacet-all + +{ + mode: "facet", + output_cpp_dir: "src/numeric", + output_hpp_dir: "include/xo/numeric", + output_impl_subdir: "detail", + // includes in ASyntaxStateMachine.hpp + includes: [ +// "\"RuntimeContext.hpp\"", +// "", + ], + // extra includes in Procedure.hpp, if any + user_hpp_includes: [ + ], + namespace1: "xo", + namespace2: "scm", + // text after includes, before ASyntaxStateMachine + pretext: [ + //"namespace xo { namespace scm { class ARuntimeContext; } }", + //"namespace xo { namespace scm { class DArray; } }", + ], + facet: "Numeric", + detail_subdir: "detail", + brief: "abstraction for a schematika numeric i.e. something that can participate in arithmetic", + using_doxygen: true, + doc: [ + "Abstraction for a schematika numeric" + ], + types: [ +// { +// name: "AGCObject", +// definition: "xo::mm::AGCObject", +// doc: [ "a gc-aware object" ], +// }, + // { name: string, doc: [ string ], definition: string }, + ], + const_methods: [ +// { +// name: "multiply", +// doc: [ "true iff procedure takes n arguments" ], +// return_type: "bool", +// args: [], +// const: true, +// noexcept: true, +// attributes: [] +// }, +// { +// name: "n_args", +// doc: ["number of arguments. -1 for n-ary" ], +// return_type: "std::int32_t", +// args: [], +// const: true, +// noexcept: true, +// attributes: [] +// } + ], + nonconst_methods: [ +// { +// name: "apply_nocheck", +// doc: ["invoke procedure; assume arguments satisfy type system" ], +// return_type: "obj", +// args: [ +// {type: "obj", name: "rcx"}, +// {type: "const DArray *", name: "args"}, +// ] +// } + ], + router_facet_explicit_content: [ + // this doesn't seem to show up anywhere + "static obj multiply(obj lhs, obj rhs);" + ], +} diff --git a/include/xo/numeric/Numeric.hpp b/include/xo/numeric/Numeric.hpp new file mode 100644 index 00000000..54f97420 --- /dev/null +++ b/include/xo/numeric/Numeric.hpp @@ -0,0 +1,22 @@ +/** @file Numeric.hpp + * + * Generated automagically from ingredients: + * 1. code generator: + * [xo-facet/codegen/genfacet] + * arguments: + * --input [idl/Numeric.json5] + * 2. jinja2 template for facet .hpp file: + * [facet.hpp.j2] + * 3. idl for facet methods + * [idl/Numeric.json5] + **/ + +#pragma once + +#include "detail/ANumeric.hpp" +#include "detail/INumeric_Any.hpp" +#include "detail/INumeric_Xfer.hpp" +#include "detail/RNumeric.hpp" + + +/* end Numeric.hpp */ diff --git a/include/xo/numeric/NumericDispatch.hpp b/include/xo/numeric/NumericDispatch.hpp new file mode 100644 index 00000000..45f12a75 --- /dev/null +++ b/include/xo/numeric/NumericDispatch.hpp @@ -0,0 +1,20 @@ +/** @file NumericDispatch.hpp + * + * @author Roland Conybeare, Feb 2026 + **/ + +#pragma once + +namespace xo { + namespace scm { + + class NumericDispatch { + public: + + + }; + + } /*namespace scm*/ +} /*namespace xo*/ + +/* end NumericDispatch.hpp */ diff --git a/include/xo/numeric/NumericOps.hpp b/include/xo/numeric/NumericOps.hpp new file mode 100644 index 00000000..720d65db --- /dev/null +++ b/include/xo/numeric/NumericOps.hpp @@ -0,0 +1,44 @@ +/** @file NumericOps.hpp +* + * @author Roland Conybeare, Feb 2026 + **/ + +#pragma once + +#include "Numeric.hpp" + +namespace xo { + namespace scm { + + class INumericOps { + public: + using BinaryOp1 = obj (*)(obj mm, void * x, void * y); + + public: + explicit INumericOp9s(BinaryOp1 multiply) : multiply_{multiply} {} + + /** multiply (x,y); allocate from mm **/ + BinaryOp1 multiply_; + }; + + /** Convenience template. To use, provide implementation + * for + * _multiply() ... + * + **/ + template + class NumericOps : public INumericOps { + public: + using BinaryOp1_Impl = obj (*)(obj mm, DRepr1 * x, DRepr2 * y); + + public: + explicit NumericOps(BinaryOp1_Impl multiply) + : INumericOps(reinterpret_cast(multiply)) + {} + }; + + } /*namespace scm*/ +} /*namespace xo*/ + +/* end NumericOps.hpp */ + diff --git a/include/xo/numeric/detail/ANumeric.hpp b/include/xo/numeric/detail/ANumeric.hpp new file mode 100644 index 00000000..bda27456 --- /dev/null +++ b/include/xo/numeric/detail/ANumeric.hpp @@ -0,0 +1,70 @@ +/** @file ANumeric.hpp + * + * Generated automagically from ingredients: + * 1. code generator: + * [xo-facet/codegen/genfacet] + * arguments: + * --input [idl/Numeric.json5] + * 2. jinja2 template for abstract facet .hpp file: + * [abstract_facet.hpp.j2] + * 3. idl for facet methods + * [idl/Numeric.json5] + **/ + +#pragma once + +// includes (via {facet_includes}) +#include +#include +#include + + +namespace xo { +namespace scm { + +using Copaque = const void *; +using Opaque = void *; + +/** +Abstraction for a schematika numeric +**/ +class ANumeric { +public: + /** @defgroup scm-numeric-type-traits **/ + ///@{ + // types + /** integer identifying a type **/ + using typeseq = xo::facet::typeseq; + using Copaque = const void *; + using Opaque = void *; + ///@} + + /** @defgroup scm-numeric-methods **/ + ///@{ + // const methods + /** 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; + + // nonconst methods + ///@} +}; /*ANumeric*/ + +/** Implementation INumeric_DRepr of ANumeric for state DRepr + * should provide a specialization: + * + * template <> + * struct xo::facet::FacetImplementation { + * using Impltype = INumeric_DRepr; + * }; + * + * then INumeric_ImplType --> INumeric_DRepr + **/ +template +using INumeric_ImplType = xo::facet::FacetImplType; + +} /*namespace scm*/ +} /*namespace xo*/ + +/* ANumeric.hpp */ diff --git a/include/xo/numeric/detail/INumeric_Any.hpp b/include/xo/numeric/detail/INumeric_Any.hpp new file mode 100644 index 00000000..0f5a03f2 --- /dev/null +++ b/include/xo/numeric/detail/INumeric_Any.hpp @@ -0,0 +1,87 @@ +/** @file INumeric_Any.hpp + * + * Generated automagically from ingredients: + * 1. code generator: + * [xo-facet/codegen/genfacet] + * arguments: + * --input [idl/Numeric.json5] + * 2. jinja2 template for abstract facet .hpp file: + * [iface_facet_any.hpp.j2] + * 3. idl for facet methods + * [idl/Numeric.json5] + **/ + +#pragma once + +#include "ANumeric.hpp" +#include + +namespace xo { namespace scm { class INumeric_Any; } } + +namespace xo { +namespace facet { + +template <> +struct FacetImplementation +{ + using ImplType = xo::scm::INumeric_Any; +}; + +} +} + +namespace xo { +namespace scm { + + /** @class INumeric_Any + * @brief ANumeric implementation for empty variant instance + **/ + class INumeric_Any : public ANumeric { + public: + /** @defgroup scm-numeric-any-type-traits **/ + ///@{ + + /** integer identifying a type **/ + using typeseq = xo::facet::typeseq; + + ///@} + /** @defgroup scm-numeric-any-methods **/ + ///@{ + + const ANumeric * iface() const { return std::launder(this); } + + // from ANumeric + + // builtin methods + typeseq _typeseq() const noexcept override { return s_typeseq; } + [[noreturn]] void _drop(Opaque) const noexcept override { _fatal(); } + + // const methods + + // nonconst methods + + ///@} + + private: + /** @defgraoup scm-numeric-any-private-methods **/ + ///@{ + + [[noreturn]] static void _fatal(); + + ///@} + + public: + /** @defgroup scm-numeric-any-member-vars **/ + ///@{ + + static typeseq s_typeseq; + static bool _valid; + + ///@} + }; + +} /*namespace scm */ +} /*namespace xo */ + +/* INumeric_Any.hpp */ diff --git a/include/xo/numeric/detail/INumeric_Xfer.hpp b/include/xo/numeric/detail/INumeric_Xfer.hpp new file mode 100644 index 00000000..c9cd2473 --- /dev/null +++ b/include/xo/numeric/detail/INumeric_Xfer.hpp @@ -0,0 +1,79 @@ +/** @file INumeric_Xfer.hpp + * + * Generated automagically from ingredients: + * 1. code generator: + * [xo-facet/codegen/genfacet] + * arguments: + * --input [idl/Numeric.json5] + * 2. jinja2 template for abstract facet .hpp file: + * [iface_facet_any.hpp.j2] + * 3. idl for facet methods + * [idl/Numeric.json5] + **/ + +#pragma once + + +namespace xo { +namespace scm { + /** @class INumeric_Xfer + **/ + template + class INumeric_Xfer : public ANumeric { + public: + /** @defgroup scm-numeric-xfer-type-traits **/ + ///@{ + /** actual implementation (not generated; often delegates to DRepr) **/ + using Impl = INumeric_DRepr; + /** integer identifying a type **/ + using typeseq = ANumeric::typeseq; + ///@} + + /** @defgroup scm-numeric-xfer-methods **/ + ///@{ + + static const DRepr & _dcast(Copaque d) { return *(const DRepr *)d; } + static DRepr & _dcast(Opaque d) { return *(DRepr *)d; } + + // from ANumeric + + // builtin methods + typeseq _typeseq() const noexcept override { return s_typeseq; } + void _drop(Opaque d) const noexcept override { _dcast(d).~DRepr(); } + + // const methods + + // non-const methods + + ///@} + + private: + using I = Impl; + + public: + /** @defgroup scm-numeric-xfer-member-vars **/ + ///@{ + + /** typeseq for template parameter DRepr **/ + static typeseq s_typeseq; + /** true iff satisfies facet implementation **/ + static bool _valid; + + ///@} + }; + + template + xo::facet::typeseq + INumeric_Xfer::s_typeseq + = xo::facet::typeseq::id(); + + template + bool + INumeric_Xfer::_valid + = xo::facet::valid_facet_implementation(); + +} /*namespace scm */ +} /*namespace xo*/ + +/* end INumeric_Xfer.hpp */ diff --git a/include/xo/numeric/detail/RNumeric.hpp b/include/xo/numeric/detail/RNumeric.hpp new file mode 100644 index 00000000..86cac666 --- /dev/null +++ b/include/xo/numeric/detail/RNumeric.hpp @@ -0,0 +1,81 @@ +/** @file RNumeric.hpp + * + * Generated automagically from ingredients: + * 1. code generator: + * [xo-facet/codegen/genfacet] + * arguments: + * --input [idl/Numeric.json5] + * 2. jinja2 template for abstract facet .hpp file: + * [iface_facet_any.hpp.j2] + * 3. idl for facet methods + * [idl/Numeric.json5] + **/ + +#pragma once + +#include "ANumeric.hpp" + +namespace xo { +namespace scm { + +/** @class RNumeric + **/ +template +class RNumeric : public Object { +private: + using O = Object; + +public: + /** @defgroup scm-numeric-router-type-traits **/ + ///@{ + using ObjectType = Object; + using DataPtr = Object::DataPtr; + using typeseq = xo::reflect::typeseq; + ///@} + + /** @defgroup scm-numeric-router-ctors **/ + ///@{ + RNumeric() {} + RNumeric(Object::DataPtr data) : Object{std::move(data)} {} + RNumeric(const ANumeric * iface, void * data) + requires std::is_same_v + : Object(iface, data) {} + + ///@} + /** @defgroup scm-numeric-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 + + // non-const methods (still const in router!) + + ///@} + /** @defgroup scm-numeric-member-vars **/ + ///@{ + + static bool _valid; + + ///@} +}; + +template +bool +RNumeric::_valid = xo::facet::valid_object_router(); + +} /*namespace scm*/ +} /*namespace xo*/ + +namespace xo { namespace facet { + template + struct RoutingFor { + using RoutingType = xo::scm::RNumeric; + }; +} } + +/* end RNumeric.hpp */ diff --git a/src/numeric/INumeric_Any.cpp b/src/numeric/INumeric_Any.cpp new file mode 100644 index 00000000..842ae275 --- /dev/null +++ b/src/numeric/INumeric_Any.cpp @@ -0,0 +1,41 @@ +/** @file INumeric_Any.cpp + * + **/ + +#include "detail/INumeric_Any.hpp" +#include + +namespace xo { +namespace scm { + +using xo::facet::DVariantPlaceholder; +using xo::facet::typeseq; +using xo::facet::valid_facet_implementation; + +void +INumeric_Any::_fatal() +{ + /* control here on uninitialized IAllocator_Any. + * Initialized instance will have specific implementation type + */ + std::cerr << "fatal" + << ": attempt to call uninitialized" + << " INumeric_Any method" + << std::endl; + std::terminate(); +} + +typeseq +INumeric_Any::s_typeseq = typeseq::id(); + +bool +INumeric_Any::_valid + = valid_facet_implementation(); + +// nonconst methods + + +} /*namespace scm*/ +} /*namespace xo*/ + +/* end INumeric_Any.cpp */