Job-Planning: first testcase - empty JobTicket

...requires a first attempt towards defining a `JobTiket`.
This turns out quite tricky, due to using those `LinkedElements`
(intrusive single linked list), which requires all added records
actually to live elsewhere. Since we want to use a custom allocator
later (the `AllocationCluster`), this boils down to allocating those
records only when about to construct the `JobTicket` itself.

What makes matters even worse: at the moment we use a separate spec
per Media channel (maybe these specs can be collapsed later non).
And thus we need to pass a collection -- or better an iterator
with raw specs, which in turn must reveal yet another nested
sequence for the prerequisite `JobTickets`.

Anyhow, now we're able at least to create an empty `JobTicket`,
backed by a dummy `JobFunctor`....
This commit is contained in:
Fischlurch 2023-04-20 23:55:02 +02:00
parent 856d8a3b51
commit 305eb825af
9 changed files with 432 additions and 65 deletions

View file

@ -672,6 +672,14 @@ namespace lib {
return SingleValIter<VAL>{ref};
}
/** not-anything-at-all iterator */
template<class VAL>
inline auto
nilIterator()
{
return SingleValIter<VAL>();
}

View file

@ -474,9 +474,9 @@ namespace meta {
public:
enum{ value = std::is_constructible<bool, Type>::value
&& HasNested_value_type<Type>::value
&& HasOperator_deref<Type>::value
&& HasOperator_inc<Type>::value
and HasNested_value_type<Type>::value
and HasOperator_deref<Type>::value
and HasOperator_inc<Type>::value
};
};
@ -497,8 +497,8 @@ namespace meta {
META_DETECT_FUNCTION(typename X::iterator, end ,(void));
enum { value = HasNested_iterator<Type>::value
&& HasFunSig_begin<Type>::value
&& HasFunSig_end<Type>::value
and HasFunSig_begin<Type>::value
and HasFunSig_end<Type>::value
};
};
@ -509,8 +509,8 @@ namespace meta {
META_DETECT_FUNCTION(typename X::iterator, end ,(void) noexcept);
enum { value = HasNested_iterator<Type>::value
&& HasFunSig_begin<Type>::value
&& HasFunSig_end<Type>::value
and HasFunSig_begin<Type>::value
and HasFunSig_end<Type>::value
};
};
@ -521,8 +521,8 @@ namespace meta {
META_DETECT_FUNCTION(typename X::const_iterator, end ,(void) const);
enum { value = HasNested_const_iterator<Type>::value
&& HasFunSig_begin<Type>::value
&& HasFunSig_end<Type>::value
and HasFunSig_begin<Type>::value
and HasFunSig_end<Type>::value
};
};
@ -533,8 +533,8 @@ namespace meta {
META_DETECT_FUNCTION(typename X::const_iterator, end ,(void) const noexcept);
enum { value = HasNested_const_iterator<Type>::value
&& HasFunSig_begin<Type>::value
&& HasFunSig_end<Type>::value
and HasFunSig_begin<Type>::value
and HasFunSig_end<Type>::value
};
};
@ -561,8 +561,8 @@ namespace meta {
META_DETECT_FUNCTION(typename X::reverse_iterator, rend ,(void));
enum { value = HasNested_reverse_iterator<Type>::value
&& HasFunSig_rbegin<Type>::value
&& HasFunSig_rend<Type>::value
and HasFunSig_rbegin<Type>::value
and HasFunSig_rend<Type>::value
};
};
@ -573,8 +573,8 @@ namespace meta {
META_DETECT_FUNCTION(typename X::reverse_iterator, rend ,(void) noexcept);
enum { value = HasNested_reverse_iterator<Type>::value
&& HasFunSig_rbegin<Type>::value
&& HasFunSig_rend<Type>::value
and HasFunSig_rbegin<Type>::value
and HasFunSig_rend<Type>::value
};
};
@ -585,8 +585,8 @@ namespace meta {
META_DETECT_FUNCTION(typename X::const_reverse_iterator, rend ,(void) const);
enum { value = HasNested_const_reverse_iterator<Type>::value
&& HasFunSig_rbegin<Type>::value
&& HasFunSig_rend<Type>::value
and HasFunSig_rbegin<Type>::value
and HasFunSig_rend<Type>::value
};
};
@ -597,8 +597,8 @@ namespace meta {
META_DETECT_FUNCTION(typename X::const_reverse_iterator, rend ,(void) const noexcept);
enum { value = HasNested_const_reverse_iterator<Type>::value
&& HasFunSig_rbegin<Type>::value
&& HasFunSig_rend<Type>::value
and HasFunSig_rbegin<Type>::value
and HasFunSig_rend<Type>::value
};
};

