From 0217fc9dbea709eee2777043d1488a7bc74392e1 Mon Sep 17 00:00:00 2001 From: Ichthyostega Date: Sun, 18 Oct 2026 23:04:51 +0200 Subject: [PATCH] Parameters: demonstrate type conversions and opaque value assignment MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Largely this test covers already established functionality. It is ''somewhat difficult'' to prove that an opaque type is present, beyond showing that values are truncated or accommodated. At the beginning of the implementation-draft, I considered a double-dispatch, but concluded that this would be too much overhead for the standard case; the drafted visitor-style dispatch was "parked" as `Domain::transferTo`. It turned out that this implementation is not directly usable, since it assumes that »the value buffer« is accessible, albeit as opaque ValBuff&. As the design matured, I decided that the presence of a »Buffer« should better not be assumed, and thus flipped the high-level-APIs around. But it is easily possible to implement this double-dispatch scheme anew on top of the now settled implementation scheme: - `Disposition::assignValueTo (Disposition&)` invoked on the source side - implemented in `ParamData::assignValueTo (Disposition&)`, and there delegating to the templated front-end setter `Disposition::setVal(X)` (which performs the second dispatch step) It remains to be seen if such an opaque value assignement is required in practice --- src/lib/par/disposition.hpp | 23 +++- src/lib/par/param-type.hpp | 5 + src/lib/par/parameter.hpp | 16 +++ src/lib/par/scale.hpp | 5 +- tests/lib/par/parameter-domain-test.cpp | 1 + tests/lib/par/parameter-test.cpp | 34 ++++- wiki/thinkPad.ichthyo.mm | 172 ++++++++++++++++++------ 7 files changed, 210 insertions(+), 46 deletions(-) diff --git a/src/lib/par/disposition.hpp b/src/lib/par/disposition.hpp index dc87e22e1..78a9937c0 100644 --- a/src/lib/par/disposition.hpp +++ b/src/lib/par/disposition.hpp @@ -64,6 +64,8 @@ namespace par { return idr_.scaleID; } + virtual void assignValueTo (Disposition&) const =0; + protected: template bool @@ -125,6 +127,8 @@ namespace par { /* === Provision Interface === */ void retrieveInto (ValBuff&) const override final; ///< @note is sometimes invoked non-virtually for sake of optimisation void setValFrom (ValBuff const&) override final; + + void assignValueTo (Disposition&) const override; }; template @@ -136,19 +140,30 @@ namespace par { template - void + inline void ParamData::retrieveInto (ValBuff& target) const { asValue(target) = val_; } template - void + inline void ParamData::setValFrom (ValBuff const& newVal) { val_ = this->conformScale (asValue (newVal)); } + /** @internal part of a double dispatch to transfer a value + * between two opaque parameter containers. */ + template + inline void + ParamData::assignValueTo (Disposition& target) const + { + target.setVal (val_); + } + + + /** @@ -161,7 +176,7 @@ namespace par { * inline the call, resulting in a direct value access. */ template - X + inline X Disposition::extract() const { X result; // RVO @@ -182,7 +197,7 @@ namespace par { template - void + inline void Disposition::setVal (X changedVal) { if (isBaseDomainMatch()) diff --git a/src/lib/par/param-type.hpp b/src/lib/par/param-type.hpp index f1ba23321..d811c8a0c 100644 --- a/src/lib/par/param-type.hpp +++ b/src/lib/par/param-type.hpp @@ -114,6 +114,11 @@ _Pragma("GCC diagnostic ignored \"-Woverloaded-virtual\"") } + /** @todo 10/2026 this API-function turned out to be merely a demonstration, + * since the same double-dispatch scheme was then implemented directly + * as Disposition::assignValueTo (Disposition&) + * @see ParameterDomain_test::verify_opaqueAssign() + */ template inline void BaseDomain::transferTo (ValBuff const& source, Domain& targetDomain, ValBuff& target) const diff --git a/src/lib/par/parameter.hpp b/src/lib/par/parameter.hpp index 482425933..68bc63a3d 100644 --- a/src/lib/par/parameter.hpp +++ b/src/lib/par/parameter.hpp @@ -68,6 +68,8 @@ namespace par { template void setVal (VAL&&); + Parameter& assignValueFrom (Parameter const&); + /* === Builder API === */ @@ -172,6 +174,8 @@ namespace par { Builder&& cyclicWrap (VAL lowerBound, VAL upperBound) { + if constexpr (std::is_same_v) + throw err::Logic {"attempt to configure a bool-parameter for cyclicWrap"}; if (lowerBound >= upperBound) throw err::Invalid{_Fmt{"invalid parameter build: cyclicWrap requires open interval minVal(%s) < maxVal(%s)"} % lowerBound % upperBound}; @@ -260,5 +264,17 @@ namespace par { } + /** transfer value with type conversion between two opaque parameters. + * @remark this requires a double dispatch, defected back from the target + */ + inline Parameter& + Parameter::assignValueFrom (Parameter const& srcParam) + { + unConst(srcParam).getPayload().assignValueTo (getPayload()); + return *this; + } + + + }} // namespace lib::par #endif /*LIB_PAR_PARAMETER_H*/ diff --git a/src/lib/par/scale.hpp b/src/lib/par/scale.hpp index f22f17cf9..93182d7b5 100644 --- a/src/lib/par/scale.hpp +++ b/src/lib/par/scale.hpp @@ -211,7 +211,10 @@ namespace par { "for cyclic wrapping into [%1.2g...%1.2g[ "} % rawVal % *minVal % *maxVal }; - return util::cyclicWrap (rawVal, *minVal, *maxVal); + if constexpr (std::is_same_v) + throw err::Logic {"cyclicWrap on a bool-parameter is pointless"}; + else + return util::cyclicWrap (rawVal, *minVal, *maxVal); } if (minVal and rawVal < *minVal) return *minVal; diff --git a/tests/lib/par/parameter-domain-test.cpp b/tests/lib/par/parameter-domain-test.cpp index 8f8c9da24..581224a37 100644 --- a/tests/lib/par/parameter-domain-test.cpp +++ b/tests/lib/par/parameter-domain-test.cpp @@ -255,6 +255,7 @@ namespace test{ * and target as reference to _some value buffer_, since this API describes * only a data type disposition, while the actual data storage is defined * as derived parameter data type. + * @todo 10/2026 it seems this was built only to explore the underlying mechanism. */ void verify_opaqueAssign() diff --git a/tests/lib/par/parameter-test.cpp b/tests/lib/par/parameter-test.cpp index f4d49bfc5..44d499adf 100644 --- a/tests/lib/par/parameter-test.cpp +++ b/tests/lib/par/parameter-test.cpp @@ -175,12 +175,42 @@ namespace test{ } - /** @test each parameter has an opaque yet distinct type - * @todo WIP 10/26 🔁 define ⟶ implement + /** @test each parameter has an opaque yet distinct dynamic type. + * - types are converted, limited and conformed + * automatically, both on setting and getting values + * - based on the embedded type information, it is possible + * to transfer the value to a differently typed parameter. + * @todo WIP 10/26 🔁 define ⟶ ✔ implement */ void verify_ParamType() { + Parameter p1 = Parameter::forType() + .maxVal(10) + .build(); + Parameter p2 = Parameter::forType() + .maxVal(20) + .build(); + p1.setVal(5.5); + p2.setVal(5.5); + CHECK (5 == p1.getVal()); + CHECK (5.5 == p2.getVal()); + + // based on type and scale information, + // a value can be transfered between opaque parameters + p2.setVal(15.5); + p1.assignValueFrom(p2); + CHECK (10 == p1.getVal()); + CHECK (15.5 == p2.getVal()); + + Parameter pb = Parameter::forValue(true).build(); + CHECK ( 1.0 == pb.getVal()); + + p2.setVal(0.2); + pb.assignValueFrom(p2); + CHECK ( 0.0 == pb.getVal()); + pb.assignValueFrom(p1); + CHECK (true == pb.getVal()); } diff --git a/wiki/thinkPad.ichthyo.mm b/wiki/thinkPad.ichthyo.mm index 114901089..e274770f4 100644 --- a/wiki/thinkPad.ichthyo.mm +++ b/wiki/thinkPad.ichthyo.mm @@ -82659,7 +82659,7 @@ - + @@ -82887,7 +82887,7 @@ - + @@ -82975,7 +82975,7 @@ - + @@ -83248,7 +83248,7 @@ - + @@ -83455,12 +83455,12 @@ - - + + - + @@ -83520,7 +83520,7 @@ - + @@ -83903,7 +83903,7 @@ - + @@ -84129,6 +84129,10 @@ + + + + @@ -84158,7 +84162,7 @@ - + @@ -84168,7 +84172,7 @@ - + @@ -84284,9 +84288,9 @@

- + - + @@ -84305,6 +84309,13 @@ + + + + + + + @@ -84875,7 +84886,7 @@ - + @@ -85203,6 +85214,49 @@ + + + + + + + + + + + + + +

+ eine ValBuff& ist immer das Argument, d.h. das ist in der Regel nur eine opaque Verpackung eines Datenwerts, der anderweitig direkt zugänglich ist +

+ +
+
+
+ + + + + + + + + + + + + + + + + + + + + + + @@ -85371,6 +85425,20 @@ + + + + + + + + + + + + + + @@ -85517,7 +85585,7 @@ - + @@ -85876,15 +85944,15 @@ - - + + - + @@ -86111,7 +86179,8 @@ - + + @@ -86160,6 +86229,9 @@ + + + @@ -88353,7 +88425,7 @@ Prop.1: dist%3 1 2 0 1 2 0 - + @@ -88367,7 +88439,7 @@ Prop.1: dist%3 1 2 0 1 2 0 - + @@ -88536,7 +88608,7 @@ Prop.1: dist%3 1 2 0 1 2 0 - + @@ -88594,7 +88666,7 @@ Prop.1: dist%3 1 2 0 1 2 0 - + @@ -88611,8 +88683,8 @@ Prop.1: dist%3 1 2 0 1 2 0 - - + + @@ -88624,37 +88696,59 @@ Prop.1: dist%3 1 2 0 1 2 0 - + - + - + + - + - - - +

wegen dem »polymorphic« ist im Container eine Identität verborgen; man kann nicht einfach auf observable Werte abstellen, aber uberflächlich verhält es sich wie ein kopierbarer Value. Das wirft subtile Fragen auf

- -
+
- + - - + + + + - + + + + + + + +

+ man müßte nur alle internen Descriptoren mit bewegen; also im Grunde eine neu-Konstruktion in-place — das wirft lediglich die gleichen konzeptionellen Probleme auf, die auch eine Copy-Konstruktion aufwirft (was ist dann die Identität?) +

+ +
+
+ + + +
+ + + + +
+
@@ -89014,7 +89108,7 @@ Prop.1: dist%3 1 2 0 1 2 0

- +