Library: attempt workaround to problem with references

There is an insidious problem when the Transformer takes references to internal state
within upstream iterators or state core. This problem only manifests when
a invariant based filtering or grouping operation is added after the Transformer,
because such an operation (notably Filter) will typically attempt to establish
the invariant from the constructor (to avoid dangling state). Unfortunately
doing so involves pulling data ''before the overall pipeline is moved into final location''

A workaround is to make the Transformer ''disengage'' on copy, so to provoke
a refresh and new pull in the new location after the copy / move / swap.
This only works if the transformer function as such is idempotent.
This commit is contained in:
Fischlurch 2024-11-23 17:21:41 +01:00
parent 8d1740418b
commit e50e9cb8e7
4 changed files with 96 additions and 55 deletions

View file

@ -78,6 +78,11 @@ The Lumiera project uses GNU indentation style with slight adaptations.
`&`,`|`, `^`, sometimes also for `!` -- using those is taken as an indication of `&`,`|`, `^`, sometimes also for `!` -- using those is taken as an indication of
entering the ``danger zone''... entering the ``danger zone''...
Spelling
~~~~~~~~
Lumiera uses _British spelling._ Please set your spell checker accordingly.
Naming conventions Naming conventions
~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~
Naming conventions are used to characterise the kind of element at hand and give a visual Naming conventions are used to characterise the kind of element at hand and give a visual
@ -110,11 +115,6 @@ In case a definition actually denotes an object, there should be
The object pointer/handle should be passed as 1^st^ argument with the name +self+ The object pointer/handle should be passed as 1^st^ argument with the name +self+
Spelling
~~~~~~~~
Lumiera uses _British spelling._ Please set your spell checker accordingly.
General Code Arrangement and Layout General Code Arrangement and Layout
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- Headers and translation units are named `*.hpp` and `*.cpp` rsp. `*.h` and `*.c` + - Headers and translation units are named `*.hpp` and `*.cpp` rsp. `*.h` and `*.c` +

View file

@ -119,7 +119,7 @@ Lumiera iterators::
construct and in while-loops. construct and in while-loops.
IterExplorer:: IterExplorer::
The function `lib::explore(IT)` builds on top of these features and is meant to basically The function `lib::explore(IT)` builds on top of these features and is meant to basically
iterate anything that is iterable -- so use it to abstract away the details. iterate anything that is iterable -- this can be used to level and abstract away the details.
+ +
- can be filtered and transformed - can be filtered and transformed
- can be reduced or collected into a vector - can be reduced or collected into a vector

View file

