Chain-Load: provide a scheme for repeated init

For context: I've engaged into writing a `LazyInit` helper component,
to resolve the inner contradiction between DSL use of `RandomDraw`
(implying value semantics) and the design of a processing pipeline,
which quite naturally leads to binding by reference into the enclosing
implementation.

In most cases, this change (to lazy on-demand initialisation) should be
transparent for the complete implementation code in `RandomDraw` -- with
one notable exception: when configuring an elaborate pipeline, especially
with dynamic changes of the probability profile during the simulation run,
then then obviously there is the desire to use the existing processing
pipeline from the reconfiguration function (in fact it would be quite
hard to explain why and where this should be avoided). `LazyInit` breaks
this usage scenario, since -- at the time the reconfiguration runs --
now the object is not initialised at all, but holds a »Trojan« functor,
which will trigger initialisation eventually.

After some headaches and grievances (why am I engaging into such an
elaborate solution for such an accidental and marginal topic...),
unfortunately it occurred to me that even this problem can be fixed,
with yet some further "minimal" adjustments to the scheme: the LazyInit
mechanism ''just needs to ensure'' that the init-functor ''sees the
same environment as in eager init'' -- that is, it must clear out the
»Trojan« first, and it ''could apply any previous pending init function''
fist. That is, with just a minimal change, we possibly build a chain
of init functors now, and apply them in given order, so each one
sees the state the previous one created -- as if this was just
direct eager object manipulation...
This commit is contained in:
Fischlurch 2023-11-25 17:18:26 +01:00
parent 04ca79fd65
commit ed8d9939bd
2 changed files with 182 additions and 2 deletions

View file

