Invocation: demonstrate complete usage cycle of extension block

In `NodeFeed_test`...
Demonstrate the base mechanism of creating a ''Param Spec'' with a
functor-definition for each parameter. This can then later be used to
invoke those functors and materialise the results into a data tuple,
and this data tuple can be linked into the TurnoutSystem, so that
the parameter values can be accessed type-safe with getter-functors.
This commit is contained in:
Fischlurch 2024-12-30 01:56:18 +01:00
parent 107d03f6ef
commit fe75bed227
4 changed files with 131 additions and 32 deletions

View file

@ -110,6 +110,8 @@ namespace lib {
template<typename SPEC>
void linkInto (HeteroData<SPEC>&);
template<typename SPEC>
void detachFrom (HeteroData<SPEC>&);
template<size_t slot> auto& get() noexcept { return std::get<slot>(*this); }
template<typename X> auto& get() noexcept { return std::get<X>(*this); }
@ -143,7 +145,8 @@ namespace lib {
_Tail&
accessTail()
{
REQUIRE (Frame::next, "HeteroData storage logic broken: follow-up extent not yet allocated");
if (Frame::next == nullptr) // Halt system by breaking noexcept
throw lumiera::error::Fatal{"HeteroData storage logic broken: follow-up extent not(yet) allocated"};
return * reinterpret_cast<_Tail*> (Frame::next);
}
@ -341,6 +344,32 @@ namespace lib {
, segments);
return last->next;
}
/**
* @internal detach the HeteroData-chain at the link to the given chainBlock.
* This enables some additional data sanity, because the internal chain can
* thus be severed when an extension data block is known to go out of scope.
* If somehow a store accessor is used after that point, the system will
* be halted when attempting to navigate to the (now defunct) data block.
*/
inline void
checkedDetach (size_t segments, StorageLoc* seg, void* chainBlock)
{
REQUIRE(seg);
while (segments and seg->next)
if (segments == 1 and seg->next == chainBlock)
{
seg->next = nullptr;
return;
}
else
{
seg = seg->next;
--segments;
}
NOTREACHED ("Failure to detach a data segment from HeteroData: "
"assumed type structure does not match real connectivity");
}
}//(End)helper
@ -369,6 +398,16 @@ namespace lib {
ENSURE (lastLink == nullptr);
lastLink = this;
}
/** cleanly detach this storage frame from the HeteroData prefix-chain. */
template<size_t seg, typename...DATA>
template<typename SPEC>
inline void
StorageFrame<seg,DATA...>::detachFrom (HeteroData<SPEC>& prefixChain)
{
StorageLoc* firstSeg = reinterpret_cast<StorageLoc*> (&prefixChain);
checkedDetach (seg, firstSeg, this);
}
}// namespace lib

View file

@ -67,10 +67,6 @@ namespace engine {
};
private:
template<class SPEC, size_t idx>
using Accessor = typename lib::HeteroData<SPEC>::template Accessor<idx>;
FrontBlock invoParam_;
public:
@ -90,19 +86,31 @@ namespace engine {
return invoParam_.get<SLOT_KEY>();
}
template<class SPEC, size_t idx>
template<class ACC>
auto&
get (Accessor<SPEC,idx> const& getter)
get (ACC const& getter)
{
return getter.get (invoParam_);
}
/** attach an extension block with further parameters
* as HeteroData-chain to the embedded FrontBlock
* @note structural properties must match, which
* is ensured when using a ParamBuildSpec.
*/
template<class CHAIN>
void
attachChainBlock (CHAIN& chainBlock)
{
chainBlock.linkInto (invoParam_);
}
template<class CHAIN>
void
detachChainBlock (CHAIN& chainBlock)
{
chainBlock.detachFrom (invoParam_);
}
};

View file

