/** @file NumericDispatch.hpp * * @author Roland Conybeare, Feb 2026 **/ #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; using BinaryOp = AnonymizedNumericOps::BinaryOp; /** 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; } /** multi-dispatch driver. * Invoke @p member_ptr in AnonymizedNumericOps **/ static obj dispatch(obj rcx, const char * caller, const char * error_headline, BinaryOp AnonymizedNumericOps::* member_ptr, obj x, obj y); /** 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); /** add w/ runtime polymorphism (double-dispatch) **/ static obj add(obj rcx, obj x, obj y); /** subtract w/ runtime polymorphism (double-dispatch) **/ static obj subtract(obj rcx, obj x, obj y); /** compare two numeric values for equality **/ static obj cmp_equal(obj rcx, obj x, obj y); /** compare two numeric values for inequality **/ static obj cmp_notequal(obj rcx, obj x, obj y); /** compare two numeric values for inequality **/ static obj cmp_less(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, typename NumericOps::BinaryOp_Impl add_fn, typename NumericOps::BinaryOp_Impl sub_fn, typename NumericOps::BinaryOp_Impl cmpeq_fn, typename NumericOps::BinaryOp_Impl cmpne_fn, typename NumericOps::BinaryOp_Impl cmplt_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, add_fn, sub_fn, cmpeq_fn, cmpne_fn, cmplt_fn); } private: /** 2d dispatch for arithmetic **/ MapType dispatch_; }; } /*namespace scm*/ } /*namespace xo*/ /* end NumericDispatch.hpp */