View file

@ -44,8 +44,11 @@
#include "lib/hierarchy-orientation-indicator.hpp"
#include "lib/linked-elements.hpp"
#include "lib/iter-adapter.hpp"
#include "lib/meta/tuple-helper.hpp"
#include "lib/meta/trait.hpp"
#include "lib/util.hpp"
#include <utility>
#include <stack>
@ -57,6 +60,7 @@ namespace engine {
//using lib::time::FSecs;
//using lib::time::Time;
using vault::engine::Job;
using vault::engine::JobFunctor;
using lib::LinkedElements;
using lib::OrientationIndicator;
using util::isnil;
@ -88,40 +92,47 @@ using util::isnil;
class JobTicket
: util::NonCopyable
{
struct Prerequisite
{
Prerequisite* next{nullptr};
JobTicket& descriptor;
Prerequisite (JobTicket& ticket)
: descriptor{ticket}
{ }
};
using Prerequisites = LinkedElements<Prerequisite>;
/** what handling this task entails */
struct Provision
{
Provision* next;
Provision* next{nullptr};
JobFunctor& jobFunctor;
Prerequisites requirements{};
////////////////////TODO some channel or format descriptor here
};
struct Prerequisite
{
Prerequisite* next;
JobTicket* descriptor;
};
struct Prerequisites ///< per channel
{
Prerequisites* next;
LinkedElements<Prerequisite> requiredJobs_;
Provision (JobFunctor& func)
: jobFunctor{func}
{ }
};
LinkedElements<Provision> channelConfig_;
LinkedElements<Prerequisites> requirement_;
LinkedElements<Provision> provision_;
template<class IT>
static LinkedElements<Provision> buildProvisionSpec (IT);
protected:
template<class IT>
JobTicket(IT featureSpec_perChannel)
: provision_{buildProvisionSpec (featureSpec_perChannel)}
{ }
public:
class ExplorationState;
friend class ExplorationState;
JobTicket()
{
TODO ("job representation, planning and scheduling");
}
ExplorationState startExploration() const;
@ -133,17 +144,18 @@ using util::isnil;
bool
isValid() const
{
if (channelConfig_.size() != requirement_.size())
if (isnil (provision_))
return false;
TODO ("validity self check");
return true;
}
};
class JobTicket::ExplorationState
{
typedef LinkedElements<Prerequisite>::iterator SubTicketSeq;
typedef Prerequisites::iterator SubTicketSeq;
typedef std::stack<SubTicketSeq> SubTicketStack; //////////////////////////TODO use a custom container to avoid heap allocations
SubTicketStack toExplore_;
@ -154,8 +166,8 @@ using util::isnil;
ExplorationState (Prerequisites& prerequisites)
{
if (not isnil (prerequisites.requiredJobs_))
toExplore_.push (prerequisites.requiredJobs_.begin());
if (not isnil (prerequisites))
toExplore_.push (prerequisites.begin());
}
// using default copy operations
@ -208,10 +220,9 @@ using util::isnil;
operator->() const
{
REQUIRE (!empty() && toExplore_.top().isValid());
REQUIRE (toExplore_.top()->descriptor);
REQUIRE (toExplore_.top()->descriptor->isValid());
REQUIRE (toExplore_.top()->descriptor.isValid());
return toExplore_.top()->descriptor;
return & toExplore_.top()->descriptor;
}
@ -238,6 +249,50 @@ using util::isnil;
/** @internal prepare and assemble the working data structure to build a JobTicket.
* @tparam IT iterator to yield a sequence of specifications for each channel,
* given as `std::pair` of a JobFunctor and a further Sequence of
* JobTicket prerequisites.
* @return the final wired instance of the data structure to back the new JobTicket
* @remark Note especially that those data structures linked together for use by the
* JobTicket are themselves allocated "elsewhere", and need to be attached
* to a memory management scheme (typically an AllocationCluster for some
* Segment of the Fixture datastructure). This data layout can be tricky
* to get right, and is chosen here for performance reasons, assuming
* that there is a huge number of segments, and these are updated
* frequently after each strike of edit operations, yet traversed
* and evaluated on a sub-second scale for ongoing playback.
*/
template<class IT>
inline LinkedElements<JobTicket::Provision>
JobTicket::buildProvisionSpec (IT featureSpec)
{ /* ---- validate parameter type ---- */
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 Preq = typename std::tuple_element<1, Spec>::type;
static_assert (lib::meta::is_basically<Func, JobFunctor>()); // -- first component specifies the JobFunctor to use
static_assert (lib::meta::can_IterForEach<Preq>::value); // -- second 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");
LinkedElements<Provision> provisionSpec; //////////////////////////////////////////////////TICKET #1292 : need to pass in Allocator as argument
for ( ; featureSpec; ++featureSpec)
{
JobFunctor& func = std::get<0> (*featureSpec);
auto& provision = provisionSpec.emplace<Provision> (func);
for (Preq pre = std::get<1> (*featureSpec); pre; ++pre)
provision.requirements.emplace<Prerequisite> (*pre);
}
provisionSpec.reverse(); // retain order of given definitions per channel
ENSURE (not isnil (provisionSpec));
return provisionSpec;
}
/// @deprecated : could be expendable ... likely incurred solely by the use of Monads as design pattern
inline JobTicket::ExplorationState
@ -257,9 +312,9 @@ using util::isnil;
inline JobTicket::ExplorationState
JobTicket::discoverPrerequisites (uint channelNr) const
{
REQUIRE (channelNr < requirement_.size());
REQUIRE (channelNr < provision_.size());
return ExplorationState (requirement_[channelNr]);
return ExplorationState (provision_[channelNr].requirements);
}

View file

@ -45,7 +45,7 @@
#include "steam/engine/dispatcher.hpp"
#include "steam/play/timings.hpp"
#include "vault/engine/job.h"
#include "lib/nocopy.hpp"
//#include "lib/nocopy.hpp"
namespace steam {
@ -90,7 +90,6 @@ namespace engine {
*/
class RenderDrive
: public JobClosure
, util::NonCopyable
{
RenderEnvironment& engine_;

View file

@ -62,11 +62,12 @@ namespace engine {
/**
* emit the VTable for JobClosure within this compilation unit,
* emit the VTable for JobFunctor within this compilation unit,
* which is still part of the Vault. The actual job implementation
* classes are defined in the Steam-Layer
*/
JobClosure::~JobClosure() { }
JobFunctor::~JobFunctor() { }
JobClosure::~JobClosure() { } ///< @deprecated 4/23 refactoring to retract C-structs from the Scheduler interface

View file

@ -199,6 +199,14 @@ namespace engine {
typedef lumiera_jobParameter const& JobParameter;
/** @todo refactoring 4/23 -- will replace JobClosure */
class JobFunctor /////////////////////////////////////////////////////TICKET #1287 : rework Job representation
: util::NonCopyable // ....has distinct identity and stable address
{
public:
virtual ~JobFunctor(); ///< this is an interface
};
/**
* Interface of the closure for frame rendering jobs.
* Hidden behind this interface resides all of the context re-building
@ -212,10 +220,11 @@ namespace engine {
* By virtue of the JobClosure-pointer, embedded into #lumiera_jobDefinition,
* the invocation of such a job may re-gain the full context, including the
* actual ProcNode to pull and further specifics, like the media channel.
*/
* @deprecated 4/23 plain-C data structures are removed from the Scheduler interface; transition to JobFunctor
*/ /////////////////////////////////////////////////////TICKET #1287 : rework Job representation
class JobClosure
: public lumiera_jobClosure
, util::NonCopyable // ....has distinct identity and stable address
, public JobFunctor /////////////////////////////////////////////////////TICKET #1287 : rework Job representation
{
public:
virtual ~JobClosure(); ///< this is an interface

View file

@ -27,7 +27,7 @@
#include "lib/test/run.hpp"
#include "lib/error.hpp"
#include "steam/engine/dispatcher-mock.hpp"
#include "steam/engine/mock-dispatcher.hpp"
//#include "steam/engine/job-planning.hpp"

View file

@ -35,17 +35,21 @@
#include "steam/engine/dispatcher.hpp"
#include "steam/engine/job-ticket.hpp"
//#include "steam/play/timings.hpp"
//#include "lib/time/timevalue.hpp"
#include "lib/time/timevalue.hpp"
////#include "lib/time/timequant.hpp"
////#include "lib/format-cout.hpp"
#include "lib/depend.hpp"
#include "lib/itertools.hpp"
//#include "lib/util-coll.hpp"
#include "vault/real-clock.hpp"
#include "lib/test/test-helper.hpp"
#include "lib/test/event-log.hpp"
#include "vault/engine/job.h"
//#include "lib/util.hpp"
//#include <functional>
//#include <vector>
#include <tuple>
//using test::Test;
//using util::isnil;
@ -66,14 +70,18 @@ namespace test {
// using lib::time::Duration;
// using lib::time::Offset;
// using lib::time::TimeVar;
using lib::time::TimeValue;
// using lib::time::Time;
// using mobject::ModelPort;
// using play::Timings;
using std::make_tuple;
namespace { // used internally
// using play::PlayTestFrames_Strategy;
// using play::ModelPorts;
using vault::engine::JobClosure;
using vault::engine::JobParameter;
// typedef play::DummyPlayConnection<play::PlayTestFrames_Strategy> DummyPlaybackSetup;
@ -118,14 +126,74 @@ namespace test {
/// @deprecated this setup is confusing and dangerous (instance identity is ambiguous)
lib::Depend<MockDispatcherTable> mockDispatcher;
class MockInvocationLog
: public lib::test::EventLog
{
public:
MockInvocationLog()
: EventLog{"MockInvocation"}
{ }
};
lib::Depend<MockInvocationLog> mockInvocation;
class DummyJobFunctor
: public vault::engine::JobClosure
{
void
invokeJobOperation (JobParameter param)
{
mockInvocation().call(this, "DummyJob", TimeValue(param.nominalTime)
, RealClock::now()
, param.invoKey.metaInfo.a
, param.invoKey.metaInfo.b
);
}
void
signalFailure (JobParameter,JobFailureReason)
{
NOTREACHED ("Job failure is not subject of this test");
}
JobKind
getJobKind() const
{
return META_JOB;
}
bool
verify (Time nominalJobTime, InvocationInstanceID invoKey) const
{
return Time::ANYTIME < nominalJobTime
and 0 <= invoKey.metaInfo.a
;
}
size_t
hashOfInstance(InvocationInstanceID invoKey) const
{
return boost::hash_value (invoKey.metaInfo.a);
}
public:
};
lib::Depend<DummyJobFunctor> dummyJobFunctor;
inline auto
defineBottomProvision()
defineBottomSpec()
{
// return lib::singleValIterator(
// JobTicket::buildProvision (
// ));
auto emptyPrereq = lib::nilIterator<JobTicket&>();
using Iter = decltype(emptyPrereq);
return lib::singleValIterator(
std::tuple<JobFunctor&, Iter>(dummyJobFunctor()
,emptyPrereq
));
}
}//(End)internal test helpers....
@ -145,9 +213,9 @@ namespace test {
{
public:
// MockJobTicket()
// : JobTicket{JobTicket::Provisions{defineBottomProvision()}}
// { };
MockJobTicket()
: JobTicket{defineBottomSpec()}
{ };
private:
};

View file

@ -69129,7 +69129,7 @@
</node>
<node BACKGROUND_COLOR="#fdfdcf" COLOR="#ff0000" CREATED="1681083619609" ID="ID_1647785356" MODIFIED="1681083636070" TEXT="Bessere L&#xf6;sung">
<icon BUILTIN="forward"/>
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1681083639877" ID="ID_358030802" MODIFIED="1681084305066" TEXT="klare performance-orientierte Datenstrukturen schaffen">
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1681083639877" ID="ID_358030802" LINK="#ID_1372752844" MODIFIED="1681951396709" TEXT="klare performance-orientierte Datenstrukturen schaffen">
<icon BUILTIN="flag-yellow"/>
<node CREATED="1681083683663" ID="ID_135955742" MODIFIED="1681084106386" TEXT="Job &#x27fc; Deskriptor(value, stateful)"/>
<node CREATED="1681083725400" ID="ID_201198910" MODIFIED="1681084115121" TEXT="JobFunktor &#x27fc; Strategy(reference, shared)"/>
@ -69696,6 +69696,214 @@
<icon BUILTIN="smiley-oh"/>
</node>
</node>
<node BACKGROUND_COLOR="#eef0c5" COLOR="#990000" CREATED="1681860325369" ID="ID_328096563" MODIFIED="1681860348325" TEXT="mu&#xdf; nun aber JobTicket-Ctor bereitstellen">
<icon BUILTIN="pencil"/>
<node BACKGROUND_COLOR="#f0d5c5" COLOR="#990033" CREATED="1681860349394" ID="ID_1525241951" MODIFIED="1681860363389" TEXT="wie definiert man ein JobTicket?">
<icon BUILTIN="help"/>
<node CREATED="1681860366713" ID="ID_161470410" MODIFIED="1681860416753" TEXT="erste N&#xe4;herung: eine Spec abliefern">
<icon BUILTIN="yes"/>
</node>
<node COLOR="#338800" CREATED="1681860397581" ID="ID_676680756" MODIFIED="1681860411652" TEXT="man kann Provision und Requirements zusammenlegen">
<icon BUILTIN="button_ok"/>
</node>
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1681860421530" ID="ID_1550922413" MODIFIED="1681860445550" TEXT="JobTicket braucht aber LinkedElements&lt;Provision&gt;">
<icon BUILTIN="flag-yellow"/>
<node CREATED="1681860473137" ID="ID_1498832886" MODIFIED="1681860486556" TEXT="den RAII-Populations-ctor nutzen">
<icon BUILTIN="idea"/>
</node>
<node CREATED="1681860490289" ID="ID_118026994" MODIFIED="1681860510052" TEXT="erst mal f&#xfc;r den Test definieren">
<icon BUILTIN="yes"/>
<node CREATED="1681860520930" ID="ID_770893349" MODIFIED="1681860570905" TEXT="Provision-Record anlegen">
<richcontent TYPE="NOTE"><html>
<head>
</head>
<body>
<p>
geht nicht: ist privat (und das ist sinnvoll so!)
</p>
</body>
</html></richcontent>
<icon BUILTIN="closed"/>
</node>
<node CREATED="1681860530027" ID="ID_1039467630" MODIFIED="1681860537190" TEXT="Provision-Record irgendwie bauen"/>
</node>
<node BACKGROUND_COLOR="#e0ceaa" COLOR="#690f14" CREATED="1681860641938" ID="ID_1900625689" MODIFIED="1681860659290" TEXT="AUA! JobTicket &#xfc;bernimmt Ownership">
<icon BUILTIN="clanbomber"/>
<node CREATED="1681860661257" ID="ID_1274485445" MODIFIED="1681860705389" TEXT="zwar nur ein vorl&#xe4;ufiges Problem (OwningHeapAllocated)">
<icon BUILTIN="idea"/>
</node>
<node CREATED="1681860689006" ID="ID_160492283" MODIFIED="1681861171511" TEXT="aber dahinter steckt ein konzeptionelles Problem">
<richcontent TYPE="NOTE"><html>
<head>
</head>
<body>
<p>
und zwar ist die JobTicket-Struktur explizit darauf angelegt, anderweitig erstellte Deskriptoren zu verlinken; das soll so sein aus Performance-Gr&#252;nden (Cache Locality &#10233; AllocationCluster)
</p>
</body>
</html></richcontent>
<arrowlink COLOR="#df2b36" DESTINATION="ID_1071396002" ENDARROW="Default" ENDINCLINATION="317;-20;" ID="Arrow_ID_375386930" STARTARROW="None" STARTINCLINATION="-437;23;"/>
<icon BUILTIN="messagebox_warning"/>
</node>
</node>
</node>
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1681864684118" ID="ID_1606009220" MODIFIED="1681864991481" TEXT="Spezifikation">
<icon BUILTIN="flag-yellow"/>
<node CREATED="1681864799687" ID="ID_1244549458" MODIFIED="1681864834215" TEXT="Aufz&#xe4;hlung Prerequisites"/>
<node CREATED="1681864758749" ID="ID_941507735" MODIFIED="1681864762804" TEXT="JobFunktor"/>
</node>
</node>
<node BACKGROUND_COLOR="#fdfdcf" COLOR="#ff0000" CREATED="1681860589211" ID="ID_1071396002" MODIFIED="1681861171511" TEXT="Problem: Allokation f&#xfc;r die Provision-Records">
<linktarget COLOR="#df2b36" DESTINATION="ID_1071396002" ENDARROW="Default" ENDINCLINATION="317;-20;" ID="Arrow_ID_375386930" SOURCE="ID_160492283" STARTARROW="None" STARTINCLINATION="-437;23;"/>
<icon BUILTIN="messagebox_warning"/>
<node CREATED="1681860891883" HGAP="24" ID="ID_1751384108" MODIFIED="1681861186918" VSHIFT="7">
<richcontent TYPE="NODE"><html>
<head>
</head>
<body>
<p>
die mu&#223; definitiv <i>von &#8222;wo anders&#8220;</i>&#160;kommen
</p>
</body>
</html></richcontent>
<icon BUILTIN="messagebox_warning"/>
</node>
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1681861077210" ID="ID_506364370" MODIFIED="1682027051753" TEXT="sollte die Deskriptoren per pushNew() erzeugen (also emplace...)">
<icon BUILTIN="yes"/>
</node>
</node>
<node BACKGROUND_COLOR="#eef0c5" COLOR="#990000" CREATED="1681861418620" ID="ID_1440642182" MODIFIED="1682027038910" TEXT="Spezifikations-Schnittstelle schaffen">
<icon BUILTIN="pencil"/>
<node CREATED="1681861430131" ID="ID_38853136" MODIFIED="1681861501198" TEXT="dort k&#xf6;nnte auch das ganze Problem Allokation mit verborgen werden">
<richcontent TYPE="NOTE"><html>
<head>
</head>
<body>
<p>
Ziel sollte tats&#228;chlich sein, die Komplexit&#228;ten mit der Allokation aus dem funktionalen Code heraus zu verbergen; denn dies dient nur dem separaten Belang der Performance
</p>
</body>
</html></richcontent>
</node>
<node CREATED="1681946822662" ID="ID_527151044" MODIFIED="1681946836012" TEXT="Form der Schnittstelle noch unklar">
<icon BUILTIN="messagebox_warning"/>
<node CREATED="1681946837591" ID="ID_1753359630" MODIFIED="1681947351700" TEXT="zun&#xe4;chst einmal nur getrieben vom Test">
<icon BUILTIN="messagebox_warning"/>
</node>
<node CREATED="1681946849061" ID="ID_1328735668" LINK="#ID_122410804" MODIFIED="1681947238611" TEXT="die ungekl&#xe4;rte Frage bez&#xfc;glich Aufteilung pro Medien-Channel">
<richcontent TYPE="NOTE"><html>
<head>
</head>
<body>
<p>
...ist hier relevant, denn dies scheidet eine einfache Funktions/Konstruktor-Schnittstelle aus; wir m&#252;ssen einen strukturierten Datensatz bereitstellen
</p>
</body>
</html></richcontent>
</node>
<node CREATED="1681946946288" ID="ID_735321008" LINK="#ID_514995150" MODIFIED="1681947691935" TEXT="&#xfc;berdies ist die interne Repr&#xe4;sentation des top-level fragw&#xfc;rdig">
<richcontent TYPE="NOTE"><html>
<head>
</head>
<body>
<p>
Zun&#228;chst wurden LinkedElements lediglich aus Gr&#252;nden der Konsistenz auch hierf&#252;r verwendet. Eine intrusive-single-linked-List mag f&#252;r die Vernetzung der Prerequisites sinnvoll sein, aber f&#252;r eine Sprungtafel nach Channel-Nr lie&#223;e sich genauso gut eine Array-backed-Implementation konstruieren (vielleicht dann ein neuer Anlauf anstelle der alten Idee des &#187;RefArray&#171; ?)
</p>
</body>
</html></richcontent>
</node>
<node CREATED="1681947254466" ID="ID_114148381" MODIFIED="1681947340793" TEXT="noch l&#xe4;ngerfristig unklar wie die Schnittstelle tats&#xe4;chlich produkiv genutzt werden wird">
<richcontent TYPE="NOTE"><html>
<head>
</head>
<body>
<p>
...denn es wird noch deutlich &#252;ber dieses PlaybackVerticalSlice hinaus dauern, bis die erste rudiment&#228;re Implementierung des Builders am Start ist &#8212; und <i>erst dann gibt es eine praktischen Bezugspunkt f&#252;r das Design</i>
</p>
</body>
</html></richcontent>
<icon BUILTIN="messagebox_warning"/>
</node>
<node CREATED="1681948120763" ID="ID_750154353" MODIFIED="1681948327526" TEXT="denkbar da&#xdf; sich das sp&#xe4;ter stets auf eine ProcNode-Referenz reduzieren l&#xe4;&#xdf;t">
<richcontent TYPE="NOTE"><html>
<head>
</head>
<body>
<p>
...m&#246;glicherweise k&#246;nnte zumindest so der wichtigste Standardfall komplett ohne einen eigens allozierten JobFunktor dargestellt werden &#8212; einfach indem alle notwendigen Parameter direkt aus der referenzierten ProcNode gezogen werden. Um diese M&#246;glichkeit abzusch&#228;tzen, m&#252;&#223;te aber zuerst definiert werden, wie der &#220;bergang zu den Prerequisites konkret im Proc-Node-Graph dargestellt werden: durch spezielle Metadaten? oder durch eine besondere Marker-Node, die wie eine Quelle fungiert?
</p>
</body>
</html></richcontent>
<icon BUILTIN="idea"/>
</node>
</node>
<node BACKGROUND_COLOR="#eef0c5" COLOR="#990000" CREATED="1681947704128" ID="ID_1307528426" MODIFIED="1682027027824" TEXT="vorl&#xe4;ufige L&#xf6;sung: Iterator &#xfc;ber std::tuple">
<icon BUILTIN="pencil"/>
<node CREATED="1681947910447" ID="ID_1183443190" MODIFIED="1681947934893" TEXT="Begr&#xfc;ndung">
<node CREATED="1681947935610" ID="ID_218509707" MODIFIED="1681947935610" TEXT="sonst m&#xfc;&#xdf;ten wir hier doch einen Deskriptor-Record-Typ einf&#xfc;hren"/>
<node CREATED="1681947938444" ID="ID_1201610351" MODIFIED="1681947959060" TEXT="und damit einer sp&#xe4;teren ausgebauten Builder-Syntax vorgreifen"/>
<node CREATED="1681947964857" ID="ID_733464382" MODIFIED="1681947997559" TEXT="besser w&#xe4;re es, das in eine Subklasse zu verschieben"/>
</node>
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1681948003825" ID="ID_1586450204" MODIFIED="1681948029740" TEXT="Hilfsfunktion: Transformator mit Allokation">
<icon BUILTIN="flag-yellow"/>
<node COLOR="#338800" CREATED="1681961414575" ID="ID_648708446" MODIFIED="1681961436412" TEXT="Argument-Typ validieren">
<icon BUILTIN="button_ok"/>
</node>
<node COLOR="#338800" CREATED="1681961449442" ID="ID_1664168385" MODIFIED="1681961462617" TEXT="Provision und Prerequisite per Allokator erzeugen">
<icon BUILTIN="button_ok"/>
</node>
<node COLOR="#338800" CREATED="1681961464064" ID="ID_647784147" MODIFIED="1682026936579" TEXT="mu&#xdf; Reihenfolge der Linked-List umkehren">
<icon BUILTIN="button_ok"/>
<node COLOR="#338800" CREATED="1681961488869" ID="ID_1984454996" MODIFIED="1682026941393" TEXT="Hilfsfunktion in LinkedElements implementieren">
<icon BUILTIN="button_ok"/>
</node>
<node COLOR="#338800" CREATED="1681961499158" ID="ID_1061765881" MODIFIED="1682026940080" TEXT="Unit-Test hierf&#xfc;r">
<icon BUILTIN="button_ok"/>
</node>
</node>
</node>
<node COLOR="#338800" CREATED="1681948057567" ID="ID_923881429" MODIFIED="1682027001897" TEXT="mu&#xdf; zun&#xe4;chst den empty()-Testcase erf&#xfc;llen">
<icon BUILTIN="button_ok"/>
<node COLOR="#338800" CREATED="1681948087120" ID="ID_555715675" MODIFIED="1682026994517" TEXT="brauche dazu einen NOP-JobFunktor">
<icon BUILTIN="button_ok"/>
<node COLOR="#338800" CREATED="1682026957482" ID="ID_637833464" MODIFIED="1682026990813" TEXT="schreibe den bestehenden dummy-job.cpp um">
<icon BUILTIN="button_ok"/>
</node>
<node COLOR="#338800" CREATED="1682026969063" ID="ID_32615180" MODIFIED="1682026989799" TEXT="verwende eine TestLog-Instanz">
<icon BUILTIN="button_ok"/>
</node>
<node CREATED="1682026978301" ID="ID_347272426" MODIFIED="1682027065816" TEXT="als Singleton per lib::Depend">
<icon BUILTIN="idea"/>
</node>
</node>
<node COLOR="#df2bbd" CREATED="1682027074106" ID="ID_1659411020" MODIFIED="1682027096603" TEXT="tut">
<richcontent TYPE="NOTE"><html>
<head>
</head>
<body>
<p>
...nach zwei Tagen Gew&#252;rge....
</p>
</body>
</html></richcontent>
<icon BUILTIN="ksmiletris"/>
</node>
</node>
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1681948045301" ID="ID_1777275098" MODIFIED="1681948056012" TEXT="dann Beispiel-Impl f&#xfc;r Mock">
<icon BUILTIN="flag-yellow"/>
</node>
</node>
</node>
</node>
</node>
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1681839812280" ID="ID_525360569" MODIFIED="1681839820465" TEXT="Iteration">
<icon BUILTIN="flag-yellow"/>
@ -69751,6 +69959,9 @@
<node CREATED="1681239735718" ID="ID_464013545" MODIFIED="1681239741761" TEXT="rekursive Tiefensuche"/>
</node>
<node CREATED="1681167579899" ID="ID_428564529" MODIFIED="1681167585941" TEXT="createJobFor(FrameCoord)"/>
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1681861351924" ID="ID_446140172" MODIFIED="1681861366116" TEXT="Builder-Mechanismus bereitstellen">
<icon BUILTIN="flag-yellow"/>
</node>
<node CREATED="1681167633659" ID="ID_374689298" MODIFIED="1681167759825" TEXT="abstrakt-referentiell">
<richcontent TYPE="NOTE"><html>
<head>
@ -69873,6 +70084,22 @@
<icon BUILTIN="flag-yellow"/>
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1681086220019" ID="ID_1372752844" MODIFIED="1681086232986" TEXT="Umbau: C-Struct - Layer zur&#xfc;ckbauen">
<icon BUILTIN="flag-yellow"/>
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1681951421768" ID="ID_283868393" MODIFIED="1681951528212" TEXT="Schrittweiser Umbau: alte C-Struct vorw&#xe4;rts-kompatibel machen">
<richcontent TYPE="NOTE"><html>
<head>
</head>
<body>
<p>
das bedeutet: die alten Interfaces m&#252;ssen von den neuen Interfaces erben, dann kann schon st&#252;ckweise Code geschrieben werden, der die neuen Interfaces vorraussetzt...
</p>
</body>
</html></richcontent>
<icon BUILTIN="flag-yellow"/>
<node COLOR="#338800" CREATED="1681951529483" ID="ID_737477406" MODIFIED="1681951551777" TEXT="JobFunctor &#x2023; JobClosure">
<icon BUILTIN="button_ok"/>
</node>
</node>
</node>
<node CREATED="1681086385917" ID="ID_1193213661" MODIFIED="1681086416077" TEXT="leichtgewichtig, kopierbar, stateful, Scheduler-impl-owned"/>
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1681425144493" ID="ID_1404753000" MODIFIED="1681425214239" TEXT="Support f&#xfc;r engine::Activity">