Dispatcher-Pipeline: arrangement of builder types

...it turns out that we actually do not need to wrap TreeExplorer
on the builder types, because basically there is only a single active
builder type, and the complete processing pipeline can be assembled
in a single terminal function.

The type rebinding problem can thus be solved just by a simple
marker struct, which inherits from a template parameter
This commit is contained in:
Fischlurch 2023-06-04 01:54:15 +02:00
parent 71ea10bf21
commit 4601c6350e
6 changed files with 140 additions and 75 deletions

View file

@ -100,11 +100,12 @@ namespace engine {
void
CalcPlanContinuation::performJobPlanningChunk(FrameCnt nextStartFrame)
{
TimeAnchor refPoint(timings_, nextStartFrame);
#if false /////////////////////////////////////////////////////////////////////////////////////////////////////////////UNIMPLEMENTED :: TICKET #1301
JobPlanningSequence jobs = dispatcher_.onCalcStream(modelPort_, channel_)
.establishNextJobs(refPoint);
Job nextChunkOfPlanning = buildFollowUpJobFrom (refPoint);
#endif /////////////////////////////////////////////////////////////////////////////////////////////////////////////UNIMPLEMENTED :: TICKET #1301 TimeAnchor refPoint(timings_, nextStartFrame);
UNIMPLEMENTED ("the actual meat: access the scheduler and fed those jobs");
}

View file

@ -40,14 +40,6 @@ namespace engine {
FrameSequencer::~FrameSequencer() { }
/** @todo WIP */
Dispatcher::JobBuilder
Dispatcher::onCalcStream (ModelPort modelPort, uint channel)
{
JobBuilder builder = {this, modelPort,channel};
return builder;
}
/** @todo WIP */
FrameCoord

View file

@ -110,53 +110,24 @@ namespace engine {
}
};
/////////////////////////////////////////////////////////////////////////////////////////////////////////////TICKET #1301 : obsolete
public: //////////////////////////////////////////////////////////////////OOO TODO not public; need a way to pick up the result type
struct PipeFrameTick;
struct PipeSelector;
struct PipeExpander;
struct PipePlanner;
/////////////////////////////////////////////////////////////////////////////////////////////////////////////TICKET #1301 : obsolete
using FrameNrIter = lib::NumIter<FrameCnt>;
struct PipelineBuilder
: FrameNrIter
{
Dispatcher* dispatcher;
Timings timings;
ModelPort port;
DataSink sink;
auto
timeRange (Time start, Time after)
{
auto frame = [&](Time t){ return timings.getBreakPointAfter(t); };
auto reset = [&](auto i){ static_cast<FrameNrIter&>(*this) = i; };
reset (lib::eachNum (frame(start), frame(after)));
return lib::treeExplore (move(*this))
.transform ([&](FrameCnt frameNr) -> TimeVar //////////////////////////////TICKET #1261 : transform-iterator unable to handle immutable time
{
return timings.getFrameStartAt (frameNr);
});
}
};
/////////////////////////////////////////////////////////////////////////////////////////////////////////////TICKET #1301 : obsolete
public:
virtual ~Dispatcher(); ///< this is an interface
/////////////////////////////////////////////////////////////////////////////////////////////////////////////TICKET #1301 : obsolete
JobBuilder onCalcStream (ModelPort modelPort, uint channel);
PipeSelector forCalcStream (Timings timings);
PipelineBuilder forCalcStream(Timings timings, ModelPort port, DataSink sink)
template<class IT>
class PlanningPipeline
: public IT
{
return PipelineBuilder{FrameNrIter(), this, timings, port, sink};
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////////TICKET #1301 : obsolete
PipeFrameTick forCalcStream (Timings timings);
};
protected:
/** core dispatcher operation: based on the coordinates of a reference point,
@ -226,42 +197,56 @@ namespace engine {
++frameNr;
currPoint = timings.getFrameStartAt (frameNr);
}
/** Builder Function: start frame sequence */
auto
timeRange (Time start, Time after)
{
stopPoint = after;
frameNr = timings.getBreakPointAfter(start);
currPoint = timings.getFrameStartAt (frameNr);
// start iterator pipeline based on this as »state core«
return lib::treeExplore (move(*this));
}
};
inline Dispatcher::PipeFrameTick
Dispatcher::forCalcStream(Timings timings)
{
return PipeFrameTick{this, timings};
}
//////////////////////////////////////////////////////////////////////////////////////////////////////////////OOO need better solution for type rebinding
using Builder = decltype( declval<Dispatcher::PipeFrameTick>().timeRange (declval<Time>(), declval<Time>()));
template<class FUN>
using FunRes_t = typename lib::meta::_Fun<FUN>::Ret;
//using Builder = decltype( declval<Dispatcher::PipeFrameTick>().timeRange (declval<Time>(), declval<Time>()));
/**
* Job-planning Step-2: select data feed connection between ModelPort
* and DataSink; this entails to select the actually active Node pipeline
*/
struct Dispatcher::PipeSelector
: Builder
: Dispatcher::PipeFrameTick
{
/** Builder Function: start frame sequence */
PipeSelector
timeRange (Time start, Time after)
{
stopPoint = after;
frameNr = timings.getBreakPointAfter(start);
currPoint = timings.getFrameStartAt (frameNr);
return move(*this); // expected to invoke buildFeed(port,sink)
}
/** Builder Function: setup processing feed ModelPort -> DataSink */
auto
buildFeed (mobject::ModelPort port, play::DataSink sink)
{
// start iterator pipeline based on this as »state core«
auto pipeline = lib::treeExplore (move(*this));
using PipeIter = decltype(pipeline);
return PlanningPipeline<PipeIter>{move (pipeline)};
}
};
inline Dispatcher::PipeSelector
Dispatcher::forCalcStream(Timings timings)
{
return PipeSelector{this, timings};
}
/**
* Job-planning Step-3: monadic depth-first exploration of Prerequisites

View file

@ -173,6 +173,7 @@ namespace test {
TimeAnchor refPoint(timings, START_FRAME);
CHECK (refPoint == Time::ZERO + Duration(10, FrameRate::PAL));
#if false /////////////////////////////////////////////////////////////////////////////////////////////////////////////UNIMPLEMENTED :: TICKET #1301
FrameCoord coordinates = dispatcher.onCalcStream (modelPort,CHANNEL)
.relativeFrameLocation (refPoint, 15);
CHECK (coordinates.absoluteNominalTime == Time(0,1));
@ -187,8 +188,7 @@ namespace test {
Job frameJob = executionPlan.createJobFor (coordinates);
CHECK (frameJob.getNominalTime() == coordinates.absoluteNominalTime);
#if false /////////////////////////////////////////////////////////////////////////////////////////////////////////////UNIMPLEMENTED :: TICKET #1275
#endif /////////////////////////////////////////////////////////////////////////////////////////////////////////////UNIMPLEMENTED :: TICKET #1275
#endif /////////////////////////////////////////////////////////////////////////////////////////////////////////////UNIMPLEMENTED :: TICKET #1301
}
@ -200,6 +200,7 @@ namespace test {
void
verify_standardDispatcherUsage()
{
#if false /////////////////////////////////////////////////////////////////////////////////////////////////////////////UNIMPLEMENTED :: TICKET #1301
Dispatcher& dispatcher = mockDispatcher();
ModelPort modelPort (getTestPort());
Timings timings (FrameRate::PAL);
@ -217,6 +218,7 @@ namespace test {
Duration coveredTime (Offset(refPoint, last(plannedChunk).getNominalTime()));
CHECK (coveredTime >= timings.getPlanningChunkDuration());
#endif /////////////////////////////////////////////////////////////////////////////////////////////////////////////UNIMPLEMENTED :: TICKET #1301
///TODO nachfolgendes muß komplett umgeschrieben werden
///TODO definieren, wie das scheduler-interface angesprochen wird

View file

@ -152,6 +152,7 @@ namespace test {
/** @test use the Dispatcher interface (mocked) to generate a frame »beat«
* - demonstrate explicitly the mapping of a (frame) number sequence
* onto a sequence of time points with the help of time quantisation
* - use the Dispatcher API to produce the same frame time sequence
* @remark this is the foundation to generate top-level frame render jobs
*/
void
@ -171,12 +172,12 @@ namespace test {
MockDispatcher dispatcher;
play::Timings timings (FrameRate::PAL);
auto [port,sink] = dispatcher.getDummyConnection(0);
auto pipeline = dispatcher.forCalcStream(timings)
.timeRange(Time{200,0}, Time{FSecs{1,2}});
CHECK (materialise (pipeline)
CHECK (materialise (
treeExplore (
dispatcher.forCalcStream(timings)
.timeRange(Time{200,0}, Time{500,0}) // Note: end point is exclusive
))
== "200ms-240ms-280ms-320ms-360ms-400ms-440ms-480ms"_expect);
}
@ -187,6 +188,8 @@ namespace test {
void
accessTopLevelJobTicket()
{
MockDispatcher dispatcher;
auto [port,sink] = dispatcher.getDummyConnection(0);
UNIMPLEMENTED ("transform into job ticket access");
}

View file

@ -73690,8 +73690,8 @@ Date:&#160;&#160;&#160;Thu Apr 20 18:53:17 2023 +0200<br/>
<arrowlink COLOR="#32c808" DESTINATION="ID_1438204358" ENDARROW="Default" ENDINCLINATION="283;12;" ID="Arrow_ID_1706669462" STARTARROW="None" STARTINCLINATION="280;20;"/>
<icon BUILTIN="button_ok"/>
</node>
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1685744060666" ID="ID_676050987" MODIFIED="1685744074319" TEXT="f&#xfc;r Anwendung von TreeExplorer-Builder-Funktionen">
<icon BUILTIN="flag-yellow"/>
<node COLOR="#5b280f" CREATED="1685744060666" ID="ID_676050987" MODIFIED="1685833565946" TEXT="f&#xfc;r Anwendung von TreeExplorer-Builder-Funktionen">
<icon BUILTIN="button_cancel"/>
<node BACKGROUND_COLOR="#fdfdcf" COLOR="#ff0000" CREATED="1685809751146" ID="ID_1263839813" MODIFIED="1685809769709" TEXT="&#xfc;ber Sequenz von dedizierten Builder-Typen l&#xf6;sen">
<icon BUILTIN="yes"/>
</node>
@ -73700,9 +73700,91 @@ Date:&#160;&#160;&#160;Thu Apr 20 18:53:17 2023 +0200<br/>
<node CREATED="1685809782637" ID="ID_1994330949" MODIFIED="1685809800179" TEXT="(inline)-Funktionen sind erst nach dem Typ definiert"/>
<node CREATED="1685809800830" ID="ID_835161833" MODIFIED="1685809812910" TEXT="decltype kann erst auf vollst&#xe4;ndigen Typ angewendet werden"/>
<node CREATED="1685809816376" ID="ID_1605798061" MODIFIED="1685809838809" TEXT="brauche aber den decltype zu Beginn des n&#xe4;chsten Binder-Typs"/>
<node BACKGROUND_COLOR="#f0d5c5" COLOR="#990033" CREATED="1685809839549" ID="ID_97735774" MODIFIED="1685809855277" TEXT="wo kann ich diesen Schlonz sauber unterbringen?">
<node COLOR="#990033" CREATED="1685809839549" ID="ID_97735774" MODIFIED="1685831728915" TEXT="wo kann ich diesen Schlonz sauber unterbringen?">
<icon BUILTIN="help"/>
<icon BUILTIN="button_cancel"/>
<node COLOR="#5b280f" CREATED="1685830984120" ID="ID_1114059991" MODIFIED="1685831038447" TEXT="eine Traits-Klasse geht hier nicht">
<richcontent TYPE="NOTE"><html>
<head>
</head>
<body>
<p>
...weil sie erst nach den Builder-Typen definiert werden kann, aber bereits vor ihnen gebraucht wird
</p>
</body>
</html></richcontent>
<icon BUILTIN="button_cancel"/>
</node>
<node COLOR="#5b280f" CREATED="1685830893511" ID="ID_293887488" MODIFIED="1685831715741" TEXT="k&#xfc;nstlich Templates einf&#xfc;gen?">
<richcontent TYPE="NOTE"><html>
<head>
</head>
<body>
<p>
...weil man dadruch von der Definitionsreihenfolge entkoppeln kann
</p>
</body>
</html></richcontent>
<icon BUILTIN="button_cancel"/>
</node>
<node COLOR="#5b280f" CREATED="1685830943935" ID="ID_340189220" MODIFIED="1685836711378" TEXT="Funktionspointer und R&#xfc;ckgabewert von der Signatur abgreifen?">
<richcontent TYPE="NOTE"><html>
<head>
</head>
<body>
<p>
geht, ist aber alles andere als klar, da man zun&#228;chst den Member-Fun-Pointer abgreifen mu&#223;, und dann von diesem den <b><font color="#4d1e6d">decltype</font></b>&#160;ziehen (und erst damit kann man <font face="Monospaced">lib::meta::_Fun</font>&#160;anwenden)
</p>
<br/>
<p>
<font color="#62322e" face="Monospaced" size="2">
&#160;&#160;using Pointer = decltype(&amp;Dispatcher::PipeFrameTick::timeRange);<br/>
&#160;&#160;using ResType = lib::meta::_Fun&lt;Pointer&gt;::Ret;<br/>
&#160;<br/>
&#160;&#160;struct Dispatcher::PipeSelector<br/>
&#160;&#160;&#160;&#160;: ResType<br/>
&#160;&#160;&#160;&#160;{<br/>
&#160;&#160;&#160;&#160;&#160;&#160;...<br/>
&#160;&#160;&#160;&#160;};
</font>
</p>
</body>
</html></richcontent>
<icon BUILTIN="button_cancel"/>
</node>
</node>
</node>
<node COLOR="#435e98" CREATED="1685830854298" ID="ID_1539456468" MODIFIED="1685833560849" TEXT="anders herum: brauchen wir &#xfc;berhaupt Zugang zum TreeExplorer-Builder?">
<font NAME="SansSerif" SIZE="12"/>
<icon BUILTIN="help"/>
<node CREATED="1685831255381" ID="ID_300704569" MODIFIED="1685831305089" TEXT="&#x27f6; die Idee war heuristisch &#x2014; wird aber gar nicht gebraucht"/>
<node CREATED="1685831075727" ID="ID_1734873256" MODIFIED="1685831104437" TEXT="letztlich passiert der ganze Pipelie-Bau jetzt an einer einzigen Stelle"/>
<node CREATED="1685831111935" ID="ID_1008108972" MODIFIED="1685831156798" TEXT="und zwar vor dem Expander wird schon der &#xbb;FrameDropper&#xab; gebraucht"/>
</node>
<node COLOR="#5b280f" CREATED="1685833510263" ID="ID_1962899865" MODIFIED="1685833556706">
<richcontent TYPE="NODE"><html>
<head>
</head>
<body>
<p>
<b>Fazit</b>: Anwendung von TreeExplorer passiert nur in einem Funktions-Scope
</p>
</body>
</html></richcontent>
<icon BUILTIN="stop-sign"/>
</node>
</node>
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1685833568159" ID="ID_1859576493" MODIFIED="1685833588992" TEXT="also brauchen wir nur einen Wrapper-Typ am Ende">
<icon BUILTIN="flag-yellow"/>
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1685833591596" ID="ID_1247414372" MODIFIED="1685833619292" TEXT="der &#xfc;bernimmt den Iterator vom fertigen TreeExplorer">
<icon BUILTIN="flag-yellow"/>
</node>
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1685833605178" ID="ID_433083338" MODIFIED="1685833619293" TEXT="und zwar kann man diesen dann durchaus per Template-Parameter &#xfc;bergeben">
<icon BUILTIN="flag-yellow"/>
</node>
</node>
</node>