@ -335,6 +335,13 @@ namespace lib {
PendingInit
prepareInitialiser (std::function<SIG>& targetFunctor, INI&& initialiser)
{
if (isInit() and targetFunctor)
{// object is already »engaged« — no need to delay init
using ExpectedArg = _FunArg<INI>;
initialiser (static_cast<ExpectedArg> (this));
return PendingInit(); // keep engaged; no pending init
}
// else: prepare delayed init...
PendingInit storageHandle{
new HeapStorage{
buildInitialiserDelegate (targetFunctor, forward<INI> (initialiser))}};
@ -344,12 +351,22 @@ namespace lib {
}
template<class SIG>
DelegateType<SIG>*
static DelegateType<SIG>*
getPointerToDelegate (HeapStorage& buffer)
{
return reinterpret_cast<DelegateType<SIG>*> (&buffer);
}
template<class SIG>
static std::function<SIG>
maybeInvoke (PendingInit const& pendingInit, RawAddr location)
{
if (not pendingInit) // no pending init -> empty TargetFun
return std::function<SIG>();
auto* pendingDelegate = getPointerToDelegate<SIG>(*pendingInit);
return (*pendingDelegate) (location); // invoke to create new TargetFun
}
template<class SIG, class INI>
DelegateType<SIG>
buildInitialiserDelegate (std::function<SIG>& targetFunctor, INI&& initialiser)
@ -358,12 +375,15 @@ namespace lib {
using ExpectedArg = _FunArg<INI>;
return DelegateType<SIG>{
[performInit = forward<INI> (initialiser)
,previousInit = move (pendingInit_)
,targetOffset = captureRawAddrOffset (this, &targetFunctor)]
(RawAddr location) -> TargetFun&
{// apply known offset backwards to find current location of the host object
TargetFun* target = relocate<TargetFun> (location, -FUNCTOR_PAYLOAD_OFFSET);
LazyInit* self = relocate<LazyInit> (target, -targetOffset);
REQUIRE (self);
// setup target as it would be with eager init
(*target) = maybeInvoke<SIG> (previousInit, location);
// invoke init, possibly downcast to derived *self
performInit (static_cast<ExpectedArg> (self));
self->pendingInit_.reset(); // release storage

View file

@ -97558,7 +97558,7 @@ Date:&#160;&#160;&#160;Thu Apr 20 18:53:17 2023 +0200<br/>
<node BACKGROUND_COLOR="#e0ceaa" COLOR="#690f14" CREATED="1700878072770" ID="ID_1728628936" MODIFIED="1700878084969" TEXT="Prolbem: ctor-Signatur zweideutig">
<icon BUILTIN="messagebox_warning"/>
</node>
<node CREATED="1700878086446" ID="ID_1368715362" MODIFIED="1700878097543" TEXT="l&#xf6;sen durch ein MarkDisabled() - Tag">
<node COLOR="#435e98" CREATED="1700878086446" ID="ID_1368715362" MODIFIED="1700883011557" TEXT="l&#xf6;sen durch ein MarkDisabled() - Tag">
<icon BUILTIN="idea"/>
</node>
</node>
@ -97579,6 +97579,17 @@ Date:&#160;&#160;&#160;Thu Apr 20 18:53:17 2023 +0200<br/>
</richcontent>
<arrowlink COLOR="#a11470" DESTINATION="ID_615420321" ENDARROW="Default" ENDINCLINATION="-38;-156;" ID="Arrow_ID_1147775137" STARTARROW="None" STARTINCLINATION="-409;35;"/>
<icon BUILTIN="messagebox_warning"/>
<node CREATED="1700883132460" ID="ID_1624384536" MODIFIED="1700883156773" TEXT="des Genaueren: der &#xbb;Trojaner&#xab; sieht wir ein valider Funktor aus"/>
<node CREATED="1700883162688" ID="ID_1541865350" MODIFIED="1700883212555" TEXT="sofern sich Initialisierung den bestehenden Funktor aufgreift..."/>
<node CREATED="1700883213489" ID="ID_1802613840" MODIFIED="1700883224039" TEXT="...besteht zumindest die Gefahr f&#xfc;r Endlosschleifen">
<icon BUILTIN="broken-line"/>
</node>
<node CREATED="1700883266746" ID="ID_541587975" MODIFIED="1700883289794" TEXT="dieses Problem k&#xf6;nnte nur durch LazyInit selber addressiert werden">
<icon BUILTIN="yes"/>
<node CREATED="1700883302425" ID="ID_601939875" MODIFIED="1700883331621" TEXT="isInit()"/>
<node CREATED="1700883367516" ID="ID_358220582" MODIFIED="1700883381190" TEXT="hilft nicht bei kaskadierten Aufrufen"/>
<node CREATED="1700883887222" ID="ID_1972271604" MODIFIED="1700883898233" TEXT="Nur der Installations-Mechanismus h&#xe4;tte eine Chance"/>
</node>
</node>
</node>
</node>
@ -97628,6 +97639,155 @@ Date:&#160;&#160;&#160;Thu Apr 20 18:53:17 2023 +0200<br/>
</node>
</node>
</node>
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1700883451009" ID="ID_1957619208" MODIFIED="1700883468235" TEXT="Analyse: wiederholte / kaskadierte Initialisierungen">
<icon BUILTIN="flag-yellow"/>
<node CREATED="1700883475839" ID="ID_837624106" MODIFIED="1700883477453" TEXT="Ablauf">
<node CREATED="1700883822501" ID="ID_402007618" MODIFIED="1700883824872" TEXT="Fall-1">
<node CREATED="1700883478738" ID="ID_1745053013" MODIFIED="1700883862198" TEXT="isInit() &#x27fc; true(leer) + kein Funktor"/>
<node CREATED="1700883537958" ID="ID_1244902831" MODIFIED="1700883549760" TEXT="isInit() &#x27fc; false + Trap"/>
<node CREATED="1700883563354" ID="ID_406459173" MODIFIED="1700883580135" TEXT="Trap &#x27f6; neuer Funktor"/>
</node>
<node CREATED="1700883585031" ID="ID_785231222" MODIFIED="1700883819027" TEXT="Fall-2">
<node CREATED="1700883478738" ID="ID_839435401" MODIFIED="1700883503483" TEXT="isInit() &#x27fc; true + echter Funktor"/>
<node CREATED="1700883537958" ID="ID_1512311774" MODIFIED="1700883549760" TEXT="isInit() &#x27fc; false + Trap"/>
<node CREATED="1700883563354" ID="ID_8356372" MODIFIED="1700883580135" TEXT="Trap &#x27f6; neuer Funktor"/>
</node>
<node CREATED="1700883590811" ID="ID_1518533927" MODIFIED="1700883821132" TEXT="Fall-3">
<node CREATED="1700883537958" ID="ID_204292878" MODIFIED="1700883549760" TEXT="isInit() &#x27fc; false + Trap"/>
<node CREATED="1700883638446" ID="ID_1317225183" MODIFIED="1700883669832" TEXT="+ neues Delegate + Trap"/>
<node CREATED="1700883653890" ID="ID_1572351022" MODIFIED="1700883656190" TEXT="+ ..."/>
<node CREATED="1700883563354" ID="ID_536028687" MODIFIED="1700883580135" TEXT="Trap &#x27f6; neuer Funktor"/>
</node>
</node>
<node CREATED="1700883981242" ID="ID_476427708" MODIFIED="1700883983854" TEXT="Fall-Muster">
<node CREATED="1700883997648" ID="ID_279106916" MODIFIED="1700884041366" TEXT="not pendingInit + kein Funktor &#x27f9; Fall-1"/>
<node CREATED="1700884059833" ID="ID_1932722762" MODIFIED="1700884071728" TEXT="not pendingInit + Funktor &#x27f9; Fall-2">
<node CREATED="1700884197594" ID="ID_1851874040" MODIFIED="1700884208296" TEXT="dieser Funktor w&#xe4;re ein Vorl&#xe4;ufer"/>
</node>
<node CREATED="1700884095741" ID="ID_1167670160" MODIFIED="1700884112957" TEXT="pendingInit + Funktor &#x27f9; Fall-3">
<node CREATED="1700884240680" ID="ID_1327583430" MODIFIED="1700884265507" TEXT="pendingInit zuerst anwenden &#x27fc; &#xdc;bergang in Fall-2"/>
</node>
<node CREATED="1700884114752" ID="ID_364127230" MODIFIED="1700884129803" TEXT="pendingInit + kein Funktor &#x27f9; LogicBroken"/>
</node>
<node CREATED="1700884471281" ID="ID_944993217" MODIFIED="1700884475692" TEXT="L&#xf6;sung...">
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1700884476470" ID="ID_1258681625" MODIFIED="1700884494881" TEXT="minimal: sollte gemacht werden">
<icon BUILTIN="yes"/>
<node CREATED="1700884496384" ID="ID_169506932" MODIFIED="1700884505209" TEXT="vor Aufruf des Initialisers..."/>
<node CREATED="1700884506445" ID="ID_14177401" MODIFIED="1700884522694" TEXT="den bestehenden Functor leer machen"/>
</node>
<node BACKGROUND_COLOR="#f0d5c5" COLOR="#990033" CREATED="1700884537072" ID="ID_1176504809" MODIFIED="1700925243615" TEXT="erweitert: machbar?">
<icon BUILTIN="help"/>
<node CREATED="1700884615478" ID="ID_1008762319" MODIFIED="1700884620881" TEXT="Init-Verkettung">
<node CREATED="1700884634923" ID="ID_1100836382" MODIFIED="1700884788061" TEXT="bestehenden pendingInit zuerst aufrufen">
<linktarget COLOR="#df4480" DESTINATION="ID_1100836382" ENDARROW="Default" ENDINCLINATION="91;0;" ID="Arrow_ID_902131970" SOURCE="ID_1845471747" STARTARROW="None" STARTINCLINATION="91;0;"/>
</node>
<node CREATED="1700884662223" ID="ID_600393324" MODIFIED="1700884669922" TEXT="damit liegt ein valider Funktor vor"/>
<node CREATED="1700884670570" ID="ID_603115571" MODIFIED="1700884678473" TEXT="der aktuelle Initialiser kann diesen verwenden"/>
<node CREATED="1700884707938" ID="ID_1487565427" MODIFIED="1700884794311" TEXT="Rekursion">
<linktarget COLOR="#b530c5" DESTINATION="ID_1487565427" ENDARROW="Default" ENDINCLINATION="9;34;" ID="Arrow_ID_1425846605" SOURCE="ID_1845471747" STARTARROW="None" STARTINCLINATION="-123;63;"/>
<node CREATED="1700884712862" ID="ID_1270371043" MODIFIED="1700884740601" TEXT="einen bestehenden pendingInit in die den adaptierten Initializer"/>
<node CREATED="1700884753993" ID="ID_1845471747" MODIFIED="1700884805374" TEXT="dort wird er zuerst aurgerufen">
<arrowlink COLOR="#df4480" DESTINATION="ID_1100836382" ENDARROW="Default" ENDINCLINATION="91;0;" ID="Arrow_ID_902131970" STARTARROW="None" STARTINCLINATION="91;0;"/>
<arrowlink COLOR="#b530c5" DESTINATION="ID_1487565427" ENDARROW="Default" ENDINCLINATION="9;34;" ID="Arrow_ID_1425846605" STARTARROW="None" STARTINCLINATION="-123;63;"/>
</node>
</node>
</node>
<node CREATED="1700884833301" ID="ID_1023052501" MODIFIED="1700884835988" TEXT="Fall-2">
<node CREATED="1700884837024" ID="ID_502217686" MODIFIED="1700884841120" TEXT="der Fall ist speziell"/>
<node CREATED="1700884841856" ID="ID_1654607159" MODIFIED="1700884865645" TEXT="das Objekt ist &#xbb;engaged&#xab;, d.h. darf nicht mehr bewegt werden"/>
<node CREATED="1700884866732" ID="ID_1005926094" MODIFIED="1700884910994" TEXT="unter diesen Umst&#xe4;nden ist gar keine lazy-Init notwendig"/>
</node>
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1700885072177" ID="ID_1660971679" MODIFIED="1700885098097" TEXT="Antwort: ist ohne gro&#xdf;en Aufwand machbar">
<icon BUILTIN="yes"/>
</node>
</node>
<node CREATED="1700885100085" ID="ID_1294902012" MODIFIED="1700928226538" TEXT="operational">
<icon BUILTIN="list"/>
<node CREATED="1700885105797" ID="ID_392736313" MODIFIED="1700885117623" TEXT="beim Aufruf zum Installieren...">
<node CREATED="1700885126594" ID="ID_933835878" MODIFIED="1700885357053" TEXT="zuerst den Fall feststellen">
<arrowlink COLOR="#517184" DESTINATION="ID_1059814147" ENDARROW="Default" ENDINCLINATION="15;-20;" ID="Arrow_ID_1161089832" STARTARROW="None" STARTINCLINATION="-149;0;"/>
<arrowlink COLOR="#5e5a98" DESTINATION="ID_1439092323" ENDARROW="Default" ENDINCLINATION="93;-8;" ID="Arrow_ID_1648939093" STARTARROW="None" STARTINCLINATION="86;0;"/>
</node>
<node CREATED="1700885175427" ID="ID_1439092323" MODIFIED="1700885335623" TEXT="je nach Fall den Adapter konfigurieren">
<linktarget COLOR="#5e5a98" DESTINATION="ID_1439092323" ENDARROW="Default" ENDINCLINATION="93;-8;" ID="Arrow_ID_1648939093" SOURCE="ID_933835878" STARTARROW="None" STARTINCLINATION="86;0;"/>
<node CREATED="1700885192462" ID="ID_271012983" MODIFIED="1700885202371" TEXT="Fall-1 : nur Trap entfernen"/>
<node CREATED="1700885205327" ID="ID_1557648916" MODIFIED="1700885220502" TEXT="Fall-3 : Trap entfernen + Vorl&#xe4;ufer aufrufen"/>
</node>
</node>
<node CREATED="1700885226922" ID="ID_1059814147" MODIFIED="1700885318282" TEXT="Fall-2">
<linktarget COLOR="#517184" DESTINATION="ID_1059814147" ENDARROW="Default" ENDINCLINATION="15;-20;" ID="Arrow_ID_1161089832" SOURCE="ID_933835878" STARTARROW="None" STARTINCLINATION="-149;0;"/>
<node CREATED="1700885257048" ID="ID_759696290" MODIFIED="1700885270297" TEXT="es liegt bereits ein echter Funktor vor"/>
<node CREATED="1700885270910" ID="ID_845153085" MODIFIED="1700885283866" TEXT="den Init-Funktor mit (this) direkt aufrufen"/>
<node CREATED="1700885284844" ID="ID_1493413821" MODIFIED="1700925478010" TEXT="keinen pendingInit zur&#xfc;ckgeben (Objekt bleibt gesperrt)"/>
</node>
</node>
</node>
</node>
<node BACKGROUND_COLOR="#eef0c5" COLOR="#990000" CREATED="1700885399157" ID="ID_1052362467" MODIFIED="1700928254133" TEXT="Erg&#xe4;nzung der Init-Routine">
<icon BUILTIN="pencil"/>
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1700885425170" ID="ID_1390543220" MODIFIED="1700885449554" TEXT="Logik zur Fall-Erkennung">
<icon BUILTIN="flag-yellow"/>
</node>
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1700885455310" ID="ID_75201701" MODIFIED="1700885475092" TEXT="zus&#xe4;tzlich einen shared_ptr innerhalb vom Adapter vorsehen">
<icon BUILTIN="flag-yellow"/>
<node CREATED="1700885486066" ID="ID_1745928936" MODIFIED="1700885498658">
<richcontent TYPE="NODE"><html>
<head>
</head>
<body>
<p>
<i>darauf </i>kommt es jetzt auch nicht mehr an
</p>
</body>
</html>
</richcontent>
</node>
<node CREATED="1700885514470" ID="ID_1944104952" MODIFIED="1700885786804" TEXT="Hinweis/Warnung: die pending-Functors sind shared">
<richcontent TYPE="NOTE"><html>
<head>
</head>
<body>
<p>
Funktor ist Funktor!
</p>
<p>
Deshalb sind sie ja stateless (und m&#252;ssen auch so bleiben, also nicht mutable). F&#252;r jeweils <i>eine Instanz</i>&#160;wird ein Funktor einfach &#187;verbrannt&#171;, indem man ihn aufruft und danach das pendingInit leert. Und zwar auf <b>*self</b>&#160;&#160;&#8212; der Funktor als Solcher bleibt stateless. Wenn ihn noch jemand anders referenziert, dann sch&#246;n....
</p>
</body>
</html>
</richcontent>
</node>
<node CREATED="1700885787889" ID="ID_532859014" MODIFIED="1700885850873">
<richcontent TYPE="NODE"><html>
<head>
</head>
<body>
<p>
Beim Umkonfigurieren wird der pendingInit <i>verschoben</i>
</p>
</body>
</html>
</richcontent>
<richcontent TYPE="NOTE"><html>
<head>
</head>
<body>
<p>
und zwar aus dem LazyInit-Objekt in den Adapter hinein. Der use-count bleibt dadurch gleich.
</p>
</body>
</html>
</richcontent>
</node>
</node>
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1700885870078" ID="ID_1085520028" MODIFIED="1700885900667" TEXT="wenn es einen pendingInit gibt (&#x27f9;Fall-3) dann verschieben">
<icon BUILTIN="flag-yellow"/>
</node>
</node>
</node>
</node>
</node>