From 3a3b7e4dd7f2e1375039edb1936224d7a539eb0a Mon Sep 17 00:00:00 2001 From: Ichthyostega Date: Thu, 19 Dec 2024 04:06:26 +0100 Subject: [PATCH] Invocation: develop a plan how to integrate a Parameter functor MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This is one remaining tricky detail to be solved. The underlying difficulty is architectural: - the processing functor will be supplied by the Media-Lib-Plug-in - while a functor to set parameters and automation will be added from another context Yet both have to work together, and both together will determine the effective type of the ''Weaving Pattern'' Thus we'll have to get both functors somehow integrated into the Level-2-Builder, yet we must be able first to pass this builder instance to the Library-Plug-in and then, in a second step, another part of the Lumiera Builder logic will have to add the Parameter wiring. The solution I'm proposing is to exploit the observation that in fact the processing functor is stored as a kind of »Prototype« within the ''Weaving Pattern'' and will be ''copied'' from there for each individual Render Node invocation. The reasons for this is, we want the optimiser to see the full instantiation of the library function and thus get maximum leverage; thus the code doing the actual call must see the functor or lambda to be able to inline it. This leads to the idea to ''separate'' this »prototype« from the `FeedManifold`; the latter thereby becomes mostly agnostic of parameter processing. However, `FeedManifold` must then accept a copy of the parameter values as constructor argument and pass it into its internal storage. This forces yet another reorganisation of the class structure. Basically the storage modules for `FeedManifold` are now prepared within a configuratiton class, which actually helps to simplify the metaprogramming definitions and keeps the enclosing namespace clean. --- src/steam/engine/feed-manifold.hpp | 177 +++++++--- src/steam/engine/weaving-pattern-builder.hpp | 9 +- tests/core/steam/engine/node-base-test.cpp | 37 +- wiki/thinkPad.ichthyo.mm | 354 ++++++++++++++++--- 4 files changed, 436 insertions(+), 141 deletions(-) diff --git a/src/steam/engine/feed-manifold.hpp b/src/steam/engine/feed-manifold.hpp index 43310b4f7..60e3d097b 100644 --- a/src/steam/engine/feed-manifold.hpp +++ b/src/steam/engine/feed-manifold.hpp @@ -107,6 +107,7 @@ namespace engine { using lib::meta::_Fun; using lib::meta::enable_if; + using lib::meta::disable_if_self; using lib::meta::is_UnaryFun; using lib::meta::is_BinaryFun; using lib::meta::is_TernaryFun; @@ -240,56 +241,100 @@ namespace engine { using BuffO = typename ArgO::List::Head; using BuffI = typename std::conditional::type; /////////////////////////TODO obsolete ... remove after switch }; - - - - /** FeedManifold building block: hold parameter data */ - template - struct ParamStorage - { - using ParSig = typename _ProcFun::SigP; - ParSig param{}; - }; - - template - struct BufferSlot_Input - { - using BuffS = lib::UninitialisedStorage::FAN_I>; - using ArgSig = typename _ProcFun::SigI; - - BuffS inBuff; - ArgSig inArgs{}; - }; - - template - struct BufferSlot_Output - { - using BuffS = lib::UninitialisedStorage::FAN_O>; - using ArgSig = typename _ProcFun::SigO; - - BuffS outBuff; - ArgSig outArgs{}; - }; - - template - using NotProvided = Tagged; - - template - using Provide_if = std::conditional_t>; }//(End)Introspection helpers. + + template - struct FeedManifold_StorageSetup - : util::NonCopyable - , BufferSlot_Output - , Provide_if<_ProcFun::hasInput(), BufferSlot_Input> - , Provide_if<_ProcFun::hasParam(), ParamStorage> + struct _StorageSetup { + using _Trait = _ProcFun; + enum{ FAN_I = _Trait::FAN_I + , FAN_O = _Trait::FAN_O + }; + static constexpr bool hasInput() { return _Trait::hasInput(); } + static constexpr bool hasParam() { return _Trait::hasParam(); } + + using ParSig = typename _Trait::SigP; + + template + using BuffS = lib::UninitialisedStorage; + + using BuffI = BuffS; + using BuffO = BuffS; + + using ArgI = typename _Trait::SigI; + using ArgO = typename _Trait::SigO; + + + /** FeedManifold building block: hold parameter data */ + struct ParamStorage + { + ParSig param; + + ParamStorage() = default; + + template + ParamStorage (INIT&& ...paramInit) + : param{forward (paramInit)...} + { } + }; + + struct BufferSlot_Input + { + BuffI inBuff; + ArgI inArgs{}; + }; + + struct BufferSlot_Output + { + BuffO outBuff; + ArgO outArgs{}; + }; + + template + using enable_if_hasParam = typename lib::meta::enable_if_c<_ProcFun>::hasParam()>::Type; + + template + using NotProvided = Tagged; + + template + using Provide_if = std::conditional_t>; + + using FeedOutput = BufferSlot_Output; + using FeedInput = Provide_if; + using FeedParam = Provide_if; + + /** + * Data Storage block for the FeedManifold + * Flexibly configured based on the processing function. + */ + struct Storage + : util::NonCopyable + , FeedOutput + , FeedInput + , FeedParam + { + FUN process; + + template + Storage (F&& fun) + : process{forward (fun)} + { } + + template + , typename =enable_if_hasParam> + Storage (F&& fun, INIT&& ...paramInit) + : FeedParam{forward (paramInit)...} + , process{forward (fun)} + { } + }; }; + /** * Adapter to connect input/output buffers to a processing functor backed by an external library. * Essentially, this is structured storage tailored specifically to a given functor signature. @@ -314,27 +359,23 @@ namespace engine { template struct FeedManifold - : FeedManifold_StorageSetup + : _StorageSetup::Storage { - using _Trait = _ProcFun; - using _F = FeedManifold; + using _S = _StorageSetup; + using _F = typename _S::Storage; - static constexpr bool hasInput() { return _Trait::hasInput(); } - static constexpr bool hasParam() { return _Trait::hasParam(); } + /** pass-through constructor */ + using _S::Storage::Storage; - using ArgI = typename _Trait::SigI; - using ArgO = typename _Trait::SigO; - enum{ FAN_I = _Trait::FAN_I - , FAN_O = _Trait::FAN_O + using ArgI = typename _S::ArgI; + using ArgO = typename _S::ArgO; + enum{ FAN_I = _S::FAN_I + , FAN_O = _S::FAN_O }; + static constexpr bool hasInput() { return _S::hasInput(); } + static constexpr bool hasParam() { return _S::hasParam(); } - FUN process; - - template - FeedManifold (INIT&& ...funSetup) - : process{forward (funSetup)...} - { } template auto& @@ -375,14 +416,34 @@ namespace engine { invoke() { if constexpr (hasInput()) - process (_F::inArgs, _F::outArgs); + _F::process (_F::inArgs, _F::outArgs); else - process (_F::outArgs); + _F::process (_F::outArgs); } }; + /** + * Builder-Prototype to create FeedManifold instances. + * This »Prototype« becomes part of the Turnout / WeavingPattern + * and holds processing- and parameter-functor instances as configuration. + * The Processing-Functor will be copied into the actual FeedManifold instance + * for each Node invocation. + * @tparam FUN type of the data processing-functor + * @tparam PAM type of an optional parameter-setup functor + */ + template + class FeedPrototype + : util::MoveOnly + { + FUN procFun_; + PAM paramFun_; + + ///////////////////////////////////////////////////////////////////////////////////////////////////////TICKET #1386 : elaborate setup / binding for parameter-creation + }; + + /** * Adapter to handle a simple yet common setup for media processing * - somehow we can invoke processing as a simple function diff --git a/src/steam/engine/weaving-pattern-builder.hpp b/src/steam/engine/weaving-pattern-builder.hpp index 08febc229..5362e5565 100644 --- a/src/steam/engine/weaving-pattern-builder.hpp +++ b/src/steam/engine/weaving-pattern-builder.hpp @@ -103,6 +103,7 @@ #include "steam/engine/buffhandle-attach.hpp" /////////////////OOO why do we need to include this? we need the accessAs() template function #include "lib/test/test-helper.hpp" ////////////////////////////OOO TODO added for test #include "lib/format-string.hpp" +#include "lib/iter-zip.hpp" //#include "lib/util-foreach.hpp" //#include "lib/iter-adapter.hpp" //#include "lib/meta/function.hpp" @@ -125,6 +126,7 @@ namespace engine { // using lib::Literal; using lib::Several; using lib::Depend; + using lib::izip; using util::_Fmt; using util::max; @@ -238,7 +240,6 @@ namespace engine { * actual NodeBuilder and PortBuilder allows to introduce extension points * and helps to abstract away internal technical details of the invocation. * @tparam POL allocation and context configuration policy - * @tparam N maximum number of input and output slots * @tparam FUN function or invocation adapter to invoke */ template @@ -346,10 +347,10 @@ namespace engine { REQUIRE (providers.size() == buffTypes.size()); auto outTypes = DataBuilder{leadPorts.policyConnect()} .reserve (buffTypes.size()); - uint i=0; - for (auto& typeConstructor : buffTypes) + + for (auto& [i,typeConstructor] : izip(buffTypes)) outTypes.append ( - typeConstructor (providers[i++])); + typeConstructor (providers[i])); ENSURE (leadPorts.size() == FunSpec::FAN_I); ENSURE (outTypes.size() == FunSpec::FAN_O); diff --git a/tests/core/steam/engine/node-base-test.cpp b/tests/core/steam/engine/node-base-test.cpp index 7e12e6a40..523c83d9f 100644 --- a/tests/core/steam/engine/node-base-test.cpp +++ b/tests/core/steam/engine/node-base-test.cpp @@ -79,21 +79,13 @@ namespace test { void verify_FeedManifold() { - // some random numbers to test... + // Prepare setup to build a suitable FeedManifold... long r1 = rani(100); - - // Prepare setup to build a suitable FeedManifold using Buffer = long; -/////////////////////////////////////////////////////////////////////////////////TODO - using T1 = tuple; - using T2 = array; - using T3 = int; - using T4 = int*; - using T5 = lib::HeteroData; -/////////////////////////////////////////////////////////////////////////////////TODO - auto fun_singleOut = [&](Buffer* buff) { *buff = r1; }; + // Example-1: a FeedManifold to adapt a simple generator function + auto fun_singleOut = [&](Buffer* buff) { *buff = r1; }; using M1 = FeedManifold; CHECK (not M1::hasInput()); CHECK (not M1::hasParam()); @@ -188,17 +180,12 @@ namespace test { BuffHandle buffI0 = buff; BuffHandle buffI1 = buffOut; BuffHandle buffI2 = provider.lockBufferFor (-22); -SHOW_EXPR(buffI0.accessAs()) -SHOW_EXPR(buffI1.accessAs()) -SHOW_EXPR(buffI2.accessAs()) CHECK (buffI0.accessAs() == r1 ); // (result from Example-1) CHECK (buffI1.accessAs() == r1+1); // (result from Example-2) CHECK (buffI2.accessAs() == -55 ); ///////////////////////////////////////OOO should be -22 // prepare a compound buffer and an extra buffer for output... BuffHandle buffO0 = provider.lockBufferFor (Sequence{-111,-222,-333}); BuffHandle buffO1 = provider.lockBufferFor (-33); -SHOW_EXPR(util::join(buffO0.accessAs())) -SHOW_EXPR(buffO1.accessAs()) CHECK ((buffO0.accessAs() == Sequence{-111,-222,-333})); CHECK (buffO1.accessAs() == -55 ); ///////////////////////////////////////OOO should be -33 @@ -209,20 +196,10 @@ SHOW_EXPR(buffO1.accessAs()) m3.outBuff.createAt(0, buffO0); m3.outBuff.createAt(1, buffO1); m3.connect(); -SHOW_EXPR(m3.inArgs) -SHOW_EXPR(m3.outArgs) // Verify data exposed prior to invocation.... auto& [ia0,ia1,ia2] = m3.inArgs; auto& [oa0,oa1] = m3.outArgs; auto& [o00,o01,o02] = *oa0; -SHOW_EXPR(ia0) -SHOW_EXPR(ia1) -SHOW_EXPR(ia2) -SHOW_EXPR(oa0) -SHOW_EXPR(o00) -SHOW_EXPR(o01) -SHOW_EXPR(o02) -SHOW_EXPR(oa1) CHECK (*ia0 == r1 ); CHECK (*ia1 == r1+1); CHECK (*ia2 == -55 ); /////////////////////////////////////////////////////OOO should be -22 @@ -232,14 +209,6 @@ SHOW_EXPR(oa1) CHECK (*oa1 == -55 ); /////////////////////////////////////////////////////OOO should be -33 m3.invoke(); -SHOW_EXPR(ia0) -SHOW_EXPR(ia1) -SHOW_EXPR(ia2) -SHOW_EXPR(oa0) -SHOW_EXPR(o00) -SHOW_EXPR(o01) -SHOW_EXPR(o02) -SHOW_EXPR(oa1) CHECK (*ia0 == r1 ); // Input buffers unchanged CHECK (*ia1 == r1+1); CHECK (*ia2 == -55 ); /////////////////////////////////////////////////////OOO should be -22 diff --git a/wiki/thinkPad.ichthyo.mm b/wiki/thinkPad.ichthyo.mm index b31a37af1..11c8af763 100644 --- a/wiki/thinkPad.ichthyo.mm +++ b/wiki/thinkPad.ichthyo.mm @@ -82,9 +82,7 @@ - - - +

TODO: Infos zusammentragen und dokumentieren @@ -25760,9 +25758,7 @@ - - - +

weil nur sie durch ihren Display-Frame die beiden Kind-Widgets kennen @@ -26446,9 +26442,7 @@ - - - +

d.h. der Versuch, die Probleme geschickt wegzuabstrahieren. @@ -27066,9 +27060,7 @@ - - - +

Das liegt vielleicht auch an der etwas „alten“ Version von ca. 2018. @@ -27894,9 +27886,7 @@ - - - +

...um festzulegen, an welcher Stelle in der Hierarchie dieses Styling definiert ist; allerdings machen wir bereits genau dies für die Timeline im Allgemeinen (und zwar genau wegen dem custom-drawing) @@ -29003,9 +28993,7 @@ - - - +

weil nämlich der Trait, für den optimalen Fall, ebenfalls die EmptyBase verwendet, um den Mix-In zu deaktivieren. @@ -30881,9 +30869,7 @@ - - - +

weil dann innerhalb des Canvas alles konsistent ist @@ -31464,9 +31450,7 @@ - - - +

StyleContext::create() @@ -33078,9 +33062,7 @@ - - - +

  • @@ -34535,9 +34517,7 @@ - - - +

    ...und dieser muß einfach lokal im UI zu realisieren sein, also ein Stock-Icon und ggfs ein Vektorgraphic-Element @@ -35190,9 +35170,7 @@ - - - +

    es gibt bereits einen Sündenfall, nämlich im RelativeCanvasHook: der muß delegieren, und daher von außen diese Methode aufrufen @@ -35683,9 +35661,7 @@ - - - +

    es sieht so aus, als wäre es "das" WorkspaceWindow @@ -36302,9 +36278,7 @@ - - - +

    • @@ -51077,9 +51051,7 @@ - - - +

      das ist ein grundlegender Beschluß. @@ -91878,8 +91850,7 @@ Date:   Thu Apr 20 18:53:17 2023 +0200
      Die Signatur des Parameter-Funktors folgt eigentlich zwansläufig aus der gegebenen Processing-Function: es muß ein TurnoutSystem& akzeptiert und ein Parameter(Tupel) geliefert werden (by-value). Seiteneffekte im TurnoutSystem sind möglich (aber die Ausnahme)

      - -
      +
      @@ -92098,6 +92069,63 @@ Date:   Thu Apr 20 18:53:17 2023 +0200
      + + + + + + + +

      + ...das wäre die billige Lösung: man erzeugt es einfach immer per Default, und dann macht man im ctor-body in FeedManifold eine conditional und eine Zuweisung. Das ist insofern unsauber, da wir Zuweisbarkeit der Werte im Param-Tupel nicht fordern (sondern nur default-Konstruierbarkeit). +

      + +
      + +
      + + + + + + + + + + +

      + ...und die neueren Compiler können sich auch nicht beschweren, daß wir anonyme Typen in die Storage binden, und obendrein sind so die ganzen Meta-Definitionen wirklich downstream nicht mehr sichtbar +

      + + +
      +
      + + + + + + + + + + + + + + +

      + er versucht nämlich erst einmal, den getemplateten Ctor mit dem this-type zu instantiieren. Das ist dann hier F = struct Storage selber. In der enable-if-Klausel bilden wir aber _ProcFun<F> — und Storage ist ganz offensichtlich keine Funktion und löst die Assertion aus +

      + +
      +
      + + + + + +
      @@ -92120,6 +92148,166 @@ Date:   Thu Apr 20 18:53:17 2023 +0200
      + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

      + beide Funktoren müssen in den Typ eingehen +

      + + +
      +
      + + + + + + + + + + + + + + + + + + +

      + wenngleich auch lediglich indirekt, denn der sichtbare Parameter ist FUN, der Typ der Processing-Function +

      + + +
      +
      + + + + + +
      + + + + +

      + neuer Name: FeedPrototype +

      + + +
      +
      + + + + + + + + + +

      + Wenn es also ein Param-Tupel gibt, entscheidet es sich im Aufruf-Kontext, ob dafür ein Init-Wert geliefert wird. Wenn nicht, dann findet Default-Initialisierung statt. Ganz einfach +

      + + +
      + +
      +
      + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -92153,6 +92341,21 @@ Date:   Thu Apr 20 18:53:17 2023 +0200
      + + + + + + + +

      + ⟹ geht in eine Builder-Klasse FeedPrototype<FUN,PAM> +

      + + +
      + +
      @@ -92508,6 +92711,36 @@ Date:   Thu Apr 20 18:53:17 2023 +0200
      + + + + + + + +

      + in den Turnout wird ein Prototyp der FeedManifold eingebettet +

      + + +
      + + + + + + + + + +

      + das heißt, idealerweise ist dieses ganze komplexe Konfigurations-Thema optional und transparent +

      + + +
      +
      +
      @@ -92524,7 +92757,7 @@ Date:   Thu Apr 20 18:53:17 2023 +0200
      - + @@ -92533,6 +92766,7 @@ Date:   Thu Apr 20 18:53:17 2023 +0200

      +
      @@ -92554,6 +92788,32 @@ Date:   Thu Apr 20 18:53:17 2023 +0200
      + + + + + + + + + + + + + + +

      + bekommt ggfs. ein zusätzliches Parameter-Tupel als ctor-Wert +

      + + +
      +
      + + + + +
      @@ -92572,6 +92832,10 @@ Date:   Thu Apr 20 18:53:17 2023 +0200
      + + + +