From 0ebb2afc159018e52e90ead35336d04fa8da3d92 Mon Sep 17 00:00:00 2001 From: Ichthyostega Date: Tue, 1 Sep 2026 19:47:31 +0200 Subject: [PATCH] Parameters: reorganise `TypeHandler` interface The original design (based on Alexandrescu) is more elegant, but has the downside to bloat the VTable size due to the mix-in arrangement used to generate the interface. The ongoing design has revealed a tight constraint on element size for the parameters; thus the change to a linearised inheritance chain. The overall purpose remains the same: the ability to generate a double-dispatch type conversion, so that the actual value type of the parameter can be treated as an implicit implementation detail. --- src/lib/par/domain.hpp | 58 ++++++------------ src/lib/par/provision.hpp | 42 ++++++++++++- tests/lib/par/parameter-domain-test.cpp | 22 +++---- wiki/thinkPad.ichthyo.mm | 78 ++++++++++++++++++++----- 4 files changed, 131 insertions(+), 69 deletions(-) diff --git a/src/lib/par/domain.hpp b/src/lib/par/domain.hpp index 7d2ee8a8c..8d702eb15 100644 --- a/src/lib/par/domain.hpp +++ b/src/lib/par/domain.hpp @@ -35,7 +35,6 @@ #include "lib/meta/typelist.hpp" -//#include "lib/meta/typelist-util.hpp" #include "lib/meta/generator.hpp" #include "lib/par/provision.hpp" #include "lib/meta/trait.hpp" @@ -54,52 +53,32 @@ namespace par { using std::numeric_limits; + /* ===== Type Handler Interface for generic parameter value access ===== */ - template - constexpr inline ValBuff& - asValBuff (X& something) - { - void* rawMem{& something}; - return * static_cast (rawMem); - } + class HandlerBase + : public Provision + { + public: + void extractAs(); + void conform(); + }; - template - constexpr inline ValBuff const& - asValBuff (X const& something) - { - void const * rawMem{& something}; - return * static_cast (rawMem); - } - - template - constexpr inline X& - asValue (ValBuff& storage) - { - void* rawMem{& storage}; - return * static_cast (rawMem); - } - - template - constexpr inline X const& - asValue (ValBuff const& storage) - { - void const * rawMem{& storage}; - return * static_cast (rawMem); - } - - - template + template class TypeHandler + : public PAR { public: virtual void extractAs (X& targetVal, ValBuff const& valBuff) =0; virtual void conform (ValBuff& targetBuff, X const& srcVal) =0; - + + using PAR::extractAs; + using PAR::conform; }; -// using lib::meta::typeseq; - + /** + * Fixed collection of elementary types supported in parameters + */ using BaseTypes = meta::Types; /** build a generic visitor interface for all types in list */ - using TypeHandlerInterface = meta::InstantiateForEach; + using TypeHandlerInterface = meta::InstantiateChained; /** @@ -302,8 +281,7 @@ _Pragma("GCC diagnostic pop") inline void BaseDomain::transferTo (ValBuff const& source, Domain& targetDomain, ValBuff& target) { - TypeHandler& typeHandler{targetDomain}; - typeHandler.conform (target, asValue (source)); + targetDomain.conform (target, asValue (source)); targetDomain.applyLimit (target); } diff --git a/src/lib/par/provision.hpp b/src/lib/par/provision.hpp index 611f141f1..5e20c1030 100644 --- a/src/lib/par/provision.hpp +++ b/src/lib/par/provision.hpp @@ -33,16 +33,54 @@ namespace par { using time::Time; + /** Marker for an opaque value buffer with + * undisclosed size and content type */ struct ValBuff { /*placeholder*/ }; + template + constexpr inline ValBuff& + asValBuff (X& something) + { + void* rawMem{& something}; + return * static_cast (rawMem); + } + + template + constexpr inline ValBuff const& + asValBuff (X const& something) + { + void const * rawMem{& something}; + return * static_cast (rawMem); + } + + template + constexpr inline X& + asValue (ValBuff& storage) + { + void* rawMem{& storage}; + return * static_cast (rawMem); + } + + template + constexpr inline X const& + asValue (ValBuff const& storage) + { + void const * rawMem{& storage}; + return * static_cast (rawMem); + } + + + + /** * Interface: access to a parameter's value, to adjust or evaluate automation. * Conceptually, the value is decomposed into a _base value_ and possibly a * time-controlled adjustment (automation). The base value can be retrieved * and assigned, while the current time-based value is the result of evaluation. - * Any parameter value is associated to a ParamType that defines the underlying - * value domain and possibly a scale with range limits and metric constraints. + * Any parameter value is implicitly associated with a Type that defines the + * underlying [value domain](\ref Domain) and possibly a \ref Scale that + * defines range limits and metric constraints. * @remark the value access and manipulation works _backwards_ from an implicit * value that is conceptually located _within_ this provision towards * an ValBuff for external access. The reason for this indirect diff --git a/tests/lib/par/parameter-domain-test.cpp b/tests/lib/par/parameter-domain-test.cpp index 57525c22e..27c88d784 100644 --- a/tests/lib/par/parameter-domain-test.cpp +++ b/tests/lib/par/parameter-domain-test.cpp @@ -184,7 +184,9 @@ namespace test{ verify_valueAccess() { BaseDomain domInt; -SHOW_EXPR(sizeof(BaseDomain)) ///////////////////////////////////////TODO this should be only one »slot«, but is actually quite large, due to using multiple inheritance in the Domain interface. /////OOO fix that! + CHECK (sizeof(BaseDomain) <= sizeof(void*)); // only the VTable + + // use the generic interface for access... Domain& dom{domInt}; int val = 1 + rani (1000); @@ -193,21 +195,18 @@ SHOW_EXPR(sizeof(BaseDomain)) ///////////////////////////////////////TODO t uint target1{0}; CHECK (not target1); - TypeHandler& hu{dom}; - hu.extractAs (target1, src); + dom.extractAs (target1, src); CHECK (target1 == uint(val)); float target2{0}; - TypeHandler& hf{dom}; - hf.extractAs (target2, src); + dom.extractAs (target2, src); CHECK (target2 == float(val)); // value clamped to target domain... val = _MIN; uint64_t target3{55}; - TypeHandler& hu64{dom}; - hu64.extractAs (target3, src); + dom.extractAs (target3, src); CHECK (target3 == _MIN); } @@ -229,20 +228,17 @@ SHOW_EXPR(sizeof(BaseDomain)) ///////////////////////////////////////TODO t ValBuff& target = asValBuff (val_in_buff); uint src1 = 1 + rani (1000); - TypeHandler& hu{dom}; - hu.conform (target, src1); + dom.conform (target, src1); CHECK (val_in_buff == int(src1)); double src2 = ranRange (1,100); CHECK (1 <= src2 and src2 < 100); - TypeHandler& hd{dom}; - hd.conform (target, src2); + dom.conform (target, src2); CHECK (val_in_buff == int(floor (src2))); // value clamped to target domain... auto mini = _MIN; - TypeHandler& h64{dom}; - h64.conform (target, mini); + dom.conform (target, mini); CHECK (val_in_buff == _MIN); } diff --git a/wiki/thinkPad.ichthyo.mm b/wiki/thinkPad.ichthyo.mm index 810a5f886..d4daa2fa9 100644 --- a/wiki/thinkPad.ichthyo.mm +++ b/wiki/thinkPad.ichthyo.mm @@ -82995,7 +82995,7 @@ - + @@ -83030,7 +83030,7 @@

