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

- +