Dispatcher-Pipeline: allocate JobTicket in Segment

PROBLEM: can not implement Spec-generation, since
 - we must use a λ for internal allocation of JobTickets
 - but recursive type inference is not possible

Will thus need to abandon the Spec-Tuple and relocate this
traversal-and-generation code into JobTicket itself
This commit is contained in:
Fischlurch 2023-06-09 02:48:38 +02:00
parent c246c21e41
commit 2c3b85a122
9 changed files with 299 additions and 66 deletions

View file

@ -34,6 +34,7 @@
#include "lib/nocopy.hpp"
#include "lib/hash-value.h"
#include "lib/iter-adapter-stl.hpp"
#include "vault/engine/job.h" //////////////////////////////////////////////////////////////////TICKET #1295 : rather need a way to retrieve a real JobFunctor building block from the ProcNode
#include <deque>
@ -46,6 +47,7 @@ namespace engine {
class ExitNode;
using ExitNodes = std::deque<engine::ExitNode>;
using vault::engine::JobFunctor;
/**
@ -64,6 +66,7 @@ namespace engine {
{
HashVal pipelineIdentity_; //////////////////////////////////////////////////////////TICKET #1293 : Hash-Chaining for invocation-ID... derive from ProcNode wiring
ExitNodes prerequisites_; ///////////////////////////////////////////////////////////TICKET #1306 : actual access to low-level-Model (ProcNode)
JobFunctor* action_{nullptr}; ////////////////////////////////////////////////////////////TICKET #1295 : link to actual implementation action in low-level-Model
public:
ExitNode()
@ -71,14 +74,24 @@ namespace engine {
, prerequisites_{}
{ }
ExitNode (HashVal id, ExitNodes&& prereq =ExitNodes{})
ExitNode (HashVal id
,ExitNodes&& prereq =ExitNodes{}
,JobFunctor* functor =nullptr)
: pipelineIdentity_{id}
, prerequisites_{std::move (prereq)}
, action_{functor}
{ }
static ExitNode NIL;
bool
empty() const
{
return 0 == pipelineIdentity_
or not action_;
}
HashVal
getPipelineIdentity() const
{
@ -90,6 +103,13 @@ namespace engine {
{
return lib::iter_stl::eachElm (prerequisites_);
}
JobFunctor&
getInvocationFunctor() const
{
REQUIRE (action_);
return *action_; ///////////////////////////////////////////////////////////////////////TICKET #1295 : decision on actual JobFunctor and invocation parameters
}
};

View file

@ -39,6 +39,7 @@
//#include "steam/state.hpp"
#include "vault/engine/job.h"
#include "steam/engine/frame-coord.hpp"
#include "steam/engine/exit-node.hpp"
//#include "lib/time/timevalue.hpp"
//#include "lib/time/timequant.hpp"
#include "lib/hierarchy-orientation-indicator.hpp"
@ -111,12 +112,14 @@ using lib::LUID;
struct Provision
{
Provision* next{nullptr};
JobFunctor& jobFunctor;
JobFunctor& jobFunctor;
ExitNode const& exitNode;
InvocationInstanceID invocationSeed;
Prerequisites requirements{};
////////////////////TODO some channel or format descriptor here
Provision (JobFunctor& func, HashVal seed =0)
Prerequisites requirements{};
Provision (JobFunctor& func, ExitNode const& node, HashVal seed =0)
: jobFunctor{func}
, exitNode{node}
, invocationSeed(static_cast<JobClosure&>(func).buildInstanceID(seed)) ////////////////TICKET #1287 : fix actual interface down to JobFunctor (after removing C structs)
{ } /////////////////TICKET #1293 : Hash-Chaining for invocation-ID... size_t hash? or a LUID?
};
@ -302,12 +305,14 @@ using lib::LUID;
static_assert (lib::meta::can_IterForEach<IT>::value); // -- can be iterated
using Spec = typename IT::value_type;
static_assert (lib::meta::is_Tuple<Spec>()); // -- payload of iterator is a tuple
using Func = typename std::tuple_element<0, Spec>::type;
using Node = typename std::tuple_element<0, Spec>::type;
using Seed = typename std::tuple_element<1, Spec>::type;
using Preq = typename std::tuple_element<2, Spec>::type;
static_assert (lib::meta::is_basically<Func, JobFunctor>()); // -- first component specifies the JobFunctor to use
using Func = typename std::tuple_element<2, Spec>::type;
using Preq = typename std::tuple_element<3, Spec>::type;
static_assert (lib::meta::is_basically<Node, ExitNode>()); // -- first component refers to the ExitNode in the model
static_assert (lib::meta::is_basically<Seed, HashVal>()); // -- second component provides a specific seed for Invocation-IDs
static_assert (lib::meta::can_IterForEach<Preq>::value); // -- third component is again an iterable sequence
static_assert (lib::meta::is_basically<Func, JobFunctor>()); // -- third component specifies the JobFunctor to use
static_assert (lib::meta::can_IterForEach<Preq>::value); // -- fourth component is again an iterable sequence
static_assert (std::is_same<typename Preq::value_type, JobTicket>()); // -- which yields JobTicket prerequisites
REQUIRE (not isnil (featureSpec)
,"require at least specification for one channel");
@ -315,10 +320,11 @@ using lib::LUID;
LinkedElements<Provision> provisionSpec; //////////////////////////////////////////////////TICKET #1292 : need to pass in Allocator as argument
for ( ; featureSpec; ++featureSpec) ///////////////////////////////////////////////////TICKET #1297 : this additional iteration over channels will go away
{
JobFunctor& func = std::get<0> (*featureSpec);
ExitNode& node = std::get<0> (*featureSpec);
HashVal invoSeed = std::get<1> (*featureSpec);
auto& provision = provisionSpec.emplace<Provision> (func, invoSeed);
for (Preq pre = std::get<2> (*featureSpec); pre; ++pre)
JobFunctor& func = std::get<2> (*featureSpec);
auto& provision = provisionSpec.emplace<Provision> (func, node, invoSeed);
for (Preq pre = std::get<3> (*featureSpec); pre; ++pre)
provision.requirements.emplace<Prerequisite> (*pre);
}
provisionSpec.reverse(); // retain order of given definitions per channel ////////////TICKET #1297 : obsolete; instead we differentiate by OutputSlot in the Segment

View file

@ -38,6 +38,7 @@
#include "steam/engine/exit-node.hpp"
//#include "lib/time/timevalue.hpp"
#include "lib/util.hpp"
#include <utility>
@ -80,6 +81,12 @@ namespace fixture {
return idx < exitNodes_.size()? exitNodes_[idx]
: ExitNode::NIL;
}
bool
empty() const
{
return util::isnil (exitNodes_);
}
};

View file

@ -37,9 +37,12 @@
#include "steam/mobject/explicitplacement.hpp"
#include "steam/engine/job-ticket.hpp"
#include "lib/time/timevalue.hpp"
#include "lib/itertools.hpp"
#include "lib/util.hpp"
#include <utility>
#include <list>
#include <deque>
#include <tuple>
namespace steam {
@ -48,7 +51,7 @@ namespace fixture {
using mobject::ExplicitPlacement;
using lib::time::TimeSpan;
using lib::time::Time;
using std::list;
using util::unConst;
using std::move;
/**
@ -64,17 +67,21 @@ namespace fixture {
*/
class Segment
{
using TicketAlloc = std::deque<engine::JobTicket>;
using PortTable = std::deque<std::reference_wrapper<engine::JobTicket>>;
protected:
/** begin of this timeline segment. */
TimeSpan span_;
/** render plan / blueprint to use for this segment */
const engine::JobTicket* jobTicket_; ////////////////////////////////////////////////////TICKET #1297 : probably we'll get an array per ModelPort here
TicketAlloc tickets_;
PortTable portTab_;
///////////////////////////////////////////////////////////////////////////////////////////////////////TICKET #725 : placeholder code
/** relevant MObjects comprising this segment. */
list<ExplicitPlacement> elements;
std::deque<ExplicitPlacement> elements;
// TODO: actually necessary??
// TODO: ownership??
///////////////////////////////////////////////////////////////////////////////////////////////////////TICKET #725 : placeholder code
@ -83,18 +90,21 @@ namespace fixture {
Segment (TimeSpan covered =TimeSpan::ALL
,const engine::JobTicket* ticket =nullptr)
: span_{covered}
, jobTicket_{ticket? ticket : &engine::JobTicket::NOP} //////////////////////////////////////////TICKET #1297 : ensure to provide a JobTicket for each ModelPort in initialisation
// , tickets_{ticket? ticket : &engine::JobTicket::NOP} //////////////////////////////////////////TICKET #1297 : ensure to provide a JobTicket for each ModelPort in initialisation
{ }
/////////////////////////////////////////////////////////////////////////////////////////////////////////////TODO Obsolet ... nur für Umbau erhalten!!
Segment (TimeSpan covered
,NodeGraphAttachment&& modelLink)
: span_{covered}
, tickets_{}
, portTab_{}
, exitNode{move (modelLink)}
{ }
Segment (Segment const& original, TimeSpan changed)
: span_{changed}
, jobTicket_{original.jobTicket_}
, tickets_{} // Note: not cloning tickets owned by Segment
, portTab_{}
, exitNode{original.exitNode} /////////////////////////////////////////////////////////////////////OOO really? cloning ExitNodes?
{ }
@ -108,16 +118,63 @@ namespace fixture {
engine::JobTicket const&
jobTicket() const /////////////////////////////////////////////////////////////////TICKET #1297 : introduce additional key per ModelPort here
jobTicket (size_t portNr) const
{
REQUIRE (jobTicket_);
return *jobTicket_;
if (portNr >= portTab_.size())
unConst(this)->generateTickets_onDemand (portNr);
ASSERT (portNr < portTab_.size());
return portTab_[portNr];
}
bool
empty() const
{
return jobTicket().empty();
return exitNode.empty();
}
private:
/** @internal Generate sequence of prerequisite JobTicket */
auto
assemblePrerequisites (ExitNode const& exitNode)
{
return lib::transformIterator (exitNode.getPrerequisites()
,[this](ExitNode const& prereq) -> engine::JobTicket&
{
tickets_.emplace_back(
assembleTicketSpec (prereq));
return tickets_.back();
});
}
/** @internal Traverse ExitNode structure and prepare JobTicket */
auto
assembleTicketSpec (ExitNode const& exitNode)
{
REQUIRE (not isnil (exitNode)); // has valid functor
using vault::engine::JobFunctor;
using Prereqs = decltype(assemblePrerequisites (exitNode));
using SpecTuple = std::tuple<ExitNode const&, HashVal, JobFunctor&, Prereqs>;
return lib::singleValIterator( /////////////////////////////////////////TICKET #1297 : multiplicity per channel will be removed here
SpecTuple(exitNode
,exitNode.getPipelineIdentity()
,exitNode.getInvocationFunctor()
,assemblePrerequisites (exitNode)
));
}
void
generateTickets_onDemand (size_t portNr)
{
for (size_t i = portTab_.size(); i <= portNr; ++i)
if (isnil (exitNode[portNr]))
portTab_.emplace_back (engine::JobTicket::NOP); // disable this slot
else
{// Ticket was not generated yet...
tickets_.emplace_back (assembleTicketSpec (exitNode[portNr]));
portTab_.emplace_back (tickets_.back()); // ref to new ticket ‣ slot
}
}
};

View file

@ -130,7 +130,7 @@ namespace test {
)
.genNode()};
fixture::Segment const& seg = mockSegs[Time{0,15}]; // access anywhere 10s <= t < 20s
JobTicket const& ticket = seg.jobTicket(); // get the master-JobTicket from this segment
JobTicket const& ticket = seg.jobTicket(0); // get the master-JobTicket from this segment
JobTicket const& prereq = *(ticket.getPrerequisites()); // pull a prerequisite JobTicket
FrameCoord coord; // Frame coordinates for invocation (placeholder)

View file

@ -97,9 +97,10 @@ namespace test {
inline auto
defineSpec (HashVal seed, IT&& prereq)
{
using SpecTuple = std::tuple<JobFunctor&, HashVal, IT>;
using SpecTuple = std::tuple<ExitNode const&, JobFunctor&, HashVal, IT>;
return lib::singleValIterator( /////////////////////////////////////////////TICKET #1297 : multiplicity per channel will be removed here
SpecTuple(DummyJob::getFunctor()
SpecTuple(ExitNode::NIL
,DummyJob::getFunctor()
, seed
, std::forward<IT> (prereq)));
}

View file

@ -86,7 +86,7 @@ namespace test {
CHECK (3 == mockSegs.size());
fixture::Segment const& seg = mockSegs[Time{0,15}]; // access anywhere 10s <= t < 20s
JobTicket const& ticket = seg.jobTicket(); ///////////////////////////////////////////////////TICKET #1297 : will need to pass a ModelPort number here (use the first one, i.e. 0)
JobTicket const& ticket = seg.jobTicket(0);
FrameCoord coord;
coord.absoluteNominalTime = Time(0,15);
@ -166,7 +166,7 @@ namespace test {
{
MockSegmentation mockSeg;
CHECK (1 == mockSeg.size());
JobTicket const& ticket = mockSeg[someTime].jobTicket();
JobTicket const& ticket = mockSeg[someTime].jobTicket(0); // just probe JobTicket generated for Model-Port-Nr.0
CHECK (util::isSameObject (ticket, JobTicket::NOP));
}
//-----------------------------------------------------------------/// Segmentation with one default segment spanning complete timeline
@ -175,7 +175,7 @@ namespace test {
CHECK (1 == mockSegs.size());
CHECK (Time::MIN == mockSegs[someTime].start());
CHECK (Time::MAX == mockSegs[someTime].after());
JobTicket const& ticket = mockSegs[someTime].jobTicket();
JobTicket const& ticket = mockSegs[someTime].jobTicket(0);
CHECK (not util::isSameObject (ticket, JobTicket::NOP));
Job someJob = ticket.createJobFor(coord); // JobTicket uses, but does not check the time given in FrameCoord
@ -204,12 +204,12 @@ namespace test {
// while the left part of the axis is marked as NOP / empty
fixture::Segment const& seg1 = mockSegs[Time::ZERO]; // access anywhere < 10s
fixture::Segment const& seg2 = mockSegs[Time{0,20}]; // access anywhere >= 10s
CHECK ( util::isSameObject (seg1.jobTicket(), JobTicket::NOP));
CHECK (not util::isSameObject (seg2.jobTicket(), JobTicket::NOP));// this one is the active segment
CHECK ( util::isSameObject (seg1.jobTicket(0),JobTicket::NOP));
CHECK (not util::isSameObject (seg2.jobTicket(0),JobTicket::NOP));// this one is the active segment
Job job = seg2.jobTicket().createJobFor(coord);
CHECK (not MockJobTicket::isAssociated (job, seg1.jobTicket()));
CHECK ( MockJobTicket::isAssociated (job, seg2.jobTicket()));
Job job = seg2.jobTicket(0).createJobFor(coord);
CHECK (not MockJobTicket::isAssociated (job, seg1.jobTicket(0)));
CHECK ( MockJobTicket::isAssociated (job, seg2.jobTicket(0)));
CHECK (marker == job.parameter.invoKey.part.a);
job.triggerJob();
@ -218,10 +218,10 @@ namespace test {
CHECK (marker == DummyJob::invocationAdditionalKey (job)); // DummyClosure is rigged such as to feed back the seed in `part.a`
// and thus we can prove this job really belongs to the marked segment
// create another job from the (empty) seg1
job = seg1.jobTicket().createJobFor (coord);
job = seg1.jobTicket(0).createJobFor (coord);
InvocationInstanceID empty; /////////////////////////////////////////////////////////////////////TICKET #1287 : temporary workaround until we get rid of the C base structs
CHECK (lumiera_invokey_eq (&job.parameter.invoKey, &empty)); // indicates that it's just a placeholder to mark a "NOP"-Job
CHECK (seg1.jobTicket().empty());
CHECK (seg1.jobTicket(0).empty());
CHECK (seg1.empty());
CHECK (not seg2.empty());
}
@ -290,7 +290,7 @@ namespace test {
{
if (segment.empty()) return 0;
Job job = segment.jobTicket().createJobFor(coord);
Job job = segment.jobTicket(0).createJobFor(coord);
job.triggerJob();
CHECK (DummyJob::was_invoked (job));
CHECK (RealClock::wasRecently (DummyJob::invocationTime (job)));
@ -325,7 +325,7 @@ namespace test {
.genNode())
.genNode()};
CHECK (1 == mockSegs.size());
JobTicket const& ticket = mockSegs[Time::ZERO].jobTicket();
JobTicket const& ticket = mockSegs[Time::ZERO].jobTicket(0); // Model-PortNr.0
auto prereq = ticket.getPrerequisites();
CHECK (not isnil (prereq));
@ -360,7 +360,7 @@ namespace test {
.genNode())
.genNode()};
auto start = singleValIterator (mockSegs[Time::ZERO].jobTicket());
auto start = singleValIterator (mockSegs[Time::ZERO].jobTicket(0));
auto it = lib::explore(start)
.expand ([](JobTicket const& ticket)

View file

@ -43,6 +43,9 @@ namespace test {
using util::isSameObject;
using engine::ExitNode;
using lib::diff::MakeRec;
using engine::Job;
using engine::JobTicket;
using engine::test::MockSegmentation;
@ -101,16 +104,26 @@ namespace test {
.genNode()
)
.genNode()};
UNIMPLEMENTED("fabricate JobTicket from ExitNode-Graph");
// // verify generated Node is assembled according to above spec...
// CHECK (13 == node.getPipelineIdentity());
// auto feed = node.getPrerequisites();
// CHECK (not isnil (feed));
// CHECK (23 == feed->getPipelineIdentity());
// ++feed;
// CHECK (55 == feed->getPipelineIdentity());
// ++feed;
// CHECK (isnil (feed));
CHECK (1 == segmentation.size()); // whole time axis covered by one segment
Segment const& seg = segmentation[Time::ANYTIME]; // thus accessed time point is irrelevant
// verify mapped JobTicket is assembled according to above spec...
auto getMarker = [](JobTicket const& ticket)
{
FrameCoord dummyFrame;
Job job = ticket.createJobFor(dummyFrame);
return job.parameter.invoKey.part.a;
};
JobTicket const& ticket = seg.jobTicket(0);
CHECK (13 == getMarker (ticket));
auto prereq = ticket.getPrerequisites();
CHECK (not isnil(prereq));
CHECK (23 == getMarker (*prereq));
++prereq;
CHECK (55 == getMarker (*prereq));
++prereq;
CHECK (isnil(prereq));
}
};

View file

@ -74111,8 +74111,76 @@ Date:&#160;&#160;&#160;Thu Apr 20 18:53:17 2023 +0200<br/>
</node>
<node BACKGROUND_COLOR="#fdfdcf" COLOR="#ff0000" CREATED="1686011373412" ID="ID_1341039933" MODIFIED="1686090506568" TEXT="Erzeugung l&#xe4;uft nun &#xfc;ber den realen JobTicket-ctor">
<icon BUILTIN="messagebox_warning"/>
<node CREATED="1686090517445" ID="ID_7221274" MODIFIED="1686090544501" TEXT="zum Gl&#xfc;ck bleibt die eigentliche Logik strukturell gleich"/>
<node CREATED="1686090545569" ID="ID_1454267269" MODIFIED="1686090574166" TEXT="nun werden eben geFakete Exit-Nodes intern gehalten"/>
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1686090517445" ID="ID_7221274" MODIFIED="1686270873897" TEXT="zum Gl&#xfc;ck bleibt die eigentliche Logik strukturell gleich">
<icon BUILTIN="idea"/>
</node>
<node COLOR="#338800" CREATED="1686090545569" ID="ID_1454267269" MODIFIED="1686270818455" TEXT="nun werden eben geFakete Exit-Nodes intern gehalten">
<icon BUILTIN="button_ok"/>
</node>
<node CREATED="1686270785030" ID="ID_888586974" MODIFIED="1686270864625" TEXT="sp&#xe4;ter werden Exit-Nodes wohl ins low-level-Model wandern">
<icon BUILTIN="yes"/>
</node>
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1686270836231" ID="ID_1399765030" MODIFIED="1686270855660" TEXT="herausfinden wie der realte JobTicket-ctor sinnvoll funktionieren kann">
<icon BUILTIN="flag-yellow"/>
</node>
</node>
<node BACKGROUND_COLOR="#e0ceaa" COLOR="#690f14" CREATED="1686263939639" ID="ID_1524676047" MODIFIED="1686270573171" STYLE="fork" TEXT="Problem: Enscheidung &#xfc;ber JobFunctor noch nicht m&#xf6;glich">
<linktarget COLOR="#535ca3" DESTINATION="ID_1524676047" ENDARROW="Default" ENDINCLINATION="321;15;" ID="Arrow_ID_176648571" SOURCE="ID_116606381" STARTARROW="None" STARTINCLINATION="-298;0;"/>
<font NAME="SansSerif" SIZE="12"/>
<icon BUILTIN="messagebox_warning"/>
<node BACKGROUND_COLOR="#d2beaf" COLOR="#5c4d6e" CREATED="1686263988480" ID="ID_410782667" MODIFIED="1686270571977" TEXT="sp&#xe4;ter wird das von der tats&#xe4;chlichen ProcNode abh&#xe4;ngen">
<icon BUILTIN="info"/>
</node>
<node BACKGROUND_COLOR="#f0d5c5" COLOR="#990033" CREATED="1686264027146" ID="ID_517145334" MODIFIED="1686270571977" TEXT="die ganze Infrastruktur ist ungekl&#xe4;rt">
<icon BUILTIN="hourglass"/>
</node>
<node COLOR="#338800" CREATED="1686264084220" ID="ID_584564107" MODIFIED="1686270586163" TEXT="f&#xfc;r Test: DummyJob-Functor injizieren">
<icon BUILTIN="button_ok"/>
<node BACKGROUND_COLOR="#e0ceaa" COLOR="#690f14" CREATED="1686264107951" ID="ID_1608571844" MODIFIED="1686270581791" TEXT="problematisch da es kein Testcode ist">
<icon BUILTIN="messagebox_warning"/>
</node>
<node COLOR="#5b280f" CREATED="1686264869561" ID="ID_195925154" MODIFIED="1686270571977" TEXT="Dependency-Injection + Mock nutzen">
<icon BUILTIN="button_cancel"/>
<node CREATED="1686264885982" ID="ID_1039850436" MODIFIED="1686270571978" TEXT="dann k&#xf6;nnte man test::DummyJob injizieren">
<icon BUILTIN="idea"/>
</node>
<node BACKGROUND_COLOR="#e0ceaa" COLOR="#690f14" CREATED="1686264912495" ID="ID_1612660724" MODIFIED="1686270571978" TEXT="NEIN! das wird irre komplex mit den lokalen Scopes">
<richcontent TYPE="NOTE"><html>
<head>
</head>
<body>
<p>
ich will f&#252;r den ganzen Mock-Support eine L&#246;sung, die &#8222;einfach funktioniert&#8220; &#8212; sofern man mit einer Instanz von MockSegmentation bzw. MockDispatcher arbeitet (und sonst nichts beeinflu&#223;t)
</p>
</body>
</html></richcontent>
<icon BUILTIN="stop-sign"/>
</node>
</node>
<node BACKGROUND_COLOR="#d2beaf" COLOR="#5c4d6e" CREATED="1686265008565" ID="ID_281343895" MODIFIED="1686270571978" TEXT="vorl&#xe4;ufig....">
<icon BUILTIN="idea"/>
<node COLOR="#338800" CREATED="1686265022475" ID="ID_462302958" MODIFIED="1686270632352" TEXT="nullptr als Fallback (f&#xfc;r einfache Tests)">
<icon BUILTIN="button_ok"/>
</node>
<node COLOR="#338800" CREATED="1686265038081" ID="ID_889617435" MODIFIED="1686270657046" TEXT="(optional) explizit einen JobFunctor-Pointer in die ExitNode legen">
<richcontent TYPE="NOTE"><html>
<head>
</head>
<body>
<p>
...denn das entspricht noch am Meisten dem sp&#228;ter mal erwarteten Ablauf
</p>
</body>
</html></richcontent>
<icon BUILTIN="button_ok"/>
</node>
<node COLOR="#338800" CREATED="1686270634650" ID="ID_1375749539" MODIFIED="1686270658949" TEXT="falls nicht definiert: JobTicket::NOP zur&#xfc;ckliefern">
<icon BUILTIN="button_ok"/>
</node>
</node>
</node>
</node>
<node BACKGROUND_COLOR="#fdfdcf" COLOR="#ff0000" CREATED="1686090622242" ID="ID_671795357" MODIFIED="1686090648184" TEXT="MockSupport_test l&#xe4;uft weiterhin ohne jedwede Anpassung">
<icon BUILTIN="flag-pink"/>
@ -74177,28 +74245,32 @@ Date:&#160;&#160;&#160;Thu Apr 20 18:53:17 2023 +0200<br/>
</node>
<node BACKGROUND_COLOR="#fdfdcf" COLOR="#ff0000" CREATED="1686009434197" ID="ID_1874481686" MODIFIED="1686009466526" TEXT="mu&#xdf; nun Segment / JobTicket-Erzeugung umstellen">
<icon BUILTIN="messagebox_warning"/>
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1686088955494" ID="ID_683990266" MODIFIED="1686088990055" TEXT="Segment bekommt nun ein NodeGraphAttachment">
<icon BUILTIN="flag-yellow"/>
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1686089017579" ID="ID_178364599" MODIFIED="1686089082884" TEXT="dieses bietet Array-Access auf die ExitNodes">
<icon BUILTIN="flag-yellow"/>
<node COLOR="#338800" CREATED="1686088955494" ID="ID_683990266" MODIFIED="1686263708546" TEXT="Segment bekommt nun ein NodeGraphAttachment">
<icon BUILTIN="button_ok"/>
<node COLOR="#338800" CREATED="1686089017579" ID="ID_178364599" MODIFIED="1686263704530" TEXT="dieses bietet Array-Access auf die ExitNodes">
<icon BUILTIN="button_ok"/>
<node CREATED="1686089092489" ID="ID_579545168" MODIFIED="1686089092489" TEXT="...in ModelPort-Reihenfolge"/>
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1686089096760" ID="ID_306119444" MODIFIED="1686089158236" TEXT="fehlertolerant &#x2016; ersatzweise ExitNode::NIL">
<icon BUILTIN="flag-yellow"/>
<node COLOR="#338800" CREATED="1686089096760" ID="ID_306119444" MODIFIED="1686263534817" TEXT="fehlertolerant &#x2016; ersatzweise ExitNode::NIL">
<icon BUILTIN="button_ok"/>
</node>
</node>
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1686089194310" ID="ID_1557640858" MODIFIED="1686089229114" TEXT="ExitNode bietet Pipeline identity hash">
<icon BUILTIN="flag-yellow"/>
<node COLOR="#338800" CREATED="1686089194310" ID="ID_1557640858" MODIFIED="1686263706221" TEXT="ExitNode bietet Pipeline identity hash">
<icon BUILTIN="button_ok"/>
</node>
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1686089236690" ID="ID_1356337031" MODIFIED="1686089259589" TEXT="und Iteration &#xfc;ber prerequisite - ExitNodes">
<icon BUILTIN="flag-yellow"/>
<node COLOR="#338800" CREATED="1686089236690" ID="ID_1356337031" MODIFIED="1686263707397" TEXT="und Iteration &#xfc;ber prerequisite - ExitNodes">
<icon BUILTIN="button_ok"/>
</node>
<node COLOR="#338800" CREATED="1686263894892" ID="ID_116606381" MODIFIED="1686270564820" TEXT="mu&#xdf; nun JobFunctor festlegen">
<arrowlink COLOR="#535ca3" DESTINATION="ID_1524676047" ENDARROW="Default" ENDINCLINATION="321;15;" ID="Arrow_ID_176648571" STARTARROW="None" STARTINCLINATION="-298;0;"/>
<icon BUILTIN="button_ok"/>
</node>
</node>
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1686089280610" ID="ID_331300527" MODIFIED="1686089333490" TEXT="Segment alloziert on-demand neues JobTicket">
<icon BUILTIN="flag-yellow"/>
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1686089580864" ID="ID_1949359516" MODIFIED="1686089591287" TEXT="Zugriff indiziert nach NodePort-Nr">
<icon BUILTIN="flag-yellow"/>
<node BACKGROUND_COLOR="#eef0c5" COLOR="#990000" CREATED="1686089280610" ID="ID_331300527" MODIFIED="1686263718501" TEXT="Segment alloziert on-demand neues JobTicket">
<icon BUILTIN="pencil"/>
<node COLOR="#338800" CREATED="1686089580864" ID="ID_1949359516" MODIFIED="1686270557984" TEXT="Zugriff indiziert nach NodePort-Nr">
<icon BUILTIN="button_ok"/>
</node>
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1686089592469" ID="ID_1688607797" MODIFIED="1686089703788" TEXT="Storage mu&#xdf; stabil + erweiterungsf&#xe4;hig sein">
<node COLOR="#435e98" CREATED="1686089592469" ID="ID_1688607797" MODIFIED="1686270559655" TEXT="Storage mu&#xdf; stabil + erweiterungsf&#xe4;hig sein">
<richcontent TYPE="NOTE"><html>
<head>
@ -74227,9 +74299,50 @@ Date:&#160;&#160;&#160;Thu Apr 20 18:53:17 2023 +0200<br/>
</node>
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1686089743535" ID="ID_1592596965" MODIFIED="1686089766715" TEXT="JobTicket-Erzeugung (vorl&#xe4;ufig) endg&#xfc;litig implementieren">
<icon BUILTIN="flag-yellow"/>
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1686089827509" ID="ID_213320277" MODIFIED="1686089890626" TEXT="Spec-Erzeugung in das Segment verlagern">
<node COLOR="#5b280f" CREATED="1686089827509" ID="ID_213320277" MODIFIED="1686270676731" TEXT="Spec-Erzeugung in das Segment verlagern">
<icon BUILTIN="button_cancel"/>
<node COLOR="#5b280f" CREATED="1686270962172" ID="ID_883202873" MODIFIED="1686270983572" TEXT="hier nun das Spec-Tupel rekursiv aufbauen">
<icon BUILTIN="button_cancel"/>
</node>
<node BACKGROUND_COLOR="#e0b7aa" COLOR="#690f14" CREATED="1686270985068" ID="ID_116441332" MODIFIED="1686271310159" STYLE="fork" TEXT="unm&#xf6;glich: rekursive Typ-Inferenz">
<richcontent TYPE="NOTE"><html>
<head>
</head>
<body>
<p>
damit sitz ich in der Falle...
</p>
<ul>
<li>
da ich rekursiv die Vorl&#228;ufer-Tickets allozieren mu&#223;, ist ein &#955; unabdingbar
</li>
<li>
aber damit kann ich den Typ des Transform-Iterators nicht mehr explizit anschreiben
</li>
<li>
anderseits kann ich aus dem gleichen Grund den Typ des Spec-Tuples nicht explizit anschreiben
</li>
</ul>
</body>
</html></richcontent>
<arrowlink COLOR="#bf3856" DESTINATION="ID_1696777369" ENDARROW="Default" ENDINCLINATION="47;-15;" ID="Arrow_ID_1288742892" STARTARROW="None" STARTINCLINATION="-91;7;"/>
<icon BUILTIN="broken-line"/>
</node>
</node>
<node BACKGROUND_COLOR="#fdfdcf" COLOR="#ff0000" CREATED="1686270678269" ID="ID_1696777369" MODIFIED="1686271185355" TEXT="Spec-Erzeugung durch ExitNode ersetzen">
<linktarget COLOR="#bf3856" DESTINATION="ID_1696777369" ENDARROW="Default" ENDINCLINATION="47;-15;" ID="Arrow_ID_1288742892" SOURCE="ID_116441332" STARTARROW="None" STARTINCLINATION="-91;7;"/>
<icon BUILTIN="flag-pink"/>
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1686270700679" ID="ID_1172741628" MODIFIED="1686270720719" TEXT="JobTIcket-ctor akzeptiert ExitNode const&amp;">
<icon BUILTIN="flag-yellow"/>
</node>
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1686270722814" ID="ID_1222081090" MODIFIED="1686270750251" TEXT="bisherige Traversierungs-Logik sinngem&#xe4;&#xdf; hier &#xfc;bersetzen">
<icon BUILTIN="flag-yellow"/>
</node>
<node COLOR="#435e98" CREATED="1686271328534" ID="ID_601604800" MODIFIED="1686271349144" TEXT="MockSegmentation baut jetzt ohnehin bereits eine ExitNode-Struktur">
<icon BUILTIN="idea"/>
</node>
</node>
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1686089789689" ID="ID_1968297332" MODIFIED="1686090078439" STYLE="bubble" TEXT="Aufruf: bekommt ExitNode">
<edge COLOR="#4b6f99"/>
<linktarget COLOR="#334242" DESTINATION="ID_1968297332" ENDARROW="Default" ENDINCLINATION="-57;70;" ID="Arrow_ID_1911874934" SOURCE="ID_634741286" STARTARROW="None" STARTINCLINATION="14;65;"/>
@ -75182,6 +75295,22 @@ Date:&#160;&#160;&#160;Thu Apr 20 18:53:17 2023 +0200<br/>
</body>
</html></richcontent>
</node>
<node BACKGROUND_COLOR="#e0ceaa" COLOR="#690f14" CREATED="1686266765287" ID="ID_1482721725" MODIFIED="1686266805196">
<richcontent TYPE="NODE"><html>
<head>
</head>
<body>
<p>
&#8623; ABER dann brauchen wir einen <i>Ref-count...</i>
</p>
</body>
</html></richcontent>
<icon BUILTIN="messagebox_warning"/>
</node>
</node>
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1686263854024" ID="ID_1705328706" MODIFIED="1686263879705" TEXT="mu&#xdf; f&#xfc;r ExitNode passenden JobFunctor bereitstellen">
<icon BUILTIN="flag-yellow"/>
</node>
</node>
<node CREATED="1685999923288" ID="ID_43857242" MODIFIED="1685999987298" TEXT="grunds&#xe4;tzlich">