@ -27,6 +27,7 @@
#include "steam/asset/meta/time-grid.hpp"
#include "lib/several-builder.hpp"
#include "lib/time/timecode.hpp"
#include "lib/test/test-helper.hpp"
#include "lib/test/diagnostic-output.hpp"/////////////////////TODO
//#include "lib/util.hpp"
@ -36,6 +37,8 @@ using lib::Several;
using lib::makeSeveral;
using lib::time::Time;
using lib::time::FSecs;
using lib::time::FrameNr;
using lib::test::showType;
namespace steam {
@ -44,7 +47,6 @@ namespace test {
/************************************************************************//**
* @test demonstrate how to feed data into, through and out of render nodes.
*/
@ -53,6 +55,7 @@ namespace test {
virtual void
run (Arg)
{
seedRand();
feedParam();
feedParamNode();
UNIMPLEMENTED ("render node pulling source data from vault");
@ -105,35 +108,72 @@ namespace test {
result.release();
}
/** @test create extended parameter data for use in recursive Node invocation */
/** @test create extended parameter data for use in recursive Node invocation.
* - demonstrate the mechanism of param-functor invocation,
* and how a Param-Spec is built to create and hold those functors
* - then instantiate an actual TurnoutSystem, as is done for a Node invocation,
* with an embedded »absolute nominal time« parameter value
* - can then invoke the param-functors and materialise results into a Param-Data-Block
* - which then can be linked internally to be reachable through the TurnoutSystem
* - other code further down the call-stack can thus access those parameter values.
* - The second part of the test uses the same scheme embedded into a Param(Agent)Node
*/
void
feedParamNode()
{
steam::asset::meta::TimeGrid::build("grid_sec", 1);
// Parameter-functor based on time-quantisation into a 1-seconds-grid
auto fun1 = [](TurnoutSystem& turSys)
{
return lib::time::FrameNr::quant (turSys.getNomTime(), "grid_sec");
return FrameNr::quant (turSys.getNomTime(), "grid_sec");
};
// The Param-Spec is used to coordinate type-safe access
// and also is used as a blueprint for building a Param(Agent)Node
auto spec = buildParamSpec()
.addValSlot (LIFE_AND_UNIVERSE_4EVER)
.addSlot (move (fun1))
;
using Spec = decltype(spec);
SHOW_TYPE(Spec)
SHOW_TYPE(Spec::ParamTup)
TurnoutSystem turnoutSys{Time{FSecs(5,2)}};
// The implied type of the parameter-tuple to generate
using ParamTup = decltype(spec)::ParamTup;
CHECK (showType<ParamTup>() == "tuple<uint, long>"_expect);
// can now store accessor-functors for later use....
auto acc0 = spec.slot<0>().makeAccessor();
auto acc1 = spec.slot<1>().makeAccessor();
// 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);
SHOW_EXPR(v0)
SHOW_EXPR(v1)
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
auto paramBlock = spec.buildParamDataBlock (turnoutSys);
SHOW_EXPR(paramBlock)
SHOW_EXPR(paramBlock.get<0>())
SHOW_EXPR(paramBlock.get<1>())
{ // Now build an actual storage block in local scope,
// thereby invoking the embedded parameter-functors...
auto paramBlock = spec.buildParamDataBlock (turnoutSys);
// Values are now materialised into paramBlock
CHECK (v0 == paramBlock.get<0>());
CHECK (v1 == paramBlock.get<1>());
// link this extension block into the parameter-chain in TurnoutSystem
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));
// should detach extension block before leaving scope
turnoutSys.detachChainBlock(paramBlock);
}
TODO ("implement a simple Builder for ParamAgent-Node");
TODO ("then use both together to demonstrate a param data feed here");

View file

@ -82336,8 +82336,19 @@ Date:&#160;&#160;&#160;Thu Apr 20 18:53:17 2023 +0200<br/>
<node CREATED="1735353775789" ID="ID_1394846816" MODIFIED="1735353797045" TEXT="dazu ist ein Funktor-Typ definiert"/>
<node CREATED="1735353798274" ID="ID_1422658744" MODIFIED="1735353856467" TEXT="und ein Accessor-Typ">
<node CREATED="1735353948999" ID="ID_1107757772" MODIFIED="1735353956728" TEXT="dieser findet zum Slot zur&#xfc;ck"/>
<node CREATED="1735353970175" ID="ID_542964897" MODIFIED="1735353992387" TEXT="und ist eine Erweiterung der HeteroData-Accessoren">
<node CREATED="1735353994703" ID="ID_755528962" MODIFIED="1735354004015" TEXT="vielleicht gar keine Erweiterung?"/>
<node CREATED="1735353970175" ID="ID_542964897" MODIFIED="1735519560792" TEXT="und ist ein HeteroData-Accessor"/>
<node CREATED="1735519565352" ID="ID_646241396" MODIFIED="1735519667848" TEXT="mit dem TurnoutSystem als Front-Block">
<richcontent TYPE="NOTE"><html>
<head>
</head>
<body>
<p>
Das hei&#223;t, hier haben wir immer einen festen Satz an Parametern, die stets im TurnoutSystem eingebettet vorliegen; diese k&#246;nnen aber als HeteroData-Chain erweitert werden um die Bl&#246;cke, die wir &#252;ber eine (oder eine Kette von) ParamBuildSpec erzeugen
</p>
</body>
</html>
</richcontent>
</node>
</node>
</node>
@ -94180,8 +94191,9 @@ Date:&#160;&#160;&#160;Thu Apr 20 18:53:17 2023 +0200<br/>
<linktarget COLOR="#4033e3" DESTINATION="ID_348960119" ENDARROW="Default" ENDINCLINATION="-2228;-103;" ID="Arrow_ID_1086551966" SOURCE="ID_1769136387" STARTARROW="None" STARTINCLINATION="1977;97;"/>
<linktarget COLOR="#ff6936" DESTINATION="ID_348960119" ENDARROW="Default" ENDINCLINATION="-641;1944;" ID="Arrow_ID_1163958018" SOURCE="ID_311704401" STARTARROW="None" STARTINCLINATION="1383;132;"/>
<icon BUILTIN="pencil"/>
<node CREATED="1735416170297" ID="ID_736958022" MODIFIED="1735416236279" TEXT="brauche ParamBuildSpec">
<node BACKGROUND_COLOR="#c8c0b6" COLOR="#435e98" CREATED="1735416170297" ID="ID_736958022" MODIFIED="1735519479807" TEXT="brauche ParamBuildSpec">
<linktarget COLOR="#bb1f2e" DESTINATION="ID_736958022" ENDARROW="Default" ENDINCLINATION="-25;-162;" ID="Arrow_ID_44922252" SOURCE="ID_1577179744" STARTARROW="None" STARTINCLINATION="32;153;"/>
<icon BUILTIN="yes"/>
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1735422554816" ID="ID_197118422" MODIFIED="1735438575232" TEXT="Aufgabe: schrittweise aufbaubar">
<icon BUILTIN="flag-yellow"/>
<node CREATED="1735422591091" ID="ID_1649575055" MODIFIED="1735422735480" TEXT="Diskrepanz zu den HeteroData Chain-Blocks">
@ -94235,8 +94247,8 @@ Date:&#160;&#160;&#160;Thu Apr 20 18:53:17 2023 +0200<br/>
<node CREATED="1735486938666" ID="ID_1675979650" MODIFIED="1735487816128" TEXT="also direkt anwendbar auf&apos;s Turnout-System"/>
</node>
</node>
<node BACKGROUND_COLOR="#eef0c5" COLOR="#990000" CREATED="1735427341106" ID="ID_29906476" MODIFIED="1735427368610" TEXT="L&#xf6;sung aufbauen...">
<icon BUILTIN="pencil"/>
<node COLOR="#338800" CREATED="1735427341106" ID="ID_29906476" MODIFIED="1735519449554" TEXT="L&#xf6;sung aufbauen...">
<icon BUILTIN="button_ok"/>
<node CREATED="1735427377686" ID="ID_1047293090" MODIFIED="1735427389228" TEXT="Typisierung">
<node CREATED="1735427448052" ID="ID_1835841396" MODIFIED="1735427511976" TEXT="mu&#xdf; komplett explizit sein">
<richcontent TYPE="NOTE"><html>
@ -94298,8 +94310,8 @@ Date:&#160;&#160;&#160;Thu Apr 20 18:53:17 2023 +0200<br/>
<linktarget COLOR="#637488" DESTINATION="ID_870944737" ENDARROW="Default" ENDINCLINATION="310;0;" ID="Arrow_ID_1871378220" SOURCE="ID_1331974543" STARTARROW="None" STARTINCLINATION="145;9;"/>
</node>
</node>
<node BACKGROUND_COLOR="#eef0c5" COLOR="#990000" CREATED="1735438595508" ID="ID_696254160" MODIFIED="1735438784764" TEXT="Implementierung">
<icon BUILTIN="pencil"/>
<node COLOR="#338800" CREATED="1735438595508" ID="ID_696254160" MODIFIED="1735519446480" TEXT="Implementierung">
<icon BUILTIN="button_ok"/>
<node COLOR="#338800" CREATED="1735438607044" ID="ID_1948837984" MODIFIED="1735438628651" TEXT="Builder-Anker: buildParamSpec()">
<icon BUILTIN="button_ok"/>
</node>
@ -94311,13 +94323,13 @@ Date:&#160;&#160;&#160;Thu Apr 20 18:53:17 2023 +0200<br/>
<node CREATED="1735438678865" ID="ID_548533062" MODIFIED="1735438686677" TEXT="&#xe4;hnlich wie f&#xfc;r die FeedManifold"/>
<node CREATED="1735438687997" ID="ID_283878162" MODIFIED="1735438699784" TEXT="verwendet lib::meta::ElmTypes :: Apply"/>
</node>
<node BACKGROUND_COLOR="#eef0c5" COLOR="#990000" CREATED="1735438707680" ID="ID_1085577180" MODIFIED="1735438715228" TEXT="Zugriffs-Slot">
<icon BUILTIN="pencil"/>
<node COLOR="#338800" CREATED="1735438707680" ID="ID_1085577180" MODIFIED="1735519443885" TEXT="Zugriffs-Slot">
<icon BUILTIN="button_ok"/>
<node COLOR="#338800" CREATED="1735438717070" ID="ID_1429780349" MODIFIED="1735438724209" TEXT="jeweiligen Funktor aufrufen">
<icon BUILTIN="button_ok"/>
</node>
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1735438726120" ID="ID_1670785950" MODIFIED="1735438739642" TEXT="Daten-Accessor konstruieren">
<icon BUILTIN="flag-yellow"/>
<node COLOR="#338800" CREATED="1735438726120" ID="ID_1670785950" MODIFIED="1735519440292" TEXT="Daten-Accessor konstruieren">
<icon BUILTIN="button_ok"/>
<node CREATED="1735487309329" ID="ID_1516453754" MODIFIED="1735487326656" TEXT="Bassis sind Accessoren auf HeteroData"/>
<node CREATED="1735489834862" ID="ID_1311598461" MODIFIED="1735489845645" TEXT="mu&#xdf; dazu den Chain-Block-Typ konstruieren">
<node CREATED="1735489850973" ID="ID_1621449411" MODIFIED="1735489863415" TEXT="aus dem Anker-Typ :: Chain"/>