From cedb1830dc4cab80c5e8b637cee2120c71e25e0c Mon Sep 17 00:00:00 2001 From: Ichthyostega Date: Sun, 7 Jul 2024 23:56:10 +0200 Subject: [PATCH] Invocation: work out solution for builder initialisation ...turns out to be surprisingly tricky, since the nested lib::SeveralBuilder instances require parametrisation by a ''policy template,'' which in turn relies on the actual allocator. And we want to provide the allocator as a constructor parameter, including the ability to pick up a custom specialisation for some specific allocator (notably AllocationCluster requires to hook into this kind of extension point, to be able to employ its dedicated API for dynamic allocation adjustment) --- src/lib/several-builder.hpp | 14 ++ src/steam/engine/node-builder.hpp | 56 ++++- wiki/thinkPad.ichthyo.mm | 383 ++++++++++++++++++------------ 3 files changed, 291 insertions(+), 162 deletions(-) diff --git a/src/lib/several-builder.hpp b/src/lib/several-builder.hpp index 65075969f..bf597f679 100644 --- a/src/lib/several-builder.hpp +++ b/src/lib/several-builder.hpp @@ -776,9 +776,21 @@ namespace lib { namespace allo { // Setup for custom allocator policies + /** + * Extension point: how to configure the SeveralBuilder + * to use an allocator \a ALO, initialised by \a ARGS + * @note must define a nested type `Policy`, + * usable as policy mix-in for SeveralBuilder + * @remark the meaning of the template parameter is defined + * by the partial specialisations; notably it is possible + * to give `ALO ≔ std::void_t` and to infer the intended + * allocator type from the initialisation \a ARGS altogether. + * @see allocation-cluster.hpp + */ template class ALO, typename...ARGS> struct SetupSeveral; + /** Specialisation: use a _monostate_ allocator type \a ALO */ template class ALO> struct SetupSeveral { @@ -786,6 +798,8 @@ namespace lib { using Policy = AllocationPolicy; }; + /** Specialisation: store a C++ standard allocator instance, + * which can be used to allocate objects of type \a X */ template class ALO, typename X> struct SetupSeveral> { diff --git a/src/steam/engine/node-builder.hpp b/src/steam/engine/node-builder.hpp index 1f81edc89..f589b6525 100644 --- a/src/steam/engine/node-builder.hpp +++ b/src/steam/engine/node-builder.hpp @@ -88,18 +88,60 @@ namespace steam { namespace engine { using std::move; + using std::forward; /////////////////////////////////////////////////////////////////////////////////////////////////////////////TICKET #1367 : Rebuild the Node Invocation + namespace { + + template class ALO =std::void_t, typename...INIT> + struct AlloPolicySelector + { + template + static auto + setupBuilder (INIT&& ...alloInit) + { + return lib::makeSeveral() + .template withAllocator (forward (alloInit)...); + } + + template + using BuilderType = decltype(setupBuilder (std::declval()...)); + }; + + struct UseHeapAlloc + { + template + static auto + setupBuilder() + { + return lib::makeSeveral(); + } + + template + using BuilderType = lib::SeveralBuilder; + }; + + template + using DataBuilder = typename POL::template BuilderType; + } + template class PortBuilder; - + template class NodeBuilder : util::MoveOnly { - lib::SeveralBuilder ports_; - std::vector leads_; + + using PortData = DataBuilder; + + PortData ports_; + std::vector leads_{}; public: + template + NodeBuilder (INIT&& ...alloInit) + : ports_{POL::template setupBuilder (forward (alloInit)...)} + { } NodeBuilder addLead (ProcNode const& lead) @@ -129,8 +171,9 @@ namespace engine { } }; + template class PortBuilder - : protected NodeBuilder + : protected NodeBuilder , util::MoveOnly { public: @@ -174,8 +217,7 @@ namespace engine { inline auto prepareNode() { - UNIMPLEMENTED("start building a new Render Node at Level-2"); - return NodeBuilder{}; + return NodeBuilder{}; } @@ -231,7 +273,7 @@ namespace engine { retrieve(void* streamType) { UNIMPLEMENTED("start a connectivity definition at Level-3"); - return NodeBuilder{}; + return LinkBuilder{}; ///////////////////////////////////////////////////////////////////OOO this is placeholder code; should at least open a ticket } diff --git a/wiki/thinkPad.ichthyo.mm b/wiki/thinkPad.ichthyo.mm index e5f6bf7e3..47293d759 100644 --- a/wiki/thinkPad.ichthyo.mm +++ b/wiki/thinkPad.ichthyo.mm @@ -227,9 +227,7 @@ - - - +

CoreService hat keine volle Bus-Connection @@ -237,9 +235,7 @@ - - - +

...das hab ich mir jetzt explizit so überlegt und es ist sinnvoll. @@ -270,9 +266,7 @@ - - - +

UI: GuiNotification @@ -283,9 +277,7 @@ - - - +

4/18 inzwischen hier alles geklärt. @@ -1342,9 +1334,7 @@ - - - +

faktisch erfolgt somit ein Callback aus einem anderen Thread @@ -2301,9 +2291,7 @@ - - - +

YAGNI @@ -3488,9 +3476,7 @@ - - - +

aber genau der andere Thread, der das gemacht hat... @@ -5582,9 +5568,7 @@ - - - +

...damit wir nicht der extremen Variabilität für Desktop-Icons unterliegen @@ -7726,9 +7710,7 @@ - - - +

habe diese Analyse 2017/2018 ein Stück weit vorangetrieben. @@ -10693,9 +10675,7 @@ - - - +

...daß man ein Ding komplett in einen Iterator packt, @@ -45651,9 +45631,7 @@ - - - +

...tut sie zwar nicht in dem Beispiel hier, aber mit genügend krimineller Energie ließe sich ein valides Beispiel konstruieren, wobei @@ -45685,9 +45663,7 @@ - - - +

0111 + 0111 = 1110 @@ -45712,9 +45688,7 @@ - - - +

Gefahr besteht... @@ -45748,9 +45722,7 @@ - - - +

206435709205.57568 - 206435709205575697/1e6  = abs(-0,000017) > 1e-6 @@ -45776,9 +45748,7 @@ - - - +

...ich hab doch ohnehin Zeiten, die sind µ-Grid quantisiert; also müßte der Fehler einer einfachen Addition auf µ-Grid genau sein @@ -45793,9 +45763,7 @@ - - - +

...da wir wissen, daß einer der Multiplikatoren eine bereits quantifizierte Zeit ist, können wir von einem Nenner 1e+6 ausgehen (ggfs noch reduziert um einen gekürzten Faktor). Das andere Argument, der Anteil-Faktor, stammt von außen und ist daher beliebig. Der einzige sichere Weg, den Kürzungs-Trick anzuwenden, ist daher, den Kehrwert des Anteil-Faktors zu re-Quantisieren, so daß sich dieses 1e+6 wegkürzt, und wir dann keine gefährliche Multiplikation mehr haben. @@ -45807,9 +45775,7 @@ - - - +

...und damit die rationale Arithmetik als Möglichkeit zu erhalten; sie wäre nicht sinnvoll nutzbar, wenn man ständig die Sorge haben müßte, daß einem die Zahlen »explodieren« können. So ist es nun schon besser, im Regelfall eine hochpräzise Berechnung zu haben (präziser als floating-point), die in Grenzfällen ungenau wird, mit letztlich kontrollierbarem Fehler-Level @@ -45822,9 +45788,7 @@ - - - +

Es fühlt sich gut an, das Problem nun doch befriedigend bezwungen zu haben; ich hatte immer das Bauchgefühl, daß da mehr Genauigkeit möglich sein sollte. Allerdings — wie sich zeigte — nur in günstigen Fällen @@ -45840,9 +45804,7 @@ - - - +

...aber nur nach Maßgabe der tatsächlichen Dimension der eingehenden Zahlen @@ -45853,9 +45815,7 @@ - - - +

Fazit: es ist das gesicherte Minimum @@ -45882,9 +45842,7 @@ - - - +

#--◆--# _raw(targetPos) ?             = 206435633551724864 @@ -45916,9 +45874,7 @@ - - - +

also offensichtlich erkennt boost::rational die Möglichkeit, den gemeinsamen Faktor 1e6 aus Zähler und Nenner wegzukürzen. Da wir aber hier einen FSec-Wert als Offset zugeben, haben wir wenig Möglichkeiten, das zu vergiften @@ -45939,9 +45895,7 @@ - - - +

rein numerisch würde das gehen, da ich Time::MAX | MIN sinnigerweise auf INT_MAX / 30 gesetzt habe. Das war vorausschauend.... @@ -45955,9 +45909,7 @@ - - - +

es untergräbt gradezu den Sinn dedizierter Zeit-Entitäten @@ -45998,9 +45950,7 @@ - - - +

  • @@ -46025,9 +45975,7 @@ - - - +
    • @@ -46049,9 +45997,7 @@ - - - +

      Das versaut den bisher sehr sauberen Code von TimeValue, und läd gradezu dazu ein, hier beliebige Werte zu konstruieren. Im Hinblick darauf, daß ich umgestalten möchte TimeValue ⟶ MicroTicks, würde damit die Daseinsberechtigung untergraben, denn man kann nun nicht mehr sicher sein, daß MicroTicks ein sicherer Wert ist. @@ -46098,9 +46044,7 @@ - - - +

      ...ganz dunkel kommt mir die Erinnerung an eine „kognitive Dissonanz“ — die ich dann schell unter den Teppich gekehrt hatte, indem ich sie mit einem Assert dokumentierte.... @@ -46141,9 +46085,7 @@ - - - +

      und die unterliegende lumiera_time_of_gridpoint weicht da ebenfalls auffällig ab... @@ -46155,9 +46097,7 @@ - - - +

      ....also ein Feature, das zwar auf theoretischer Basis entwickelt wurde, aber nur im testgetriebenen Kontext; hier wohl entstanden aus der implementierungsmäßigen Symmetrie zu Grid::gridPoint(n) @@ -46173,9 +46113,7 @@ - - - +

      TimeValue Quantiser::materialise(TimeValue const& raw) { return timeOf (gridPoint (raw)); } @@ -46185,9 +46123,7 @@ - - - +

      • @@ -46334,9 +46270,7 @@ - - - +

        Ja!!!
        Hat lange gedauert, bis ich da drauf gekommen bin; aber das ist so eindeutig die richtige und angemessene Lösung, daß ich jetzt ausgesprochen erleichtert bin. @@ -46363,9 +46297,7 @@ - - - +

        in Grenzbereichen greift das ZoomWindow ein und begrenzt Ausschläge; selbst wenn der angeschlossene Code direkt die Pixel-Werte verwendet, muß trotzdem auf solche Eingriffe geprüft werden @@ -46453,9 +46385,7 @@ - - - +

        im nächsten Zyklus wird das aber als Head-content gewertet ⟹ body-content wird erhöht @@ -46469,9 +46399,7 @@ - - - +

        damals war ich zufrieden, sobald es „halbwegs“ funktioniert hat @@ -46479,9 +46407,7 @@ - - - +

        • @@ -46518,9 +46444,7 @@ - - - +

          z.B. in (0,1) = Struktur-Graph @@ -46566,9 +46490,7 @@ - - - +

          Zwischenfazit: das Problem wurde erst dadurch sichtbar, daß in der Logik im Track-Head innere Widersprüche bestanden; nach Durchlaufen eines Abstimmungszyklus bestand sofort wieder eine Diskrepanz, und das Layout konnte sich folglich nicht stabilisieren. Dies habe ich inzwischen behoben, insofern nun das TrackHeadWidget grundsätzlich komplett ausformuliert ist, und alle Zuständigkeiten dort klar verteilt sind. Nach Durchlaufen einer Display-Evaluation ergibt sich nun in Summe genau der Wert, der der mit dem TrackBody abgestimmten Höhe entspricht. @@ -46602,9 +46524,7 @@ - - - +

            /** Hooks up an adjustment to focus handling in a container, so when a child @@ -46665,9 +46585,7 @@ - - - +

          0000001086: POSTCONDITION: body-canvas-widget.cpp:512: worker_3: maybeRebuildLayout: (not isnil (profile_)) DisplayEvaluation logic broken @@ -46740,9 +46658,7 @@ - - - +

          adjust (rulerCanvas_, canvasWidth ≔0, rulerHeight ≔11) @@ -46774,9 +46690,7 @@ - - - +

          scrollPos ⟿ zoomWindow geändert, nachdem das Profil aufgebaut wurde @@ -46785,9 +46699,7 @@ - - - +

          ...denn den pixSpan sollte sich ja grade eben nicht ändern, sondern nur der sichtbare Fenster-Ausschnitt; die Implementierung mit dem ZoomWindow zielt ja genau darauf, die Metrik konstant zu halten, selbst wenn sich das sichtbare Fenster (wie hier) ändert @@ -46801,9 +46713,7 @@ - - - +

          und nur das kann man vom Design her einfordern (daß sie sich stabilisiert und nicht in Oszillationen gerät) @@ -82404,16 +82314,13 @@ Date:   Thu Apr 20 18:53:17 2023 +0200
          - - - +

          ...da der Typ des Builders vom Allocator abhängt

          - -
          +
          @@ -87507,9 +87414,59 @@ Date:   Thu Apr 20 18:53:17 2023 +0200
          - + + + + + + + + + +

          + ...den Code eines Builders liest man normalerweise gar nicht im Detail, sobald man verstanden hat, daß es sich um einen Builder / eine DSL handelt; wenn der Builder gut geschrieben ist, kann man direkt die gebaute Datenstruktur erkennen +

          + +
          +
          + + + + + + +

          + wenn das ginge, dann könnte man einfach der Struktur Schritt für Schritt die Felder zuweisen, und dann würde sie irgendwann auf magische Weise »fixiert« im Speicher +

          + +
          +
          + + + + +

          + ...wir bauen hier eine sehr komplexe Struktur, und deshalb sollte vermieden werden, auch noch ein komplexes Protokoll neu zu erfinden +

          + +
          +
          +
          + + + + +

          + ....es geht hier auch um die Allokation, die Daten sollen nachher kompakt liegen und minimal sein; außerdem geht es um das Beherrschen von Komplexität und die Wartbarkeit des Codes; komplex aufeinander abgestimmte Datenstrukturen sollten abgekapselt sein, um ein Verfallen der Architektur durch opportunistische Anpassungen zu verhindern +

          + +
          + + +
          +
          @@ -87518,23 +87475,142 @@ Date:   Thu Apr 20 18:53:17 2023 +0200
          - + - - - + + + - + + - + - - - + + + + + + + + + + + + + + + + + + + + + + + + + +

          + Ansatzpunkt: genau das habe ich für den SeveralBuilder bereits gelöst +

          + +
          + +
          + + + + + + + + + + +

          + warum ist das so schwer verflixt noch einmal!!!!! +

          + +
          + + + +
          + + + + + + + + + +

          + nicht als template-template-Parameter... +

          + + +
          + + + + + +

          + ...denn sonst wird man die ALO, INIT... - Parameter nicht los, sondern sie werden Teil des Builder-Typs (wir wollen aber, daß sie nur implizit in den Builder-Typ eingehen) +

          + + +
          +
          + + + + + + + + +

          + auf das muß sich der Builder abstützen, nicht auf den lib::SeveralBuilder oder dessen Policy +

          + + +
          +
          + + + + + + +

          + ...nicht versuchen, die beiden zu verbinden oder irgendwie durch default-Parameter ausdrücken +

          + + +
          +
          + + + + + + +

          + tja... und jedes nested template braucht ein Präfix "template <fun>" in der Syntax +

          + + +
          +
          +
          +
          @@ -88765,16 +88841,13 @@ Date:   Thu Apr 20 18:53:17 2023 +0200
          - - - +

          alle Werte müssen zuverlässig in die Zieldatenstruktur kopiert  werden

          - -
          +