diff --git a/src/lib/meta/function-closure.hpp b/src/lib/meta/function-closure.hpp index 5c3f51701..10b648201 100644 --- a/src/lib/meta/function-closure.hpp +++ b/src/lib/meta/function-closure.hpp @@ -655,7 +655,7 @@ namespace func{ * `f(a,b,c)->res + (b,c)` yields `f(a)->res` * * @param f function, function pointer or functor - * @param arg value tuple, used to close function arguments starting from right + * @param arg value tuple, used to close function arguments, aligned to the right end. * @return new function object, holding copies of the values and using them at the * closed arguments; on invocation, only the remaining arguments need to be supplied. */ diff --git a/src/lib/meta/tuple-closure.hpp b/src/lib/meta/tuple-closure.hpp index 4e5098cf9..bd13588ec 100644 --- a/src/lib/meta/tuple-closure.hpp +++ b/src/lib/meta/tuple-closure.hpp @@ -56,20 +56,30 @@ namespace meta{ * ones are supplied as function arguments. */ template - struct TupleClosureBuilder; + struct TupleClosureBuilder + { + static_assert (!sizeof(PAR), + "attempt to partially close something not tuple-like"); + }; template class TUP, typename...PARS> struct TupleClosureBuilder> { + static_assert (sizeof...(PARS) + ,"attempt to partially close empty record"); + using Tuple = TUP; using TupleBuilderSig = Tuple(PARS...); + /** the builder function to be partially closed */ static Tuple buildRecord (PARS ...params) { return {std::move(params)...}; } + /** preconfigure some elements to the given values, + * starting from left */ template static auto closeFront (VALS&& ...vs) @@ -79,15 +89,19 @@ namespace meta{ return wrapBuilder (func::PApply::bindFront (buildRecord, move(boundArgs))); } + /** preconfigure some elements to the given values, + * in forward order yet aligned to the tuple end */ template static auto closeBack (VALS&& ...vs) { using ClosedTypes = TySeq...>; - auto boundArgs = std::make_tuple (std::forward (vs)...); // Note: must be passed by-val here + auto boundArgs = std::make_tuple (std::forward (vs)...); return wrapBuilder (func::PApply::bindBack (buildRecord, move(boundArgs))); } + /** preconfigure element to the given value + * @tparam idx zero-based position */ template static auto close (VAL&& val) @@ -99,15 +113,15 @@ namespace meta{ private: template static auto - wrapBuilder (CLO partialClosure) + wrapBuilder (CLO closureFun) { using RemainingArgs = typename _Fun::Args; using RemainingParams = typename lib::meta::RebindVariadic::Type; - return [closure = move(partialClosure) + return [partialClosure = move(closureFun) ] (RemainingParams remPar) { - return std::apply (closure, remPar); + return std::apply (partialClosure, remPar); }; } }; @@ -121,7 +135,11 @@ namespace meta{ * on top of std::array, with N times the same type. */ template - struct ArrayAdapt; + struct ArrayAdapt + { + static_assert(sizeof...(TTT) + ,"empty list ... attempting total (not partial) closure?"); + }; /** Metafunction to detect if a type-sequence holds uniform types */ @@ -145,6 +163,7 @@ namespace meta{ { using NFold = typename Repeat::Seq; using Array = typename RebindVariadic::Type; + static_assert(N,"attempt to partially close empty array"); }; template diff --git a/src/steam/engine/node-builder.hpp b/src/steam/engine/node-builder.hpp index 702b0821f..f6a59a304 100644 --- a/src/steam/engine/node-builder.hpp +++ b/src/steam/engine/node-builder.hpp @@ -501,7 +501,30 @@ namespace engine { closeParamFront (PAR v1, PARS ...vs) { return adaptParam( - WAB::ParamClosure::template closeFront (v1,vs...)); + WAB::ParamClosure::template closeFront (forward (v1) + ,forward(vs)...)); + } + + /** immediately close the rightmost parameter positions, + * applying the given values in forward order. */ + template + auto + closeParamBack (PAR v1, PARS ...vs) + { + return adaptParam( + WAB::ParamClosure::template closeBack (forward (v1) + ,forward(vs)...)); + } + + /** immediately close a single parameter at designated position + * @tparam idx zero-based index of the element in the param-tuple + */ + template + auto + closeParam (PAR val) + { + return adaptParam( + WAB::ParamClosure::template close (forward (val))); } diff --git a/tests/core/steam/engine/node-builder-test.cpp b/tests/core/steam/engine/node-builder-test.cpp index 90d94fba0..06b3227e3 100644 --- a/tests/core/steam/engine/node-builder-test.cpp +++ b/tests/core/steam/engine/node-builder-test.cpp @@ -195,7 +195,14 @@ namespace test { /** @test build a node and partially close (≙ predefine) some parameters, * while leaving other parameters open to be set on invocation - * through a parameter-functor. + * through a parameter-functor. + * - define a processing-function which takes an array of parameters, + * which will be handled similar as a tuple with uniform types. + * - demonstrate that several partial-closures can be cascaded; + * first close one parameter given by index, then close staring + * from the front and then aligned to the end + * - now a single param «slot» remains open, which can be wired + * to receive automation data (note: 1-tuple generated automatically) * @remark it is quite common that processing functionality provided by an * external library exposes both technical and artistic parameters, which * leads to the situation that technical parameters can be predetermined @@ -212,14 +219,16 @@ namespace test { ProcNode node{prepareNode("Test") .preparePort() - .invoke ("fun()", procFun) - .closeParamFront (1,2,3,4) - .attachAutomation (autoFun) + .invoke ("fun()", procFun) // param(·,·,·,·,·) + .closeParam<2> (1) // param(·,·,1,·,·) + .closeParamFront(2) // param(2,·,1,·,·) + .closeParamBack (3,4) // param(2,·,1,3,4) + .attachAutomation (autoFun) // △ .completePort() .build()}; Time timeOfEvil{5555,0}; - CHECK (15 == invokeRenderNode(node,timeOfEvil)); + CHECK (2+5+1+3+4 == invokeRenderNode (node, timeOfEvil)); } diff --git a/wiki/thinkPad.ichthyo.mm b/wiki/thinkPad.ichthyo.mm index c3899309d..83ac4fb5c 100644 --- a/wiki/thinkPad.ichthyo.mm +++ b/wiki/thinkPad.ichthyo.mm @@ -58819,7 +58819,7 @@ - + @@ -58892,6 +58892,10 @@ + + + + @@ -105746,7 +105750,37 @@ StM_bind(Builder<R1> b1, Extension<R1,R2> extension) - + + + + + + +

+ AUA!‼ Hammer auf den letzten Metern +

+ + +
+ + + +

+ ...wie so oft: +

+

+ Du sagst Dir, anstandshalber sollte es noch einen kompletten Integrationstest geben, hast noch ein schlechtes Gewissen, daß Du Dich „verspielst“ — und dann das: das sorgfälig schrittweise aufgebaute Design kann ein ganz und gar grundlegendes und sehr geläufiges Problem nicht handhaben! +

+

+ +

+

+ Was mach ich jetzt bloß ... der NodeBuilder ist doch schon so komplex, daß ich ihn selber kaum noch stemmen kann..... Muß ich jetzt die grundelgende Systematik der Builder-DSL über den Haufen werfen und alles nochmal von Grund auf implementieren....??? +

+ +
+ +
@@ -105757,7 +105791,7 @@ StM_bind(Builder<R1> b1, Extension<R1,R2> extension) - + @@ -105766,6 +105800,7 @@ StM_bind(Builder<R1> b1, Extension<R1,R2> extension)

+ @@ -105784,7 +105819,7 @@ StM_bind(Builder<R1> b1, Extension<R1,R2> extension) - + @@ -105819,14 +105854,15 @@ StM_bind(Builder<R1> b1, Extension<R1,R2> extension) - + + - + - - + + @@ -105835,8 +105871,9 @@ StM_bind(Builder<R1> b1, Extension<R1,R2> extension)

+
- + @@ -105845,8 +105882,9 @@ StM_bind(Builder<R1> b1, Extension<R1,R2> extension)

+
- + @@ -105856,6 +105894,7 @@ StM_bind(Builder<R1> b1, Extension<R1,R2> extension) + @@ -105866,7 +105905,7 @@ StM_bind(Builder<R1> b1, Extension<R1,R2> extension) - + @@ -105879,8 +105918,47 @@ StM_bind(Builder<R1> b1, Extension<R1,R2> extension) - + + + + + + + +

+ daß wir jetzt eine std::function erzeugen ist hier ganz furchbar +

+ + +
+ + + + + +

+ ein Schritt vor, +

+

+ zwei Schritte zurück... +

+ +
+ +
+
+ + + + +

+ wenn mehr als ein Parameter closed wird ⟹ Heap Storage +

+ +
+ +
@@ -105898,8 +105976,11 @@ StM_bind(Builder<R1> b1, Extension<R1,R2> extension)
- + + + + @@ -105936,7 +106017,7 @@ StM_bind(Builder<R1> b1, Extension<R1,R2> extension) - + @@ -105958,7 +106039,7 @@ StM_bind(Builder<R1> b1, Extension<R1,R2> extension) - + @@ -105975,7 +106056,7 @@ StM_bind(Builder<R1> b1, Extension<R1,R2> extension) - + @@ -106050,7 +106131,8 @@ StM_bind(Builder<R1> b1, Extension<R1,R2> extension) - + + @@ -106060,10 +106142,11 @@ StM_bind(Builder<R1> b1, Extension<R1,R2> extension) - - - + + + + @@ -106087,8 +106170,9 @@ StM_bind(Builder<R1> b1, Extension<R1,R2> extension) + - + @@ -106108,14 +106192,14 @@ StM_bind(Builder<R1> b1, Extension<R1,R2> extension) - - - + + + - + @@ -106202,8 +106286,8 @@ StM_bind(Builder<R1> b1, Extension<R1,R2> extension) - - + + @@ -106212,7 +106296,7 @@ StM_bind(Builder<R1> b1, Extension<R1,R2> extension) - + @@ -106229,7 +106313,7 @@ StM_bind(Builder<R1> b1, Extension<R1,R2> extension) - + @@ -106245,26 +106329,54 @@ StM_bind(Builder<R1> b1, Extension<R1,R2> extension) - + - - + + + + - - + + + + + + + + +

+ ...was uns aber nix hilft, denn wir kommen gar nicht dorthin +

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