From 2468f6d0ee1369b5682dc5ebcaa151aa70227971 Mon Sep 17 00:00:00 2001 From: Ichthyostega Date: Thu, 2 Jan 2025 03:08:34 +0100 Subject: [PATCH] Invocation: reshape scheme for data-access for Param-Weaving-Pattern MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit As it turns out, we need to embed the Param-Functor tuple, but only for a single use from a »builder« component. On the other hand, the nested »Slot« classes are deemed dangerous, since they just seem to invite being bound into some functor, which would create a dangling reference once the `ParamBuildSpec` is gone. Thus it's better to do away with this reference and make those accessors basically static, because this way they ''can'' be embedded into param-access functors (and I'd expect precisely that to happen in real use) --- src/steam/engine/param-weaving-pattern.hpp | 131 +++++++++++++-------- tests/core/steam/engine/node-feed-test.cpp | 24 ++-- wiki/thinkPad.ichthyo.mm | 123 +++++++++++++------ 3 files changed, 184 insertions(+), 94 deletions(-) diff --git a/src/steam/engine/param-weaving-pattern.hpp b/src/steam/engine/param-weaving-pattern.hpp index 85711cbda..b66df8d5a 100644 --- a/src/steam/engine/param-weaving-pattern.hpp +++ b/src/steam/engine/param-weaving-pattern.hpp @@ -62,6 +62,7 @@ namespace engine { using std::move; using std::forward; + using std::function; using std::make_tuple; using std::tuple; using lib::Several;////TODO RLY? @@ -96,6 +97,15 @@ namespace engine { return addSlot ([paramVal](TurnoutSystem&){ return paramVal; }); } + + /** intended for unit-testing: invoke one of the embedded param-functors */ + template + auto + invokeParamFun (TurnoutSystem& turnoutSys) + { + return std::get (functors_) (turnoutSys); + } + /** @internal the _chain constructor type_ is a type rebinding meta function (nested struct), * which extends the HeteroData chain given by \a ANK with the sequence of types derived from * the result-values of all functors stored in the ParamBuildSpec, i.e. the resulting param tuple. @@ -104,63 +114,74 @@ namespace engine { */ using ChainCons = typename lib::meta::RebindVariadic::Type; - /** invoke all parameter-functors and _drop off_ the result into a »chain-block« (non-copyable) */ - typename ChainCons::NewFrame - buildParamDataBlock (TurnoutSystem& turnoutSys) - { - return std::apply ([&](auto&&... paramFun) - { // invoke parameter-functors and build NewFrame from results - return ChainCons::build (paramFun (turnoutSys) ...); - } - ,functors_); - } - - /** invoke all parameter-functors and package all results by placement-new into a »chain-block« */ - void - emplaceParamDataBlock (void* storage, TurnoutSystem& turnoutSys) - { - std::apply ([&](auto&&... paramFun) - { // invoke parameter-functors and build NewFrame from results - ChainCons::emplace (storage, paramFun (turnoutSys) ...); - } - ,functors_); - } - + /** a (static) getter functor able to work on the full extended HeteroData-Chain + * @remark the front-end of this chain resides in TurnoutSystem */ template - class Slot + struct Accessor : util::MoveOnly { - ParamBuildSpec& spec_; - - Slot (ParamBuildSpec& spec) - : spec_{spec} - { } - friend class ParamBuildSpec; - - public: - auto - invokeParamFun (TurnoutSystem& turnoutSys) - { - return std::get (spec_.functors_) (turnoutSys); - } - - /** a getter functor able to work on the full extended HeteroData-Chain - * @remark the front-end of this chain resides in TurnoutSystem */ - using Accessor = typename ChainCons::template Accessor; - static auto makeAccessor() { return Accessor{}; } - static auto& getParamVal (TurnoutSystem& turnoutSys) { - return turnoutSys.get (makeAccessor()); + using StorageAccessor = typename ChainCons::template Accessor; + return turnoutSys.get (StorageAccessor()); } }; template - Slot - slot() - { return *this; } + Accessor + makeAccessor() + { + return Accessor{}; + } + + class BlockBuilder + : util::MoveOnly + { + Functors functors_; + + public: + /** invoke all parameter-functors and _drop off_ the result into a »chain-block« (non-copyable) */ + typename ChainCons::NewFrame + buildParamDataBlock (TurnoutSystem& turnoutSys) + { + return std::apply ([&](auto&&... paramFun) + { // invoke parameter-functors and build NewFrame from results + return ChainCons::build (paramFun (turnoutSys) ...); + } + ,functors_); + } + + /** invoke all parameter-functors and package all results by placement-new into a »chain-block« */ + void + emplaceParamDataBlock (void* storage, TurnoutSystem& turnoutSys) + { + std::apply ([&](auto&&... paramFun) + { // invoke parameter-functors and build NewFrame from results + ChainCons::emplace (storage, paramFun (turnoutSys) ...); + } + ,functors_); + } + + private: + BlockBuilder (Functors&& funz) + : functors_{move (funz)} + { } + + friend class ParamBuildSpec; + }; + + /** + * Terminal Builder: (destructively) transform this ParamBuildSpec + * into a BlockBuilder, which can then be used to create a Parameter data block, + * thereby invoking the embedded functors and drop-off the results into storage. + */ + BlockBuilder + makeBlockBuilder() + { + return BlockBuilder (move (functors_)); + } }; auto @@ -179,20 +200,30 @@ namespace engine { { using Functors = typename SPEC::Functors; using DataBlock = typename SPEC::ChainCons::NewFrame; + using BlockBuilder = typename SPEC::BlockBuilder; - Functors paramFunctors; + BlockBuilder blockBuilder_; + + function postProcess_; struct Feed : util::NonCopyable { lib::UninitialisedStorage buffer; + + DataBlock& block() { return buffer[0]; } + + void + emplaceParamDataBlock (BlockBuilder& builder, TurnoutSystem& turnoutSys) + { + builder.emplaceParamDataBlock (&block(), turnoutSys); + } }; /** forwarding-ctor to provide the detailed input/output connections */ - template - ParamWeavingPattern (Functors funTup) - : paramFunctors{move (funTup)} + ParamWeavingPattern (BlockBuilder builder) + : blockBuilder_{move (builder)} { } diff --git a/tests/core/steam/engine/node-feed-test.cpp b/tests/core/steam/engine/node-feed-test.cpp index b29172f90..72a6fd15f 100644 --- a/tests/core/steam/engine/node-feed-test.cpp +++ b/tests/core/steam/engine/node-feed-test.cpp @@ -142,21 +142,25 @@ namespace test { CHECK (showType() == "tuple"_expect); // can now store accessor-functors for later use.... - auto acc0 = spec.slot<0>().makeAccessor(); - auto acc1 = spec.slot<1>().makeAccessor(); + auto acc0 = spec.makeAccessor<0>(); + auto acc1 = spec.makeAccessor<1>(); // drive test with a random »nominal Time« <10s with ms granularity Time nomTime{rani(10'000),0}; TurnoutSystem turnoutSys{nomTime}; // can now immediately invoke the embedded parameter-functors - auto v0 = spec.slot<0>().invokeParamFun (turnoutSys); - auto v1 = spec.slot<1>().invokeParamFun (turnoutSys); + auto v0 = spec.invokeParamFun<0> (turnoutSys); + auto v1 = spec.invokeParamFun<1> (turnoutSys); CHECK (v0 == LIFE_AND_UNIVERSE_4EVER); // ◁————————— the first paramFun yields the configured fixed value CHECK (v1 == FrameNr::quant (nomTime, "grid_sec")); // ◁————————— the second paramFun accesses the time in TurnoutSystem + // after all setup of further accessor functors is done + // finally transform the ParamSpec into a storage-block-builder: + auto blockBuilder = spec.makeBlockBuilder(); + { // Now build an actual storage block in local scope, // thereby invoking the embedded parameter-functors... - auto paramBlock = spec.buildParamDataBlock (turnoutSys); + auto paramBlock = blockBuilder.buildParamDataBlock (turnoutSys); // Values are now materialised into paramBlock CHECK (v0 == paramBlock.get<0>()); CHECK (v1 == paramBlock.get<1>()); @@ -165,11 +169,9 @@ namespace test { turnoutSys.attachChainBlock(paramBlock); // can now access the parameter values through the TurnoutSystem as front-End - CHECK (v0 == spec.slot<0>().getParamVal (turnoutSys)); - CHECK (v1 == spec.slot<1>().getParamVal (turnoutSys)); - // and can also use the accessor-functors stored above - CHECK (v0 == turnoutSys.get(acc0)); - CHECK (v1 == turnoutSys.get(acc1)); + // using the pre-configured accessor-functors stored above + CHECK (v0 == acc0.getParamVal (turnoutSys)); + CHECK (v1 == acc1.getParamVal (turnoutSys)); // should detach extension block before leaving scope turnoutSys.detachChainBlock(paramBlock); @@ -180,7 +182,7 @@ namespace test { using Feed = WaPa::Feed; Feed feed; - spec.emplaceParamDataBlock (& feed.buffer[0], turnoutSys); + feed.emplaceParamDataBlock (blockBuilder, turnoutSys); SHOW_EXPR(feed.buffer[0].get<0>()) SHOW_EXPR(feed.buffer[0].get<1>()) TODO ("implement a simple Builder for ParamAgent-Node"); diff --git a/wiki/thinkPad.ichthyo.mm b/wiki/thinkPad.ichthyo.mm index 21e17251c..d57fb545f 100644 --- a/wiki/thinkPad.ichthyo.mm +++ b/wiki/thinkPad.ichthyo.mm @@ -82339,9 +82339,7 @@ Date:   Thu Apr 20 18:53:17 2023 +0200
- - - +

Das heißt, hier haben wir immer einen festen Satz an Parametern, die stets im TurnoutSystem eingebettet vorliegen; diese können aber als HeteroData-Chain erweitert werden um die Blöcke, die wir über eine (oder eine Kette von) ParamBuildSpec erzeugen @@ -94373,15 +94371,14 @@ Date:   Thu Apr 20 18:53:17 2023 +0200
+ - - - +

denn ich kann nicht ein non-copyable-Member fertig per Konstruktor bekommen.... @@ -94393,9 +94390,10 @@ Date:   Thu Apr 20 18:53:17 2023 +0200
- + - + + @@ -94404,9 +94402,7 @@ Date:   Thu Apr 20 18:53:17 2023 +0200
- - - +

heißt, man müßte entweder explizit umkopieren, oder es bräuchte eine Konvention, wie man das (optional) gegebene BuffHandle dann eben doch frei gibt; letztlich wird ja ein BuffHandle zurückgegeben, und das wäre dann dasjenige, daß vom rekursiven Call belegt wurde. Könnte sogar klappen, ist aber als Trickserei zu werten. @@ -94419,9 +94415,7 @@ Date:   Thu Apr 20 18:53:17 2023 +0200
- - - +

Die Aufteilung in diese fünf Schritte dient vor allem der Gliederung der Abläufe; es ist aber nur bedingt ein »Protokoll«, in dem in bestimmten Schritten etwas Festgelegtes passieren muß... @@ -94432,9 +94426,7 @@ Date:   Thu Apr 20 18:53:17 2023 +0200
- - - +

Wenn man Strukturen biegen, leer machen oder umdeuten muß... @@ -94448,7 +94440,8 @@ Date:   Thu Apr 20 18:53:17 2023 +0200
- + + @@ -94463,8 +94456,8 @@ Date:   Thu Apr 20 18:53:17 2023 +0200
- - + + @@ -94472,20 +94465,33 @@ Date:   Thu Apr 20 18:53:17 2023 +0200
- - + + + + + + + + + + + + + + - - - + + + + + + - - - +

...da gibt es definitiv keinen anderen Ausweg, und eigentlich wird ja dadurch auch erst die Builder-Notation wirklich sinnvoll; daß man ein non-copyable-Objekt aus einer Funktion „abwerfen“ kann ist sowiso grenzwertig.... @@ -94493,14 +94499,12 @@ Date:   Thu Apr 20 18:53:17 2023 +0200
- + - - - +

...damit man sieht, wie man's tatsächlich braucht; @@ -94524,12 +94528,65 @@ Date:   Thu Apr 20 18:53:17 2023 +0200
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - + + +