2008-07-20 20:08:08 +02:00
|
|
|
|
/*
|
2024-12-28 23:16:55 +01:00
|
|
|
|
PARAM-WEAVING-PATTERN.hpp - Pattern to carry out special parameter computations
|
2010-12-17 23:28:49 +01:00
|
|
|
|
|
Copyright: clarify and simplify the file headers
* Lumiera source code always was copyrighted by individual contributors
* there is no entity "Lumiera.org" which holds any copyrights
* Lumiera source code is provided under the GPL Version 2+
== Explanations ==
Lumiera as a whole is distributed under Copyleft, GNU General Public License Version 2 or above.
For this to become legally effective, the ''File COPYING in the root directory is sufficient.''
The licensing header in each file is not strictly necessary, yet considered good practice;
attaching a licence notice increases the likeliness that this information is retained
in case someone extracts individual code files. However, it is not by the presence of some
text, that legally binding licensing terms become effective; rather the fact matters that a
given piece of code was provably copyrighted and published under a license. Even reformatting
the code, renaming some variables or deleting parts of the code will not alter this legal
situation, but rather creates a derivative work, which is likewise covered by the GPL!
The most relevant information in the file header is the notice regarding the
time of the first individual copyright claim. By virtue of this initial copyright,
the first author is entitled to choose the terms of licensing. All further
modifications are permitted and covered by the License. The specific wording
or format of the copyright header is not legally relevant, as long as the
intention to publish under the GPL remains clear. The extended wording was
based on a recommendation by the FSF. It can be shortened, because the full terms
of the license are provided alongside the distribution, in the file COPYING.
2024-11-17 23:42:55 +01:00
|
|
|
|
Copyright (C)
|
2024-12-13 03:28:28 +01:00
|
|
|
|
2024, Hermann Vosseler <Ichthyostega@web.de>
|
2010-12-17 23:28:49 +01:00
|
|
|
|
|
Copyright: clarify and simplify the file headers
* Lumiera source code always was copyrighted by individual contributors
* there is no entity "Lumiera.org" which holds any copyrights
* Lumiera source code is provided under the GPL Version 2+
== Explanations ==
Lumiera as a whole is distributed under Copyleft, GNU General Public License Version 2 or above.
For this to become legally effective, the ''File COPYING in the root directory is sufficient.''
The licensing header in each file is not strictly necessary, yet considered good practice;
attaching a licence notice increases the likeliness that this information is retained
in case someone extracts individual code files. However, it is not by the presence of some
text, that legally binding licensing terms become effective; rather the fact matters that a
given piece of code was provably copyrighted and published under a license. Even reformatting
the code, renaming some variables or deleting parts of the code will not alter this legal
situation, but rather creates a derivative work, which is likewise covered by the GPL!
The most relevant information in the file header is the notice regarding the
time of the first individual copyright claim. By virtue of this initial copyright,
the first author is entitled to choose the terms of licensing. All further
modifications are permitted and covered by the License. The specific wording
or format of the copyright header is not legally relevant, as long as the
intention to publish under the GPL remains clear. The extended wording was
based on a recommendation by the FSF. It can be shortened, because the full terms
of the license are provided alongside the distribution, in the file COPYING.
2024-11-17 23:42:55 +01:00
|
|
|
|
**Lumiera** is free software; you can redistribute it and/or modify it
|
|
|
|
|
|
under the terms of the GNU General Public License as published by the
|
|
|
|
|
|
Free Software Foundation; either version 2 of the License, or (at your
|
|
|
|
|
|
option) any later version. See the file COPYING for further details.
|
2010-12-17 23:28:49 +01:00
|
|
|
|
|
2008-07-20 20:08:08 +02:00
|
|
|
|
*/
|
|
|
|
|
|
|
2024-12-13 03:28:28 +01:00
|
|
|
|
|
2024-12-28 21:41:08 +01:00
|
|
|
|
/** @file param-weaving-pattern.hpp
|
2024-12-28 23:16:55 +01:00
|
|
|
|
** Construction kit to establish a set of parameters pre-computed prior to invocation
|
|
|
|
|
|
** of nested nodes. This arrangement is also known as »Parameter Agent Node« (while actually
|
2025-01-04 19:28:58 +01:00
|
|
|
|
** it is a Weaving Pattern residing within some Node's Port). The use-case is to provide a set
|
2024-12-28 23:16:55 +01:00
|
|
|
|
** of additional parameter values, beyond what can be derived directly by a parameter-functor
|
|
|
|
|
|
** based on the _absolute-nominal-Time_ of the invocation. The necessity for such a setup may
|
|
|
|
|
|
** arise when additional context or external state must be combined with the nominal time into
|
|
|
|
|
|
** a tuple of data values, which shall then be consumed by several follow-up evaluations further
|
|
|
|
|
|
** down into a recursive invocation tree _for one single render job._ The solution provided by
|
2025-01-04 19:28:58 +01:00
|
|
|
|
** the Parameter Agent Node relies on placing those additional data values into a tuple, which
|
|
|
|
|
|
** is then stored directly in the render invocation stack frame, prior to descending into further
|
|
|
|
|
|
** recursive Node evaluations. Notably, parameter-functors within the scope of this evaluation tree
|
|
|
|
|
|
** can then access these additional parameters through the TurnoutSystem of the overall invocation.
|
2024-12-21 23:58:56 +01:00
|
|
|
|
**
|
2025-01-04 23:56:42 +01:00
|
|
|
|
** ## Configuration
|
|
|
|
|
|
** In order to setup such an evaluation scheme involving a Parameter Agent as top entrance point,
|
|
|
|
|
|
** and a delegate Node tree below, in a first step, the evaluations for the additional parameter
|
|
|
|
|
|
** values must be established. This is achieved by defining a _Parameter Build Spec,_ which is
|
|
|
|
|
|
** a descriptor record with a builder-DSL notation to be assembled step by step. Internally,
|
|
|
|
|
|
** this ParamBuildSpec embeds a tuple of parameter-functors, one for each new parameter value.
|
|
|
|
|
|
** Furthermore, since the intended usage scheme calls for a lib::HeteroData »chain block« as
|
|
|
|
|
|
** storage for the extended parameter values, an _anchor type_ is embedded into the type signature
|
|
|
|
|
|
** of ParamBuildSpec; this _anchor_ is assumed to be the HeteroData-prefix-chain, where the new
|
|
|
|
|
|
** data block is assumed to be attached at the end. In the common use case, this prefix will be
|
|
|
|
|
|
** the default layout of a TurnoutSystem, which internally embeds a lib::HeteroData record,
|
|
|
|
|
|
** configured to hold some basic parameters, which are present in every render invocation:
|
|
|
|
|
|
** - the _absolute nominal Time_ in the timeline
|
|
|
|
|
|
** - a _process Key_
|
|
|
|
|
|
**
|
|
|
|
|
|
** Since this is a well-known, fixed layout, the definition of a ParamBuildSpec can be started
|
|
|
|
|
|
** from a static convenience function, steam::engine::buildParamSpec(), which yields an (initially
|
|
|
|
|
|
** empty) ParamBuildSpec, anchored at the default layout of the TurnoutSystem. On this builder term,
|
|
|
|
|
|
** several «parameter slots» can be added successively, either
|
|
|
|
|
|
** - by embedding a fixed (constant) parameter value
|
|
|
|
|
|
** - or with a parameter-functor, which works on the basic default TurnoutSystem
|
|
|
|
|
|
**
|
|
|
|
|
|
** Once a ParamBuildSpec is outfitted with all desired functors, it can be used to generate
|
|
|
|
|
|
** _accessor functors_ — which are the crucial ingredient for actually accessing the extended
|
|
|
|
|
|
** parameter values from the nested node tree. Please recall that also a regular Render Node Port
|
|
|
|
|
|
** can embed a parameter-functor, which works on the TurnoutSystem. Usually this param-functor
|
|
|
|
|
|
** will retrieve the _absolute nominal time_ from there, but in our case here, the purpose of
|
|
|
|
|
|
** the whole elaborate scheme is that such an parameter-functor embedded into some processing
|
|
|
|
|
|
** node down in the nested tree can access the extended parameters, which were generated
|
|
|
|
|
|
** initially by the Param Agent Node at top-level and reside in a storage block somewhere up
|
|
|
|
|
|
** the call stack, from where they are linked-in temporarily into the TurnoutSystem. Thus,
|
|
|
|
|
|
** after building the ParamBuildSpec, next some actual Render Nodes have to be built, which
|
|
|
|
|
|
** include the _accessor functors_ retrieved from the ParamBuildSpec. These are actually
|
|
|
|
|
|
** static type markers, as they do not actually refer to the ParamBuildSpec, but rather to
|
|
|
|
|
|
** the «slot number» in the structure (which is encoded into the type signature). Such an
|
|
|
|
|
|
** accessor functor can be applied to the extended TurnoutSystem, and will retrieve the
|
|
|
|
|
|
** corresponding extended parameter value from the chain-block linked temporarily into
|
|
|
|
|
|
** the TurnoutSystem.
|
|
|
|
|
|
**
|
|
|
|
|
|
** Finally, when the nested delegate Node tree is complete, the actual Param Agent Node
|
|
|
|
|
|
** can be built through a special hook in the NodeBuilder: After opening the nested definition
|
|
|
|
|
|
** of a port, invoke steam::engine::PortBuilderRoot::computeParam(spec), passing the ParamBuildSpec
|
|
|
|
|
|
** record (with the actual functor instances embedded!). Furthermore, the link to the delegate
|
|
|
|
|
|
** Node tree must be added, followed by `.completePort()`. Optionally, a post-processing functor
|
|
|
|
|
|
** can be added, which will be invoked after all parameters are generated, but before delegating
|
|
|
|
|
|
** to the nested Node tree.
|
|
|
|
|
|
**
|
|
|
|
|
|
** As should be clear from context, the so called »Param Agent Node« is actually a special port.
|
|
|
|
|
|
** Yet in practice, you'd typically set up a top-level node, where each port is configured with
|
|
|
|
|
|
** a suitable Param Agent setup, and then delegates to the processing chain to produce the
|
|
|
|
|
|
** content to produce for this port. Internally, this Param Agent setup is a Turnout (thus
|
|
|
|
|
|
** implementing the Port interface) with a special \ref ParamWeavingPattern. The latter
|
|
|
|
|
|
** incorporates all the steps necessary to establish this special extended parameter setup
|
|
|
|
|
|
** - it first invokes all the parameter-functors in the tuple
|
|
|
|
|
|
** - it forms a parameter tuple from the result values
|
|
|
|
|
|
** - this parameter-tuple is dropped off into a storage within the current stack frame
|
|
|
|
|
|
** - then this storage block (which is a valid HeteroData chain-block), will be linked
|
|
|
|
|
|
** temporarily with the current TurnoutSystem of the invocation
|
|
|
|
|
|
** - next an optional postprocessing-functor will be invoked
|
|
|
|
|
|
** - followed by a regular recursive invocation of the delegate tree
|
|
|
|
|
|
** - as a last step, the temporary storage block is disconnected from the TurnoutSystem
|
|
|
|
|
|
** - and the result buffer of the recursive delegate tree is returned as result.
|
|
|
|
|
|
**
|
2024-12-28 23:16:55 +01:00
|
|
|
|
** @see node-builder.hpp
|
2024-12-21 23:58:56 +01:00
|
|
|
|
** @see weaving-pattern-builder.hpp
|
2025-01-04 23:56:42 +01:00
|
|
|
|
** @see \ref NodeFeed_test::feedParamNode() "elaborate demonstration example"
|
2024-12-21 23:58:56 +01:00
|
|
|
|
** @see \ref proc-node.hpp "Overview of Render Node structures"
|
2024-12-13 03:28:28 +01:00
|
|
|
|
**
|
2024-12-21 23:58:56 +01:00
|
|
|
|
** @warning WIP as of 12/2024 first complete integration round of the Render engine ////////////////////////////TICKET #1367
|
2024-12-13 03:28:28 +01:00
|
|
|
|
**
|
2008-07-20 20:08:08 +02:00
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
|
|
|
2024-12-28 21:41:08 +01:00
|
|
|
|
#ifndef STEAM_ENGINE_PARAM_WEAVING_PATTERN_H
|
|
|
|
|
|
#define STEAM_ENGINE_PARAM_WEAVING_PATTERN_H
|
2008-07-20 20:08:08 +02:00
|
|
|
|
|
2024-12-13 03:28:28 +01:00
|
|
|
|
#include "steam/common.hpp"
|
2024-12-14 03:50:10 +01:00
|
|
|
|
#include "steam/engine/turnout.hpp"
|
2024-12-13 03:28:28 +01:00
|
|
|
|
#include "steam/engine/turnout-system.hpp"
|
2025-01-01 03:23:23 +01:00
|
|
|
|
#include "lib/uninitialised-storage.hpp"
|
2025-01-01 22:02:08 +01:00
|
|
|
|
#include "lib/meta/variadic-rebind.hpp"
|
2024-12-29 03:23:59 +01:00
|
|
|
|
#include "lib/meta/tuple-helper.hpp"
|
2025-01-01 03:23:23 +01:00
|
|
|
|
#include "lib/meta/function.hpp"
|
2008-07-20 20:08:08 +02:00
|
|
|
|
|
2024-12-28 23:16:55 +01:00
|
|
|
|
#include <tuple>
|
|
|
|
|
|
#include <utility>
|
2008-07-20 20:08:08 +02:00
|
|
|
|
|
|
|
|
|
|
|
2018-11-15 23:55:13 +01:00
|
|
|
|
namespace steam {
|
2008-07-20 20:08:08 +02:00
|
|
|
|
namespace engine {
|
|
|
|
|
|
|
2024-12-28 23:16:55 +01:00
|
|
|
|
using std::move;
|
2024-12-29 03:23:59 +01:00
|
|
|
|
using std::forward;
|
2025-01-02 03:08:34 +01:00
|
|
|
|
using std::function;
|
2024-12-29 03:23:59 +01:00
|
|
|
|
using std::make_tuple;
|
2024-12-28 23:16:55 +01:00
|
|
|
|
using std::tuple;
|
2025-01-04 19:28:58 +01:00
|
|
|
|
using lib::meta::Tuple;
|
|
|
|
|
|
using lib::meta::ElmTypes;
|
2024-12-28 23:16:55 +01:00
|
|
|
|
|
|
|
|
|
|
|
2025-01-04 23:56:42 +01:00
|
|
|
|
/**
|
|
|
|
|
|
* Specification record for the setup of a »Param Agent Node«.
|
|
|
|
|
|
* @tparam ANCH the lib::HeteroData prefix-chain to use as anchor point
|
|
|
|
|
|
* @tparam FUNZ a set of parameter-functors used to generate additional parameter values.
|
|
|
|
|
|
* @note This template provides a builder-DSL notation, starting with the free function
|
|
|
|
|
|
* \ref buildParamSpec(). Further parameter «slots» can be added step by step.
|
|
|
|
|
|
* @remark use the nested Accessor records to retrieve the generated parameter values
|
|
|
|
|
|
* and use the nested BlockBuilder as a »Prototype« in the ParamWeavingPattern,
|
|
|
|
|
|
* which actually can be configured through the NodeBuilder...
|
|
|
|
|
|
*/
|
2025-01-04 19:28:58 +01:00
|
|
|
|
template<class ANCH, typename...FUNZ>
|
2024-12-28 23:16:55 +01:00
|
|
|
|
struct ParamBuildSpec
|
|
|
|
|
|
{
|
|
|
|
|
|
using Functors = tuple<FUNZ...>;
|
|
|
|
|
|
|
2025-01-04 19:28:58 +01:00
|
|
|
|
using ResTypes = typename ElmTypes<Functors>::template Apply<lib::meta::_FunRet>;
|
|
|
|
|
|
using ParamTup = Tuple<ResTypes>;
|
2024-12-29 03:23:59 +01:00
|
|
|
|
|
2024-12-28 23:16:55 +01:00
|
|
|
|
Functors functors_;
|
|
|
|
|
|
|
|
|
|
|
|
ParamBuildSpec (Functors&& funz)
|
|
|
|
|
|
: functors_{move (funz)}
|
|
|
|
|
|
{ }
|
2024-12-29 03:23:59 +01:00
|
|
|
|
|
2025-01-04 19:28:58 +01:00
|
|
|
|
/** can be copied if all functors are copyable... */
|
|
|
|
|
|
ParamBuildSpec clone() { return *this; }
|
|
|
|
|
|
|
|
|
|
|
|
|
2024-12-29 03:23:59 +01:00
|
|
|
|
template<typename FUN>
|
|
|
|
|
|
auto
|
|
|
|
|
|
addSlot (FUN&& paramFun)
|
|
|
|
|
|
{
|
2025-01-04 19:28:58 +01:00
|
|
|
|
using FunN = std::decay_t<FUN>;
|
|
|
|
|
|
return ParamBuildSpec<ANCH,FUNZ...,FunN>{std::tuple_cat (move(functors_)
|
|
|
|
|
|
,make_tuple (forward<FUN>(paramFun)))};
|
2024-12-29 03:23:59 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
template<typename PAR>
|
|
|
|
|
|
auto
|
|
|
|
|
|
addValSlot (PAR paramVal)
|
|
|
|
|
|
{
|
|
|
|
|
|
return addSlot ([paramVal](TurnoutSystem&){ return paramVal; });
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-01-02 03:08:34 +01:00
|
|
|
|
|
|
|
|
|
|
/** intended for unit-testing: invoke one of the embedded param-functors */
|
|
|
|
|
|
template<size_t slot>
|
|
|
|
|
|
auto
|
|
|
|
|
|
invokeParamFun (TurnoutSystem& turnoutSys)
|
|
|
|
|
|
{
|
|
|
|
|
|
return std::get<slot> (functors_) (turnoutSys);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2024-12-29 18:27:05 +01:00
|
|
|
|
/** @internal the _chain constructor type_ is a type rebinding meta function (nested struct),
|
2025-01-04 23:56:42 +01:00
|
|
|
|
* which extends the HeteroData chain given by \a ANCH with the sequence of types derived from
|
2024-12-29 18:27:05 +01:00
|
|
|
|
* the result-values of all functors stored in the ParamBuildSpec, i.e. the resulting param tuple.
|
|
|
|
|
|
* @remark HeteroData defines a nested struct `Chain`, and with the help of `RebindVariadic`,
|
2025-01-04 23:56:42 +01:00
|
|
|
|
* the type sequence from the ParamTup can be used to instantiate this chain constructor.
|
2024-12-29 18:27:05 +01:00
|
|
|
|
*/
|
2025-01-04 19:28:58 +01:00
|
|
|
|
using ChainCons = typename lib::meta::RebindVariadic<ANCH::template Chain, ParamTup>::Type;
|
2024-12-29 18:27:05 +01:00
|
|
|
|
|
2025-01-02 03:08:34 +01:00
|
|
|
|
|
|
|
|
|
|
/** a (static) getter functor able to work on the full extended HeteroData-Chain
|
|
|
|
|
|
* @remark the front-end of this chain resides in TurnoutSystem */
|
|
|
|
|
|
template<size_t slot>
|
|
|
|
|
|
struct Accessor
|
2024-12-29 18:27:05 +01:00
|
|
|
|
{
|
2025-01-02 03:08:34 +01:00
|
|
|
|
static auto&
|
|
|
|
|
|
getParamVal (TurnoutSystem& turnoutSys)
|
|
|
|
|
|
{
|
|
|
|
|
|
using StorageAccessor = typename ChainCons::template Accessor<slot>;
|
2025-02-18 23:55:58 +01:00
|
|
|
|
return turnoutSys.retrieveData (StorageAccessor());
|
2025-01-02 03:08:34 +01:00
|
|
|
|
}
|
|
|
|
|
|
};
|
2024-12-29 18:27:05 +01:00
|
|
|
|
|
2025-01-02 03:08:34 +01:00
|
|
|
|
template<size_t idx>
|
|
|
|
|
|
Accessor<idx>
|
|
|
|
|
|
makeAccessor()
|
2025-01-01 03:23:23 +01:00
|
|
|
|
{
|
2025-01-02 03:08:34 +01:00
|
|
|
|
return Accessor<idx>{};
|
2025-01-01 03:23:23 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
2025-01-04 23:56:42 +01:00
|
|
|
|
/**
|
|
|
|
|
|
* @internal Helper: after the ParamBuildSpec is complete,
|
|
|
|
|
|
* it will be packaged into a BlockBuilder, which is then embedded
|
|
|
|
|
|
* as a kind of »Prototype« into the `Turnout<ParamWeavingPattern>`
|
|
|
|
|
|
* @remark #emplateParamDataBlock is invoked on each Node activation.
|
|
|
|
|
|
*/
|
2025-01-02 03:08:34 +01:00
|
|
|
|
class BlockBuilder
|
2024-12-29 03:23:59 +01:00
|
|
|
|
: util::MoveOnly
|
|
|
|
|
|
{
|
2025-01-02 03:08:34 +01:00
|
|
|
|
Functors functors_;
|
2024-12-29 03:23:59 +01:00
|
|
|
|
|
|
|
|
|
|
public:
|
2025-01-02 03:08:34 +01:00
|
|
|
|
/** invoke all parameter-functors and _drop off_ the result into a »chain-block« (non-copyable) */
|
|
|
|
|
|
typename ChainCons::NewFrame
|
|
|
|
|
|
buildParamDataBlock (TurnoutSystem& turnoutSys)
|
2024-12-29 03:23:59 +01:00
|
|
|
|
{
|
2025-01-02 03:08:34 +01:00
|
|
|
|
return std::apply ([&](auto&&... paramFun)
|
|
|
|
|
|
{ // invoke parameter-functors and build NewFrame from results
|
|
|
|
|
|
return ChainCons::build (paramFun (turnoutSys) ...);
|
|
|
|
|
|
}
|
|
|
|
|
|
,functors_);
|
2024-12-29 03:23:59 +01:00
|
|
|
|
}
|
2024-12-29 18:27:05 +01:00
|
|
|
|
|
2025-01-02 03:08:34 +01:00
|
|
|
|
/** invoke all parameter-functors and package all results by placement-new into a »chain-block« */
|
|
|
|
|
|
void
|
|
|
|
|
|
emplaceParamDataBlock (void* storage, TurnoutSystem& turnoutSys)
|
2024-12-29 18:27:05 +01:00
|
|
|
|
{
|
2025-01-02 03:08:34 +01:00
|
|
|
|
std::apply ([&](auto&&... paramFun)
|
|
|
|
|
|
{ // invoke parameter-functors and build NewFrame from results
|
|
|
|
|
|
ChainCons::emplace (storage, paramFun (turnoutSys) ...);
|
|
|
|
|
|
}
|
|
|
|
|
|
,functors_);
|
2024-12-29 18:27:05 +01:00
|
|
|
|
}
|
2025-01-02 03:08:34 +01:00
|
|
|
|
|
|
|
|
|
|
private:
|
|
|
|
|
|
BlockBuilder (Functors&& funz)
|
|
|
|
|
|
: functors_{move (funz)}
|
|
|
|
|
|
{ }
|
|
|
|
|
|
|
|
|
|
|
|
friend class ParamBuildSpec;
|
2024-12-29 03:23:59 +01:00
|
|
|
|
};
|
|
|
|
|
|
|
2025-01-02 03:08:34 +01:00
|
|
|
|
/**
|
|
|
|
|
|
* Terminal Builder: (destructively) transform this ParamBuildSpec
|
|
|
|
|
|
* into a BlockBuilder, which can then be used to create a Parameter data block,
|
2025-01-04 23:56:42 +01:00
|
|
|
|
* thereby invoking the embedded functors to drop-off the results into storage.
|
2025-01-02 03:08:34 +01:00
|
|
|
|
*/
|
|
|
|
|
|
BlockBuilder
|
|
|
|
|
|
makeBlockBuilder()
|
|
|
|
|
|
{
|
|
|
|
|
|
return BlockBuilder (move (functors_));
|
|
|
|
|
|
}
|
2024-12-28 23:16:55 +01:00
|
|
|
|
};
|
|
|
|
|
|
|
Invocation: fill in the wiring for a nested Port builder
unfortunately the "mechanics" of this builder setup are quite convoluted,
due to constrains with the memory manager, which basically force us to
collect a set of ''builder-λ'', together with summing up all the required storage,
so that the actual allocation of all Ports can be done into one contiguous block
of memory, to be connected to the actual Node.
For the regular `PortBuilder`, we use a helper subclass, the `WeavingBuilder`,
to construct this builderλ. But here, for the setup of an ''Param Agent Node,''
the actual wiring is much simpler and it is not justified to use a delegate builder;
rather we perfrom the complete setup directly in the terminal sub-builder operation,
prior to returning up to the NodeBuilder, which controls the overall build.
2025-01-03 23:43:51 +01:00
|
|
|
|
inline auto
|
2024-12-28 23:16:55 +01:00
|
|
|
|
buildParamSpec()
|
|
|
|
|
|
{
|
|
|
|
|
|
return ParamBuildSpec<TurnoutSystem::FrontBlock>{tuple<>{}};
|
|
|
|
|
|
}
|
2008-07-20 20:08:08 +02:00
|
|
|
|
|
2024-12-13 03:28:28 +01:00
|
|
|
|
|
2025-01-04 23:56:42 +01:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2024-12-13 03:28:28 +01:00
|
|
|
|
/**
|
2024-12-28 23:16:55 +01:00
|
|
|
|
* Implementation for a _Weaving Pattern_ to conduct extended parameter evaluation.
|
2025-01-04 23:56:42 +01:00
|
|
|
|
* A tuple of parameter-functors is embedded and will be invoked on each activation,
|
|
|
|
|
|
* to generate a tuple of parameter-values, which are placed into the local stack
|
|
|
|
|
|
* frame and then made accessible through the TurnoutSystem. Then the delegatePort_
|
|
|
|
|
|
* is invoked recursively; the additional parameter values are thus usable from
|
|
|
|
|
|
* within all nodes contained therein, during this recursive evaluation.
|
2024-12-13 03:28:28 +01:00
|
|
|
|
*/
|
2025-01-01 03:23:23 +01:00
|
|
|
|
template<class SPEC>
|
2024-12-28 21:41:08 +01:00
|
|
|
|
struct ParamWeavingPattern
|
2025-01-01 03:23:23 +01:00
|
|
|
|
: util::MoveOnly
|
2024-12-13 03:28:28 +01:00
|
|
|
|
{
|
2025-01-01 03:23:23 +01:00
|
|
|
|
using Functors = typename SPEC::Functors;
|
|
|
|
|
|
using DataBlock = typename SPEC::ChainCons::NewFrame;
|
2025-01-02 03:08:34 +01:00
|
|
|
|
using BlockBuilder = typename SPEC::BlockBuilder;
|
2025-01-02 22:40:46 +01:00
|
|
|
|
using PostProcessor = function<void(TurnoutSystem&)>;
|
2025-01-02 03:08:34 +01:00
|
|
|
|
|
|
|
|
|
|
BlockBuilder blockBuilder_;
|
2025-01-02 22:40:46 +01:00
|
|
|
|
PostProcessor postProcess_;
|
|
|
|
|
|
Port& delegatePort_;
|
2024-12-13 03:28:28 +01:00
|
|
|
|
|
2025-01-04 23:56:42 +01:00
|
|
|
|
/** Storage data frame placed on the call stack */
|
2025-01-01 03:23:23 +01:00
|
|
|
|
struct Feed
|
|
|
|
|
|
: util::NonCopyable
|
|
|
|
|
|
{
|
|
|
|
|
|
lib::UninitialisedStorage<DataBlock> buffer;
|
2025-01-02 22:40:46 +01:00
|
|
|
|
OptionalBuff outBuff;
|
2025-01-02 03:08:34 +01:00
|
|
|
|
|
|
|
|
|
|
DataBlock& block() { return buffer[0]; }
|
|
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
|
emplaceParamDataBlock (BlockBuilder& builder, TurnoutSystem& turnoutSys)
|
|
|
|
|
|
{
|
|
|
|
|
|
builder.emplaceParamDataBlock (&block(), turnoutSys);
|
|
|
|
|
|
}
|
2025-01-01 03:23:23 +01:00
|
|
|
|
};
|
2024-12-13 03:28:28 +01:00
|
|
|
|
|
|
|
|
|
|
|
2025-01-04 23:56:42 +01:00
|
|
|
|
/** forwarding-ctor to used from within Turnout, to provide actual setup. */
|
2025-01-02 22:40:46 +01:00
|
|
|
|
ParamWeavingPattern (BlockBuilder builder, PostProcessor postProc, Port& delegate)
|
2025-01-02 03:08:34 +01:00
|
|
|
|
: blockBuilder_{move (builder)}
|
2025-01-02 22:40:46 +01:00
|
|
|
|
, postProcess_{move (postProc)}
|
|
|
|
|
|
, delegatePort_{delegate}
|
2024-12-13 03:28:28 +01:00
|
|
|
|
{ }
|
|
|
|
|
|
|
|
|
|
|
|
|
2025-01-02 22:40:46 +01:00
|
|
|
|
/** Preparation: create a Feed data frame to use as local scope */
|
2024-12-13 03:28:28 +01:00
|
|
|
|
Feed
|
2025-01-04 19:28:58 +01:00
|
|
|
|
mount (TurnoutSystem&)
|
2024-12-13 03:28:28 +01:00
|
|
|
|
{
|
2025-06-20 16:09:22 +02:00
|
|
|
|
return Feed();
|
2024-12-13 03:28:28 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
2025-01-02 22:40:46 +01:00
|
|
|
|
/** Invoke the parameter-functors to create the basic parameter data */
|
2024-12-13 03:28:28 +01:00
|
|
|
|
void
|
|
|
|
|
|
pull (Feed& feed, TurnoutSystem& turnoutSys)
|
|
|
|
|
|
{
|
2025-01-02 22:40:46 +01:00
|
|
|
|
feed.emplaceParamDataBlock (blockBuilder_, turnoutSys);
|
2024-12-13 03:28:28 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
2025-01-02 22:40:46 +01:00
|
|
|
|
/** Link the param-data-block into the current TurnoutSystem,
|
|
|
|
|
|
* possibly post-process the param data. From this point on,
|
2025-01-04 23:56:42 +01:00
|
|
|
|
* Nodes within the nested scope can draw from this data.
|
2025-01-02 22:40:46 +01:00
|
|
|
|
*/
|
2024-12-13 03:28:28 +01:00
|
|
|
|
void
|
2025-01-02 22:40:46 +01:00
|
|
|
|
shed (Feed& feed, TurnoutSystem& turnoutSys, OptionalBuff outBuff)
|
2024-12-13 03:28:28 +01:00
|
|
|
|
{
|
2025-01-02 22:40:46 +01:00
|
|
|
|
turnoutSys.attachChainBlock(feed.block());
|
|
|
|
|
|
feed.outBuff = outBuff;
|
|
|
|
|
|
if (postProcess_)
|
|
|
|
|
|
postProcess_(turnoutSys);
|
2024-12-13 03:28:28 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
2025-01-02 22:40:46 +01:00
|
|
|
|
/** recursively invoke the delegate port, while the generated
|
|
|
|
|
|
* parameter-data is indirectly reachable through the TurnoutSystem
|
|
|
|
|
|
*/
|
2024-12-13 03:28:28 +01:00
|
|
|
|
void
|
2025-01-02 22:40:46 +01:00
|
|
|
|
weft (Feed& feed, TurnoutSystem& turnoutSys)
|
2024-12-13 03:28:28 +01:00
|
|
|
|
{
|
2025-01-02 22:40:46 +01:00
|
|
|
|
feed.outBuff = delegatePort_.weave (turnoutSys, feed.outBuff);
|
2025-01-04 19:28:58 +01:00
|
|
|
|
ENSURE (feed.outBuff);
|
2024-12-13 03:28:28 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
2025-01-02 22:40:46 +01:00
|
|
|
|
/** clean-up: detach the parameter-data-block.
|
|
|
|
|
|
* @return the output buffer produced by the recursive delegate call.
|
|
|
|
|
|
*/
|
2024-12-13 03:28:28 +01:00
|
|
|
|
BuffHandle
|
2025-01-02 22:40:46 +01:00
|
|
|
|
fix (Feed& feed, TurnoutSystem& turnoutSys)
|
2024-12-13 03:28:28 +01:00
|
|
|
|
{
|
2025-01-02 22:40:46 +01:00
|
|
|
|
turnoutSys.detachChainBlock(feed.block());
|
2025-01-04 19:28:58 +01:00
|
|
|
|
return *feed.outBuff;
|
2024-12-13 03:28:28 +01:00
|
|
|
|
}
|
2025-02-03 03:27:06 +01:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/** @internal expose data not dependent on the template params */
|
|
|
|
|
|
friend auto
|
|
|
|
|
|
_accessInternal(ParamWeavingPattern& patt)
|
|
|
|
|
|
{
|
|
|
|
|
|
return std::tie (patt.delegatePort_);
|
|
|
|
|
|
}
|
2024-12-13 03:28:28 +01:00
|
|
|
|
};
|
|
|
|
|
|
|
2008-07-20 20:08:08 +02:00
|
|
|
|
|
2024-12-13 03:28:28 +01:00
|
|
|
|
}}// namespace steam::engine
|
2024-12-28 21:41:08 +01:00
|
|
|
|
#endif /*STEAM_ENGINE_PARAM_WEAVING_PATTERN_H*/
|