- +
@@ -83090,11 +83090,11 @@ - - + + - + @@ -83103,6 +83103,7 @@

+
@@ -83117,7 +83118,7 @@
- + @@ -83164,10 +83165,23 @@ - - + + + + + + +

+ ...was nicht komplett durch den C++ - Standard gedeckt ist, jedoch aufgrund der Alignment-Contstraints und der Pflicht zur zero-overhead-Implementierung praktisch immer gegeben sein dürfte +

+ +
+
+ + +
@@ -84335,7 +84349,7 @@

- +
@@ -84354,8 +84368,16 @@
- - + + + + + + + + + + @@ -84371,7 +84393,16 @@ - + + + + +

+ bedeutet, es gibt eine Methode um eine Provision& zu bekommen, welche konsequenterweise dann über das Implementierungs-Interface erreichbar sein muß (da wir uns auf eine einfache Vererbungskette einschränken müssen) +

+ +
+
@@ -84402,12 +84433,12 @@ - +

- ...sonst wird es schwierig mit dem Zusammenstellen der Interface-Kette; tatsächlich lassen sich alle für dieses Interface vorgesehenen Operationen »leer« Implementieren — es passiert dann einfach gar nichts, keine Zuweisung, keine Verbindung + ...sonst wird es schwierig mit dem Zusammenstellen der Interface-Kette; tatsächlich lassen sich alle für dieses Interface vorgesehenen Operationen »leer« Implementieren — es passiert dann einfach gar nichts, keine Zuweisung, keine Verbindung — was inhaltlich-logisch sogar korrekt ist, ein NICHTS-Parameter...

@@ -84421,6 +84452,25 @@ + + + + + +

+ es handelt sich dabei durchgehend um Abstraktionen, wobei sich jedoch der Charakter der Abstraktion ändert von einer Zusicherung zu etwas, auf dem wir konkret aufbauen können +

+ +
+
+ + + + + + + +