diff --git a/CMakeLists.txt b/CMakeLists.txt index c762fbfa..92d4b9e7 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -29,14 +29,32 @@ xo_add_genfacet( # ---------------------------------------------------------------- +# note: manual target; generated code committed to git +xo_add_genfacetimpl( + TARGET xo-numeric-facetimpl-numeric-float + FACET_PKG xo_numeric + FACET Numeric + REPR Float + INPUT idl/INumeric_DFloat.json5 +) + +# note: manual target; generated code committed to git +xo_add_genfacetimpl( + TARGET xo-numeric-facetimpl-numeric-integer + FACET_PKG xo_numeric + FACET Numeric + REPR Integer + INPUT idl/INumeric_DInteger.json5 +) + +# ---------------------------------------------------------------- + xo_add_genfacet_all(xo-numeric-genfacet-all) # ---------------------------------------------------------------- -#add_subdirectory(src/numeric) # NOTE: will need cmake export here -#add_subdirectory(utest) +add_subdirectory(src/numeric) +add_subdirectory(utest) # ---------------------------------------------------------------- # cmake export - - diff --git a/NumericDispatch.hpp b/NumericDispatch.hpp deleted file mode 100644 index a312c1c1..00000000 --- a/NumericDispatch.hpp +++ /dev/null @@ -1,44 +0,0 @@ -/** @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_numericConfig.cmake.in b/cmake/xo_numericConfig.cmake.in index 4155d92e..a38ab389 100644 --- a/cmake/xo_numericConfig.cmake.in +++ b/cmake/xo_numericConfig.cmake.in @@ -7,7 +7,7 @@ include(CMakeFindDependencyMacro) # in CMakeLists.txt # #find_dependency(xo_gc) -find_dependency(xo_facet) +find_dependency(xo_procedure2) find_dependency(subsys) #find_dependency(indentlog) diff --git a/idl/INumeric_DFloat.json5 b/idl/INumeric_DFloat.json5 new file mode 100644 index 00000000..6b269c6d --- /dev/null +++ b/idl/INumeric_DFloat.json5 @@ -0,0 +1,18 @@ +{ + mode: "implementation", + output_cpp_dir: "src/numeric", + output_hpp_dir: "include/xo/numeric", + output_impl_subdir: "float", + includes: [ +// "", +// "" + ], + local_types: [ ], + namespace1: "xo", + namespace2: "scm", + facet_idl: "idl/Numeric.json5", + brief: "provide ANumeric interface for DFloat", + using_doxygen: true, + repr: "DFloat", + doc: [ "implement ANumeric for DFloat" ], +} diff --git a/idl/INumeric_DInteger.json5 b/idl/INumeric_DInteger.json5 new file mode 100644 index 00000000..5c478c12 --- /dev/null +++ b/idl/INumeric_DInteger.json5 @@ -0,0 +1,18 @@ +{ + mode: "implementation", + output_cpp_dir: "src/numeric", + output_hpp_dir: "include/xo/numeric", + output_impl_subdir: "integer", + includes: [ +// "", +// "" + ], + local_types: [ ], + namespace1: "xo", + namespace2: "scm", + facet_idl: "idl/Numeric.json5", + brief: "provide ANumeric interface for DInteger", + using_doxygen: true, + repr: "DInteger", + doc: [ "implement ANumeric for DInteger" ], +} diff --git a/include/xo/numeric/FloatIntegerOps.hpp b/include/xo/numeric/FloatIntegerOps.hpp new file mode 100644 index 00000000..97a2c3f6 --- /dev/null +++ b/include/xo/numeric/FloatIntegerOps.hpp @@ -0,0 +1,42 @@ +/** @file FloatIntegerOps.hpp + * + * @author Roland Conybeare, Feb 2026 + **/ + +#pragma once + +#include "Numeric.hpp" +#include +#include +#include + + +namespace xo { + namespace scm { + + class FloatIntegerOps { + public: + using AGCObject = xo::mm::AGCObject; + + public: + static obj multiply(obj rcx, + DFloat * x, DInteger * y); + static obj divide(obj rcx, + DFloat * x, DInteger * y); + }; + + class IntegerFloatOps { + public: + using AGCObject = xo::mm::AGCObject; + + public: + static obj multiply(obj rcx, + DInteger * x, DFloat * y); + static obj divide(obj rcx, + DInteger * x, DFloat * y); + }; + + } +} + +/* end FloatIntegerOps.hpp */ diff --git a/include/xo/numeric/FloatOps.hpp b/include/xo/numeric/FloatOps.hpp new file mode 100644 index 00000000..c3a2c288 --- /dev/null +++ b/include/xo/numeric/FloatOps.hpp @@ -0,0 +1,30 @@ +/** @file FloatOps.hpp + * + * @author Roland Conybeare, Feb 2026 + **/ + +#pragma once + +#include "Numeric.hpp" +#include +#include + + +namespace xo { + namespace scm { + + class FloatOps { + public: + using AGCObject = xo::mm::AGCObject; + + public: + static obj multiply(obj rcx, + DFloat * x, DFloat * y); + static obj divide(obj rcx, + DFloat * x, DFloat * y); + }; + + } +} + +/* end FloatOps.hpp */ diff --git a/include/xo/numeric/IntegerOps.hpp b/include/xo/numeric/IntegerOps.hpp new file mode 100644 index 00000000..4f9138de --- /dev/null +++ b/include/xo/numeric/IntegerOps.hpp @@ -0,0 +1,31 @@ +/** @file IntegerOps.hpp + * + * @author Roland Conybeare, Feb 2026 + **/ + +#pragma once + +#include "Numeric.hpp" +#include +#include + +namespace xo { + namespace scm { + + class IntegerOps { + public: + using AGCObject = xo::mm::AGCObject; + + public: + static obj multiply(obj rcx, + DInteger * x, DInteger * y); + + static obj divide(obj rcx, + DInteger * x, DInteger * y); + + }; + + } +} + +/* end IntegerOps.hpp */ diff --git a/include/xo/numeric/NumericDispatch.hpp b/include/xo/numeric/NumericDispatch.hpp index 45f12a75..5174430e 100644 --- a/include/xo/numeric/NumericDispatch.hpp +++ b/include/xo/numeric/NumericDispatch.hpp @@ -5,13 +5,93 @@ #pragma once +#include "NumericOps.hpp" +#include +#include +#include +#include + namespace xo { namespace scm { + /** Runtime polymoprhic multimethod dispatch. + * Hash on argument types to get function table + **/ class NumericDispatch { public: + //using AAllocator = xo::mm::AAllocator; + using AGCObject = xo::mm::AGCObject; + using MemorySizeVisitor = xo::mm::MemorySizeVisitor; + using typeseq = xo::reflect::typeseq; + using KeyType = std::pair; + using MappedType = AnonymizedNumericOps; - + /** hash function for key_type **/ + struct KeyHash { + + std::size_t operator()(const KeyType & 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 << 7); + } + + }; + + using MapType = xo::map::DArenaHashMap>; + + public: + NumericDispatch(uint32_t hint_max_capacity) + : dispatch_{"numeric-dispatch", + hint_max_capacity, + false /*!debug_flag*/} {} + + /** @p hint_max_capacity only honored the first time instance() + * is called. + **/ + static NumericDispatch & instance(uint32_t hint_max_capacity = 64) { + static NumericDispatch s_instance(hint_max_capacity); + return s_instance; + } + + /** multiply w/ runtime polymorphism (double-dispatch) + **/ + static obj multiply(obj rcx, + obj x, + obj y); + + /** divide w/ runtime polymorphism (double-dispatch) + **/ + static obj divide(obj rcx, + obj x, + obj y); + + /** report memory use for owned arenas to @p visitor **/ + void visit_pools(const MemorySizeVisitor & visitor); + + /** Use: + * Need to have overload + * multiply(obj, DRepr1, DRepr2) -> obj + * available + **/ + template + void register_impl(typename NumericOps::BinaryOp_Impl mul_fn, + typename NumericOps::BinaryOp_Impl div_fn) { + + KeyType key(typeseq::id().seqno(), + typeseq::id().seqno()); + + // note: copying op table so they're in proximity + this->dispatch_[key] = NumericOps::make(mul_fn, div_fn); + } + + private: + /** 2d dispatch for arithmetic **/ + MapType dispatch_; }; } /*namespace scm*/ diff --git a/include/xo/numeric/NumericOps.hpp b/include/xo/numeric/NumericOps.hpp index 720d65db..4e900534 100644 --- a/include/xo/numeric/NumericOps.hpp +++ b/include/xo/numeric/NumericOps.hpp @@ -1,44 +1,52 @@ /** @file NumericOps.hpp -* + * * @author Roland Conybeare, Feb 2026 **/ #pragma once -#include "Numeric.hpp" +#include +#include +#include +#include namespace xo { namespace scm { - - class INumericOps { + class AnonymizedNumericOps { public: - using BinaryOp1 = obj (*)(obj mm, void * x, void * y); + using ARuntimeContext = xo::scm::ARuntimeContext; + using AGCObject = xo::mm::AGCObject; + using BinaryOp = obj (*)(obj mm, void * x, void * y); public: - explicit INumericOp9s(BinaryOp1 multiply) : multiply_{multiply} {} + /** note: null ctor load-bearing for membership in DArenaHashTable **/ + AnonymizedNumericOps() = default; + /** @p multiply to multiply (x,y); allocate from mm **/ + explicit AnonymizedNumericOps(BinaryOp multiply, + BinaryOp divide) + : multiply_{multiply}, divide_{divide} {} - /** multiply (x,y); allocate from mm **/ - BinaryOp1 multiply_; + BinaryOp multiply_ = nullptr; + BinaryOp divide_ = nullptr; }; - /** Convenience template. To use, provide implementation - * for - * _multiply() ... - * - **/ template - class NumericOps : public INumericOps { + class NumericOps { public: - using BinaryOp1_Impl = obj (*)(obj mm, DRepr1 * x, DRepr2 * y); + using ARuntimeContext = xo::scm::ARuntimeContext; + using AGCObject = xo::mm::AGCObject; + using BinaryOp_Impl = obj (*)(obj rcx, DRepr1 * x, DRepr2 * y); + using BinaryOp_Anon = AnonymizedNumericOps::BinaryOp; public: - explicit NumericOps(BinaryOp1_Impl multiply) - : INumericOps(reinterpret_cast(multiply)) - {} + static AnonymizedNumericOps make(BinaryOp_Impl multiply, + BinaryOp_Impl divide) { + return AnonymizedNumericOps(reinterpret_cast(multiply), + reinterpret_cast(divide)); + } }; } /*namespace scm*/ } /*namespace xo*/ /* end NumericOps.hpp */ - diff --git a/include/xo/numeric/NumericPrimitives.hpp b/include/xo/numeric/NumericPrimitives.hpp new file mode 100644 index 00000000..376f94b9 --- /dev/null +++ b/include/xo/numeric/NumericPrimitives.hpp @@ -0,0 +1,23 @@ +/** @file NumericDispatch.hpp + * + * @author Roland Conybeare, Feb 2026 + **/ + +#pragma once + +#include + +namespace xo { + namespace scm { + + /** @brief primitives using multidispatch + **/ + class NumericPrimitives { + public: + /** poly divide **/ + static DPrimitive_gco_2_gco_gco s_div_gco_gco_pm; + }; + } +} + +/* end NumericDispatch.hpp */ diff --git a/include/xo/numeric/float/INumeric_DFloat.hpp b/include/xo/numeric/float/INumeric_DFloat.hpp new file mode 100644 index 00000000..8e88438e --- /dev/null +++ b/include/xo/numeric/float/INumeric_DFloat.hpp @@ -0,0 +1,56 @@ +/** @file INumeric_DFloat.hpp + * + * Generated automagically from ingredients: + * 1. code generator: + * [xo-facet/codegen/genfacet] + * arguments: + * --input [idl/INumeric_DFloat.json5] + * 2. jinja2 template for abstract facet .hpp file: + * [iface_facet_repr.hpp.j2] + * 3. idl for facet methods + * [idl/INumeric_DFloat.json5] + **/ + +#pragma once + +#include "Numeric.hpp" +#include "DFloat.hpp" + +namespace xo { namespace scm { class INumeric_DFloat; } } + +namespace xo { + namespace facet { + template <> + struct FacetImplementation + { + using ImplType = xo::scm::INumeric_Xfer + ; + }; + } +} + +namespace xo { + namespace scm { + /** @class INumeric_DFloat + **/ + class INumeric_DFloat { + public: + /** @defgroup scm-numeric-dfloat-type-traits **/ + ///@{ + using Copaque = xo::scm::ANumeric::Copaque; + using Opaque = xo::scm::ANumeric::Opaque; + ///@} + /** @defgroup scm-numeric-dfloat-methods **/ + ///@{ + // const methods + + // non-const methods + ///@} + }; + + } /*namespace scm*/ +} /*namespace xo*/ + +/* end */ \ No newline at end of file diff --git a/include/xo/numeric/init_numeric.hpp b/include/xo/numeric/init_numeric.hpp new file mode 100644 index 00000000..c3f1cf19 --- /dev/null +++ b/include/xo/numeric/init_numeric.hpp @@ -0,0 +1,21 @@ +/** @file init_numeric.hpp + * + * @author Roland Conybeare, Feb 2026 + **/ + +#pragma once + +#include + +namespace xo { + /* tag to represent the xo-numeric/ subsystem within ordered initialization */ + enum S_numeric_tag {}; + + template <> + struct InitSubsys { + static void init(); + static InitEvidence require(); + }; +} + +/* end init_numeric.hpp */ diff --git a/include/xo/numeric/integer/INumeric_DInteger.hpp b/include/xo/numeric/integer/INumeric_DInteger.hpp new file mode 100644 index 00000000..ca530949 --- /dev/null +++ b/include/xo/numeric/integer/INumeric_DInteger.hpp @@ -0,0 +1,56 @@ +/** @file INumeric_DInteger.hpp + * + * Generated automagically from ingredients: + * 1. code generator: + * [xo-facet/codegen/genfacet] + * arguments: + * --input [idl/INumeric_DInteger.json5] + * 2. jinja2 template for abstract facet .hpp file: + * [iface_facet_repr.hpp.j2] + * 3. idl for facet methods + * [idl/INumeric_DInteger.json5] + **/ + +#pragma once + +#include "Numeric.hpp" +#include "DInteger.hpp" + +namespace xo { namespace scm { class INumeric_DInteger; } } + +namespace xo { + namespace facet { + template <> + struct FacetImplementation + { + using ImplType = xo::scm::INumeric_Xfer + ; + }; + } +} + +namespace xo { + namespace scm { + /** @class INumeric_DInteger + **/ + class INumeric_DInteger { + public: + /** @defgroup scm-numeric-dinteger-type-traits **/ + ///@{ + using Copaque = xo::scm::ANumeric::Copaque; + using Opaque = xo::scm::ANumeric::Opaque; + ///@} + /** @defgroup scm-numeric-dinteger-methods **/ + ///@{ + // const methods + + // non-const methods + ///@} + }; + + } /*namespace scm*/ +} /*namespace xo*/ + +/* end */ \ No newline at end of file diff --git a/include/xo/numeric/numeric_register_facets.hpp b/include/xo/numeric/numeric_register_facets.hpp new file mode 100644 index 00000000..7beeb10e --- /dev/null +++ b/include/xo/numeric/numeric_register_facets.hpp @@ -0,0 +1,16 @@ +/** @file numeric_register_facets.hpp + * + * @author Roland Conybeare, Feb 2026 + **/ + +#pragma once + +namespace xo { + namespace scm { + /** Setup numeric facet dispatch **/ + bool numeric_register_facets(); + + } +} + +/* end numeric_register_facets.hpp */ diff --git a/src/numeric/CMakeLists.txt b/src/numeric/CMakeLists.txt new file mode 100644 index 00000000..4d2b4345 --- /dev/null +++ b/src/numeric/CMakeLists.txt @@ -0,0 +1,25 @@ +# numeric/CMakeLists.txt + +set(SELF_LIB xo_numeric) +set(SELF_SRCS + init_numeric.cpp + numeric_register_facets.cpp + NumericPrimitives.cpp + NumericDispatch.cpp + INumeric_Any.cpp + FloatIntegerOps.cpp + FloatOps.cpp + IntegerOps.cpp +) + +xo_add_shared_library4(${SELF_LIB} ${PROJECT_NAME}Targets ${PROJECT_VERSION} 1 ${SELF_SRCS}) +xo_dependency(${SELF_LIB} xo_procedure2) +xo_dependency(${SELF_LIB} subsys) + +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) diff --git a/src/numeric/FloatIntegerOps.cpp b/src/numeric/FloatIntegerOps.cpp new file mode 100644 index 00000000..65a106ab --- /dev/null +++ b/src/numeric/FloatIntegerOps.cpp @@ -0,0 +1,48 @@ +/** @file FloatIntegerOps.cp + * + * @author Roland Conybeare, Feb 2206 + **/ + +#include "FloatIntegerOps.hpp" +#include "float/INumeric_DFloat.hpp" + +namespace xo { + using xo::mm::AGCObject; + + namespace scm { + + // ----- Float op Integer ----- + + obj + FloatIntegerOps::multiply(obj rcx, + DFloat * x, DInteger * y) + { + return DFloat::box(rcx.allocator(), x->value() * y->value()); + } + + obj + FloatIntegerOps::divide(obj rcx, + DFloat * x, DInteger * y) + { + return DFloat::box(rcx.allocator(), x->value() / y->value()); + } + + // ----- Integer op Float ----- + + obj + IntegerFloatOps::multiply(obj rcx, + DInteger * x, DFloat * y) + { + return DFloat::box(rcx.allocator(), x->value() * y->value()); + } + + obj + IntegerFloatOps::divide(obj rcx, + DInteger * x, DFloat * y) + { + return DFloat::box(rcx.allocator(), x->value() / y->value()); + } + } +} + +/* end FloatIntegerOps.cpp */ diff --git a/src/numeric/FloatOps.cpp b/src/numeric/FloatOps.cpp new file mode 100644 index 00000000..9db149b9 --- /dev/null +++ b/src/numeric/FloatOps.cpp @@ -0,0 +1,31 @@ +/** @file FloatOps.cp + * + * @author Roland Conybeare, Feb 2206 + **/ + +#include "FloatOps.hpp" +#include "float/INumeric_DFloat.hpp" + +namespace xo { + using xo::mm::AGCObject; + + namespace scm { + + obj + FloatOps::multiply(obj rcx, + DFloat * x, DFloat * y) + { + return DFloat::box(rcx.allocator(), x->value() * y->value()); + } + + obj + FloatOps::divide(obj rcx, + DFloat * x, DFloat * y) + { + return DFloat::box(rcx.allocator(), x->value() / y->value()); + } + + } +} + +/* end FloatOps.cpp */ diff --git a/src/numeric/INumeric_DFloat.cpp b/src/numeric/INumeric_DFloat.cpp new file mode 100644 index 00000000..4024dc04 --- /dev/null +++ b/src/numeric/INumeric_DFloat.cpp @@ -0,0 +1,22 @@ +/** @file INumeric_DFloat.cpp + * + * Generated automagically from ingredients: + * 1. code generator: + * [xo-facet/codegen/genfacet] + * arguments: + * --input [idl/INumeric_DFloat.json5] + * 2. jinja2 template for abstract facet .hpp file: + * [iface_facet_any.hpp.j2] + * 3. idl for facet methods + * [idl/INumeric_DFloat.json5] +**/ + +#include "float/INumeric_DFloat.hpp" + +namespace xo { + namespace scm { + + } /*namespace scm*/ +} /*namespace xo*/ + +/* end INumeric_DFloat.cpp */ diff --git a/src/numeric/INumeric_DInteger.cpp b/src/numeric/INumeric_DInteger.cpp new file mode 100644 index 00000000..a4ae6a12 --- /dev/null +++ b/src/numeric/INumeric_DInteger.cpp @@ -0,0 +1,22 @@ +/** @file INumeric_DInteger.cpp + * + * Generated automagically from ingredients: + * 1. code generator: + * [xo-facet/codegen/genfacet] + * arguments: + * --input [idl/INumeric_DInteger.json5] + * 2. jinja2 template for abstract facet .hpp file: + * [iface_facet_any.hpp.j2] + * 3. idl for facet methods + * [idl/INumeric_DInteger.json5] +**/ + +#include "integer/INumeric_DInteger.hpp" + +namespace xo { + namespace scm { + + } /*namespace scm*/ +} /*namespace xo*/ + +/* end INumeric_DInteger.cpp */ diff --git a/src/numeric/IntegerOps.cpp b/src/numeric/IntegerOps.cpp new file mode 100644 index 00000000..c8322266 --- /dev/null +++ b/src/numeric/IntegerOps.cpp @@ -0,0 +1,31 @@ +/** @file IntegerOps.cpp + * + * @author Roland Conybeare, Feb 2026 + **/ + +#include "IntegerOps.hpp" +#include "integer/INumeric_DInteger.hpp" + +namespace xo { + using xo::mm::AGCObject; + + namespace scm { + + obj + IntegerOps::multiply(obj rcx, + DInteger * x, DInteger * y) + { + return DInteger::box(rcx.allocator(), x->value() * y->value()); + } + + obj + IntegerOps::divide(obj rcx, + DInteger * x, DInteger * y) + { + return DInteger::box(rcx.allocator(), x->value() / y->value()); + } + + } +} + +/* end IntegerOps.cpp */ diff --git a/src/numeric/NumericDispatch.cpp b/src/numeric/NumericDispatch.cpp new file mode 100644 index 00000000..bfc65586 --- /dev/null +++ b/src/numeric/NumericDispatch.cpp @@ -0,0 +1,59 @@ +/** @file NumericDispatch.cpp + * + * @author Roland Conybeare, Feb 2026 + **/ + +#include "NumericDispatch.hpp" +#include + +namespace xo { + using xo::mm::AGCObject; + + namespace scm { + + void + NumericDispatch::visit_pools(const MemorySizeVisitor & visitor) + { + dispatch_.visit_pools(visitor); + } + + obj + NumericDispatch::multiply(obj rcx, + obj x, + obj y) + { + KeyType key(x._typeseq(), y._typeseq()); + + auto target_fn + = NumericDispatch::instance().dispatch_[key].multiply_; + + return (*target_fn)(rcx, x.data(), y.data()); + } + + obj + NumericDispatch::divide(obj rcx, + obj x, + obj y) + { + scope log(XO_DEBUG(true)); + + KeyType key(x._typeseq(), y._typeseq()); + + log && log(xtag("x.tseq", x._typeseq().seqno()), + xtag("y.tseq", y._typeseq().seqno())); + + auto target_fn + = NumericDispatch::instance().dispatch_[key].divide_; + + log && log(xtag("target_fn", target_fn)); + + assert(target_fn); + + return (*target_fn)(rcx, x.data(), y.data()); + } + + + } /*namespace scm*/ +} /*namespace xo*/ + +/* end NumericDispatch.cpp **/ diff --git a/src/numeric/NumericPrimitives.cpp b/src/numeric/NumericPrimitives.cpp new file mode 100644 index 00000000..5666a751 --- /dev/null +++ b/src/numeric/NumericPrimitives.cpp @@ -0,0 +1,22 @@ +/** @file NumericPrimitives.cpp + * + * @author Roland Conybeare, Feb 2026 + **/ + +#include "NumericPrimitives.hpp" +#include "NumericDispatch.hpp" + +namespace xo { + using xo::mm::AGCObject; + + namespace scm { + + DPrimitive_gco_2_gco_gco + NumericPrimitives::s_div_gco_gco_pm("_div", + &NumericDispatch::divide); + + + } /*namespace scm*/ +} /*namespace xo*/ + +/* end NumericDispatch.cpp */ diff --git a/src/numeric/init_numeric.cpp b/src/numeric/init_numeric.cpp new file mode 100644 index 00000000..1b205585 --- /dev/null +++ b/src/numeric/init_numeric.cpp @@ -0,0 +1,36 @@ +/** @file init_numeric.cpp + * + * @author Roland Conybeare, Feb 2026 + **/ + +#include "init_numeric.hpp" +#include +#include "Subsystem.hpp" +#include "numeric_register_facets.hpp" + +namespace xo { + using xo::scm::numeric_register_facets; + + void + InitSubsys::init() + { + numeric_register_facets(); + } + + InitEvidence + InitSubsys::require() + { + InitEvidence retval; + + /* direct subsystem deps for xo-numeric/ */ + retval ^= InitSubsys::require(); + + /* xo-numeric/'s own initialization code */ + retval ^= Subsystem::provide("numeric", &init); + + return retval; + } + +} /*namespace xo*/ + +/* end init_numeric.cpp */ diff --git a/src/numeric/numeric_register_facets.cpp b/src/numeric/numeric_register_facets.cpp new file mode 100644 index 00000000..3e2d94a5 --- /dev/null +++ b/src/numeric/numeric_register_facets.cpp @@ -0,0 +1,61 @@ +/** @file numeric_register_facets.cpp + * + * @author Roland Conybeare, Feb 2026 + **/ + +#include "numeric_register_facets.hpp" +#include "NumericDispatch.hpp" +#include "Numeric.hpp" + +#include "FloatIntegerOps.hpp" +#include "FloatOps.hpp" +#include "float/INumeric_DFloat.hpp" + +#include "IntegerOps.hpp" +#include "integer/INumeric_DInteger.hpp" + +#include +#include + +#include +#include +#include + +namespace xo { + using xo::facet::FacetRegistry; + using xo::reflect::typeseq; + + namespace scm { + + bool + numeric_register_facets() + { + scope log(XO_DEBUG(true)); + + FacetRegistry::register_impl(); + + NumericDispatch::instance().register_impl + (&FloatOps::multiply, + &FloatOps::divide); + + NumericDispatch::instance().register_impl + (&FloatIntegerOps::multiply, + &FloatIntegerOps::divide); + + NumericDispatch::instance().register_impl + (&IntegerFloatOps::multiply, + &IntegerFloatOps::divide); + + NumericDispatch::instance().register_impl + (&IntegerOps::multiply, + &IntegerOps::divide); + + log && log(xtag("ANumeric.tseq", typeseq::id())); + + return true; + } + + } /*namespace scm*/ +} /*namespace xo*/ + +/* end numeric_register_facets.cpp */ diff --git a/utest/CMakeLists.txt b/utest/CMakeLists.txt new file mode 100644 index 00000000..8b714e4a --- /dev/null +++ b/utest/CMakeLists.txt @@ -0,0 +1,12 @@ +# built unittest xo-numeric/utest + +set(UTEST_EXE utest.numeric) +set(UTEST_SRCS + numeric_utest_main.cpp + Numeric.test.cpp +) + +xo_add_utest_executable(${UTEST_EXE} ${UTEST_SRCS}) +xo_self_dependency(${UTEST_EXE} xo_numeric) +#xo_dependency(${UTEST_EXE} randomgen) +xo_external_target_dependency(${UTEST_EXE} Catch2 Catch2::Catch2) diff --git a/utest/Numeric.test.cpp b/utest/Numeric.test.cpp new file mode 100644 index 00000000..53a44058 --- /dev/null +++ b/utest/Numeric.test.cpp @@ -0,0 +1,76 @@ +/** @file Numeric.test.cpp + * + * @author Roland Conybeare, Feb 2026 + **/ + +#include "init_numeric.hpp" +#include "NumericDispatch.hpp" +#include +#include +#include + +namespace xo { + using xo::scm::NumericDispatch; + //using xo::mm::AAllocator; + using xo::mm::DArena; + using xo::mm::ArenaConfig;; + using xo::mm::MemorySizeInfo; + using xo::facet::FacetRegistry; + using xo::facet::TypeRegistry; + //using xo::facet::with_facet; + //using xo::facet::obj; + + namespace ut { + + namespace { + struct Fixture { + explicit Fixture(const std::string & testname, + std::size_t aux_arena_size = 16 * 1024) + : aux_arena_( + ArenaConfig().with_name(testname).with_size(aux_arena_size)) + {} + + + bool log_memory_layout(scope * p_log) { + auto visitor = [p_log](const MemorySizeInfo & info) { + *p_log && (*p_log)(xtag("resource", info.resource_name_), + xtag("used", info.used_), + xtag("alloc", info.allocated_), + xtag("commit", info.committed_), + xtag("resv", info.reserved_)); + }; + + aux_arena_.visit_pools(visitor); + TypeRegistry::instance().visit_pools(visitor); + FacetRegistry::instance().visit_pools(visitor); + NumericDispatch::instance().visit_pools(visitor); + + return true; + } + + DArena aux_arena_; + }; + } /*namespace*/ + + static InitEvidence s_init = (InitSubsys::require()); + + TEST_CASE("Numeric-init" "[numeric]") + { + const auto & testname = Catch::getResultCapture().getCurrentTestName(); + + constexpr bool c_debug_flag = true; + scope log(XO_DEBUG(c_debug_flag), xtag("test", testname)); + + Fixture fixture(testname); + { + // real purpose: ensure s_init sutvives static linking + REQUIRE(s_init.evidence()); + } + + log && fixture.log_memory_layout(&log); + } + + } /*namespace ut*/ +} /*namespace xo*/ + +/* end Numeric.test.cpp */ diff --git a/utest/numeric_utest_main.cpp b/utest/numeric_utest_main.cpp new file mode 100644 index 00000000..96d5d0b6 --- /dev/null +++ b/utest/numeric_utest_main.cpp @@ -0,0 +1,24 @@ +/* file numeric_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 numeric_utest_main.cpp */