@ -79,10 +79,11 @@
** **
** @warning all builder operations work by _moving_ the existing pipeline built thus far into the parent ** @warning all builder operations work by _moving_ the existing pipeline built thus far into the parent
** of the newly built subclass object. The previously existing pipeline is defunct after that ** of the newly built subclass object. The previously existing pipeline is defunct after that
** move; if you captured it into a variable, be sure to capture the _result_ of the new ** move; if you captured it into a variable, be sure to capture the _result_ of the new builder
** builder operation as well and don't use the old variable anymore. Moreover, it should ** operation as well and don't use the old variable anymore. An insidious trap can be to store
** be ensured that any "state core" used within IterExplorer has an efficient move ctor; ** references to source iterator state _from within_ the pipeline. Moreover, it should be ensured
** including RVO, the compiler is typically able to optimise such move calls away altogether. ** that any "state core" used within IterExplorer has an efficient move ctor; including RVO,
** the compiler is typically able to optimise such move calls away altogether.
** **
** @see IterExplorer_test ** @see IterExplorer_test
** @see iter-adapter.hpp ** @see iter-adapter.hpp
@ -763,6 +764,10 @@ namespace lib {
* `operator->` on any iterator downstream. This is also the reason why the * `operator->` on any iterator downstream. This is also the reason why the
* ItemWrapper is necessary, precisely _because we want to support_ functions * ItemWrapper is necessary, precisely _because we want to support_ functions
* producing a value; it provides a safe location for this value to persist. * producing a value; it provides a safe location for this value to persist.
* @warning handling a transformer function which exposes references can be dangerous.
* For this reason, Transformer attempts to »dis-engage« on each copy / assignment,
* in order to provoke a re-invocation of the transformer function, which hopefully
* picks up references to the copied / moved / swapped location. Be careful though!
*/ */
template<class SRC, class RES> template<class SRC, class RES>
class Transformer class Transformer
@ -782,15 +787,38 @@ namespace lib {
using pointer = typename meta::ValueTypeBinding<RES>::pointer; using pointer = typename meta::ValueTypeBinding<RES>::pointer;
Transformer() =default;
// inherited default copy operations
template<typename FUN> template<typename FUN>
Transformer (SRC&& dataSrc, FUN&& transformFunctor) Transformer (SRC&& dataSrc, FUN&& transformFunctor)
: SRC{move (dataSrc)} // NOTE: slicing move to strip IterExplorer (Builder) : SRC{move (dataSrc)} // NOTE: slicing move to strip IterExplorer (Builder)
, trafo_{_FunTraits<FUN,SRC>::adaptFunctor (forward<FUN> (transformFunctor))} , trafo_{_FunTraits<FUN,SRC>::adaptFunctor (forward<FUN> (transformFunctor))}
{ } { }
Transformer() =default;
Transformer (Transformer const& o)
: SRC{o}
, trafo_{o.trafo_}
, treated_{/* deliberately empty: force re-engage */}
{ }
Transformer (Transformer && o)
: SRC{move (o)}
, trafo_{move (o.trafo_)}
, treated_{/* deliberately empty: force re-engage */}
{ }
Transformer&
operator= (Transformer changed)
{
swap (*this,changed);
return *this;
}
friend void
swap (Transformer& t1, Transformer& t2)
{
using std::swap;
t1.treated_.reset();
t2.treated_.reset();
swap (t1.trafo_, t2.trafo_);
}
/** refresh state when other layers manipulate the source sequence /** refresh state when other layers manipulate the source sequence
* @remark expansion replaces the current element by a sequence of * @remark expansion replaces the current element by a sequence of
@ -981,6 +1009,8 @@ namespace lib {
* This limitation was deemed acceptable (adapting a function with several arguments would * This limitation was deemed acceptable (adapting a function with several arguments would
* require quite some nasty technicalities). The first argument of this `aggFun` refers * require quite some nasty technicalities). The first argument of this `aggFun` refers
* to the accumulator by value, and thereby also implicitly defines the aggregate result type. * to the accumulator by value, and thereby also implicitly defines the aggregate result type.
* @warning the Aggregator \a AGG *must not capture references* to upstream internal state, because
* the overall pipeline will be moved into final location _after the initial ctor call._
*/ */
template<class SRC, typename AGG, class GRP> template<class SRC, typename AGG, class GRP>
class GroupAggregator class GroupAggregator

View file

@ -19134,9 +19134,7 @@
</node> </node>
<node CREATED="1664834616551" ID="ID_1590264446" MODIFIED="1664834836962" TEXT="in der Endversion wird uns die Hysterese sch&#xfc;tzen"> <node CREATED="1664834616551" ID="ID_1590264446" MODIFIED="1664834836962" TEXT="in der Endversion wird uns die Hysterese sch&#xfc;tzen">
<richcontent TYPE="NOTE"><html> <richcontent TYPE="NOTE"><html>
<head> <head/>
</head>
<body> <body>
<p> <p>
...unter der Annahme, da&#223; das K&#252;rzen ggfs.auch verl&#228;ngern kann, und damit schon relativ nahe am verf&#252;gbaren Platz ist. Dann verhindert die Hysterese, da&#223; nochmal gepr&#252;ft wird ...unter der Annahme, da&#223; das K&#252;rzen ggfs.auch verl&#228;ngern kann, und damit schon relativ nahe am verf&#252;gbaren Platz ist. Dann verhindert die Hysterese, da&#223; nochmal gepr&#252;ft wird
@ -19590,9 +19588,7 @@
<node CREATED="1665873235907" ID="ID_438342430" MODIFIED="1665873254132" TEXT="hier soll sich das ElementBoxWidget m&#xf6;glichst passiv verhalten"/> <node CREATED="1665873235907" ID="ID_438342430" MODIFIED="1665873254132" TEXT="hier soll sich das ElementBoxWidget m&#xf6;glichst passiv verhalten"/>
<node CREATED="1665873270653" ID="ID_340799218" MODIFIED="1665873303819"> <node CREATED="1665873270653" ID="ID_340799218" MODIFIED="1665873303819">
<richcontent TYPE="NODE"><html> <richcontent TYPE="NODE"><html>
<head> <head/>
</head>
<body> <body>
<p> <p>
es gibt <i>anderswo </i>einen dedizierten &quot;Content Controller&quot; es gibt <i>anderswo </i>einen dedizierten &quot;Content Controller&quot;
@ -20045,9 +20041,7 @@
</node> </node>
<node CREATED="1666284884372" ID="ID_1055383793" MODIFIED="1666285096886"> <node CREATED="1666284884372" ID="ID_1055383793" MODIFIED="1666285096886">
<richcontent TYPE="NODE"><html> <richcontent TYPE="NODE"><html>
<head> <head/>
</head>
<body> <body>
<p> <p>
liegt an der <i>inkrementellen Natur</i>&#160;der Layout-Zuteilung liegt an der <i>inkrementellen Natur</i>&#160;der Layout-Zuteilung
@ -20593,9 +20587,7 @@
<icon BUILTIN="messagebox_warning"/> <icon BUILTIN="messagebox_warning"/>
<node CREATED="1480724761876" ID="ID_335451126" MODIFIED="1576282358098" TEXT="wegen BusTerm"> <node CREATED="1480724761876" ID="ID_335451126" MODIFIED="1576282358098" TEXT="wegen BusTerm">
<richcontent TYPE="NOTE"><html> <richcontent TYPE="NOTE"><html>
<head> <head/>
</head>
<body> <body>
<p> <p>
braucht feste Speicher-Addresse braucht feste Speicher-Addresse
@ -21256,9 +21248,7 @@
</node> </node>
<node CREATED="1575220914655" ID="ID_646969276" MODIFIED="1575220994424" TEXT="nur TrackPresenter oder DisplayFrame k&#xe4;men in Frage"> <node CREATED="1575220914655" ID="ID_646969276" MODIFIED="1575220994424" TEXT="nur TrackPresenter oder DisplayFrame k&#xe4;men in Frage">
<richcontent TYPE="NOTE"><html> <richcontent TYPE="NOTE"><html>
<head> <head/>
</head>
<body> <body>
<p> <p>
weil nach hier etablierter Policy diesen erlaubt w&#228;re, &quot;von oben&quot; in den trackPresenter.displayFrame.trackBody reinzugreifen f&#252;r die startLine_ weil nach hier etablierter Policy diesen erlaubt w&#228;re, &quot;von oben&quot; in den trackPresenter.displayFrame.trackBody reinzugreifen f&#252;r die startLine_
@ -23206,9 +23196,7 @@
</body> </body>
</html></richcontent> </html></richcontent>
<richcontent TYPE="NOTE"><html> <richcontent TYPE="NOTE"><html>
<head> <head/>
</head>
<body> <body>
<p> <p>
...hab ich mich je anders entschieden? ...hab ich mich je anders entschieden?
@ -26893,9 +26881,7 @@
<node CREATED="1563469368703" ID="ID_856512794" MODIFIED="1563469385040" TEXT="jeder weitere Sub-Track h&#xe4;ngt eine Zeile an"/> <node CREATED="1563469368703" ID="ID_856512794" MODIFIED="1563469385040" TEXT="jeder weitere Sub-Track h&#xe4;ngt eine Zeile an"/>
<node CREATED="1563469415896" ID="ID_307382994" MODIFIED="1563469442614"> <node CREATED="1563469415896" ID="ID_307382994" MODIFIED="1563469442614">
<richcontent TYPE="NODE"><html> <richcontent TYPE="NODE"><html>
<head> <head/>
</head>
<body> <body>
<p> <p>
aber verschachtelte sub-Tracks werden <i>in</i>&#160;dieser gehandhabt aber verschachtelte sub-Tracks werden <i>in</i>&#160;dieser gehandhabt
@ -37050,9 +37036,7 @@
<icon BUILTIN="stop-sign"/> <icon BUILTIN="stop-sign"/>
<node CREATED="1533310564980" ID="ID_1796116534" MODIFIED="1576282358027" TEXT="ist es nicht..."> <node CREATED="1533310564980" ID="ID_1796116534" MODIFIED="1576282358027" TEXT="ist es nicht...">
<richcontent TYPE="NOTE"><html> <richcontent TYPE="NOTE"><html>
<head> <head/>
</head>
<body> <body>
<p> <p>
nur bei laufender Event-Loop nur bei laufender Event-Loop
@ -40250,9 +40234,7 @@
</node> </node>
<node CREATED="1666964041691" ID="ID_190646112" MODIFIED="1666964239733"> <node CREATED="1666964041691" ID="ID_190646112" MODIFIED="1666964239733">
<richcontent TYPE="NODE"><html> <richcontent TYPE="NODE"><html>
<head> <head/>
</head>
<body> <body>
<p style="text-align: center"> <p style="text-align: center">
Menu Menu
@ -41827,9 +41809,7 @@
<node CREATED="1670608693763" ID="ID_1403342865" MODIFIED="1670608757928" TEXT="genauere Betrachtung zeigt: hier keine Gefahr"/> <node CREATED="1670608693763" ID="ID_1403342865" MODIFIED="1670608757928" TEXT="genauere Betrachtung zeigt: hier keine Gefahr"/>
<node CREATED="1670608703396" ID="ID_1449271152" MODIFIED="1670960623932" TEXT="Duration wird errechnet und ist daher ggfs. sehr gro&#xdf;, aber nicht giftig"> <node CREATED="1670608703396" ID="ID_1449271152" MODIFIED="1670960623932" TEXT="Duration wird errechnet und ist daher ggfs. sehr gro&#xdf;, aber nicht giftig">
<richcontent TYPE="NOTE"><html> <richcontent TYPE="NOTE"><html>
<head> <head/>
</head>
<body> <body>
<p> <p>
der Nenner ist limitiert (kleiner Time::SCALE) und nicht toxisch der Nenner ist limitiert (kleiner Time::SCALE) und nicht toxisch
@ -42665,9 +42645,7 @@
<icon BUILTIN="ksmiletris"/> <icon BUILTIN="ksmiletris"/>
<node CREATED="1670618176639" ID="ID_393011013" MODIFIED="1670618207065"> <node CREATED="1670618176639" ID="ID_393011013" MODIFIED="1670618207065">
<richcontent TYPE="NODE"><html> <richcontent TYPE="NODE"><html>
<head> <head/>
</head>
<body> <body>
<p> <p>
und die Testsuite ist auf Anhieb <b><font color="#0ba911">GR&#220;N</font></b> und die Testsuite ist auf Anhieb <b><font color="#0ba911">GR&#220;N</font></b>
@ -43340,9 +43318,7 @@
</node> </node>
<node COLOR="#338800" CREATED="1670889821294" ID="ID_842321492" MODIFIED="1670889891273" TEXT="aufgekl&#xe4;rt: war t&#xfc;ckische Falle in der Metrik-Optimierung"> <node COLOR="#338800" CREATED="1670889821294" ID="ID_842321492" MODIFIED="1670889891273" TEXT="aufgekl&#xe4;rt: war t&#xfc;ckische Falle in der Metrik-Optimierung">
<richcontent TYPE="NOTE"><html> <richcontent TYPE="NOTE"><html>
<head> <head/>
</head>
<body> <body>
<p> <p>
...und der ganze Ansatz mit Newton-N&#228;herung stellte sich als unsinnig heraus; jetzt rechnen wir die Optimierung mit einem Schu&#223; in float, und reizen dann sogar noch den Headroom aus, wodurch die Werte viel genauer werden ...und der ganze Ansatz mit Newton-N&#228;herung stellte sich als unsinnig heraus; jetzt rechnen wir die Optimierung mit einem Schu&#223; in float, und reizen dann sogar noch den Headroom aus, wodurch die Werte viel genauer werden
@ -43693,9 +43669,7 @@
<icon BUILTIN="button_ok"/> <icon BUILTIN="button_ok"/>
<node CREATED="1668353519645" ID="ID_1709187608" MODIFIED="1668474384018" TEXT="so exakt wie m&#xf6;glich"> <node CREATED="1668353519645" ID="ID_1709187608" MODIFIED="1668474384018" TEXT="so exakt wie m&#xf6;glich">
<richcontent TYPE="NOTE"><html> <richcontent TYPE="NOTE"><html>
<head> <head/>
</head>
<body> <body>
<p> <p>
da reichen meine Algebra-Kenntnisse nicht aus.... da reichen meine Algebra-Kenntnisse nicht aus....
@ -43933,9 +43907,7 @@
</node> </node>
<node CREATED="1669673828418" ID="ID_1875664128" MODIFIED="1669673980107" TEXT="f&#xfc;r solche F&#xe4;lle w&#xfc;rde sogar die &quot;Bereinigung&quot; selber entgleisen"> <node CREATED="1669673828418" ID="ID_1875664128" MODIFIED="1669673980107" TEXT="f&#xfc;r solche F&#xe4;lle w&#xfc;rde sogar die &quot;Bereinigung&quot; selber entgleisen">
<richcontent TYPE="NOTE"><html> <richcontent TYPE="NOTE"><html>
<head> <head/>
</head>
<body> <body>
<p> <p>
Und zwar, wenn der Nenner viel kleiner ist als der Z&#228;hler, und der Z&#228;hler extrem gro&#223;. Dann w&#252;rde n&#228;mlich die Ganzzahl-Division keine signifikante Verringerung der Dimension bewirken, und die anschlie&#223;ende re-Quantisierung das Ergebnis (bedingt durch die Normierung auf einen gemeinsamen Nenner) sogar noch vergr&#246;&#223;ern Und zwar, wenn der Nenner viel kleiner ist als der Z&#228;hler, und der Z&#228;hler extrem gro&#223;. Dann w&#252;rde n&#228;mlich die Ganzzahl-Division keine signifikante Verringerung der Dimension bewirken, und die anschlie&#223;ende re-Quantisierung das Ergebnis (bedingt durch die Normierung auf einen gemeinsamen Nenner) sogar noch vergr&#246;&#223;ern
@ -53155,6 +53127,45 @@
</node> </node>
<node BACKGROUND_COLOR="#fdfdcf" COLOR="#ff0000" CREATED="1732335516273" ID="ID_77601" MODIFIED="1732335551076" TEXT="Konsequenz: KEINE Aktivit&#xe4;t in einem Konstruktor darf Referenzen binden"> <node BACKGROUND_COLOR="#fdfdcf" COLOR="#ff0000" CREATED="1732335516273" ID="ID_77601" MODIFIED="1732335551076" TEXT="Konsequenz: KEINE Aktivit&#xe4;t in einem Konstruktor darf Referenzen binden">
<icon BUILTIN="flag-pink"/> <icon BUILTIN="flag-pink"/>
<node BACKGROUND_COLOR="#f8f1cb" COLOR="#a50125" CREATED="1732336927298" ID="ID_1133143344" MODIFIED="1732336965422" TEXT="das betrifft auch Weitere, z.B. das Grouping">
<icon BUILTIN="messagebox_warning"/>
</node>
<node CREATED="1732336967005" ID="ID_643449650" MODIFIED="1732337008685">
<richcontent TYPE="NODE"><html>
<head/>
<body>
<p>
ich brauche einen <b>engaged</b>-State
</p>
</body>
</html></richcontent>
<node CREATED="1732337022157" ID="ID_544252009" MODIFIED="1732337084587" TEXT="das k&#xf6;nnte dann weiteres Verschieben sperren"/>
<node CREATED="1732337085316" ID="ID_487485041" MODIFIED="1732337105606" TEXT="zumindest darf Invarianten-Processing erst mit diesem Schirt passieren"/>
<node CREATED="1732372728476" ID="ID_1531001529" MODIFIED="1732373067818" TEXT="&#xe4;rgerlich: bl&#xe4;ht Storage auf und bricht Invarianten"/>
</node>
<node BACKGROUND_COLOR="#c8c0b6" COLOR="#435e98" CREATED="1732377283840" ID="ID_1863518121" MODIFIED="1732378140499" TEXT="versuche Workaround: re-engage">
<icon BUILTIN="help"/>
<icon BUILTIN="idea"/>
<node CREATED="1732377307860" ID="ID_410007394" MODIFIED="1732377339117" TEXT="das Problem besteht einzig im Transformer">
<icon BUILTIN="idea"/>
</node>
<node CREATED="1732377323718" ID="ID_250925762" MODIFIED="1732377333805" TEXT="die Grouper kopieren n&#xe4;mlich per-Value"/>
<node CREATED="1732377340359" ID="ID_1293483567" MODIFIED="1732377393572" TEXT="der Transformer hat schon impliziten &quot;engaged&quot;-State">
<richcontent TYPE="NOTE"><html>
<head/>
<body>
<p>
...er l&#228;&#223;t n&#228;mlich den ItemWrapper zun&#228;chst leer, und verwendet das f&#252;r eine Lazy-invocation der Transformation
</p>
</body>
</html></richcontent>
</node>
<node CREATED="1732377394409" ID="ID_205213439" MODIFIED="1732377416893" TEXT="also w&#xfc;rde es gen&#xfc;gen, da&#xdf; jedes Copy/Move &#x27fc; disengaged"/>
<node CREATED="1732377419435" ID="ID_343740069" LINK="https://stackoverflow.com/a/3279550/444796" MODIFIED="1732377731172" TEXT="Nebenbei: copy-and-swap-Idiom verwenden"/>
<node COLOR="#338800" CREATED="1732378142413" ID="ID_1308227786" MODIFIED="1732378149468" TEXT="best&#xe4;tigt: l&#xf6;st das Problem">
<icon BUILTIN="button_ok"/>
</node>
</node>
</node> </node>
</node> </node>
</node> </node>