diff --git a/src/lib/hetero-data.hpp b/src/lib/hetero-data.hpp index 2e4cb4817..c70cc2f29 100644 --- a/src/lib/hetero-data.hpp +++ b/src/lib/hetero-data.hpp @@ -47,6 +47,8 @@ #include "lib/nocopy.hpp" //#include "lib/linked-elements.hpp" #include "lib/meta/typelist.hpp" +#include "lib/meta/typelist-manip.hpp" +#include "lib/meta/typeseq-util.hpp" //#include //#include @@ -134,7 +136,27 @@ namespace lib { }; template - using Constructor = typename _Tail::template Constructor; + struct Constructor + { + using NewFrame = StorageFrame; + using ChainType = meta::Append,NewFrame>; + + template + NewFrame + operator() (INIT&& ...initArgs) + { + return {initArgs ...}; + } + + template + using ChainConstructor = typename ChainType::template Constructor; + + template + using Accessor = typename ChainType::template Accessor<_Self::size()+slot>; + + template + using AccessorFor = Accessor()>; + }; }; template<> diff --git a/src/lib/meta/typeseq-util.hpp b/src/lib/meta/typeseq-util.hpp index 54f1509c1..0bc97b4ce 100644 --- a/src/lib/meta/typeseq-util.hpp +++ b/src/lib/meta/typeseq-util.hpp @@ -56,6 +56,29 @@ namespace lib { namespace meta { + /** + * Find the index of the first incidence of a type in a type-sequence. + * @note static assertion if the type is not in the type sequence + * @see https://stackoverflow.com/a/60868425/444796 + */ + template + constexpr size_t + indexOfType() + { + static_assert (not sizeof(X), "Type not found in type-sequence"); + return 0; + } + + template + constexpr size_t + indexOfType() + { + if constexpr (std::is_same_v) + return 0; + else + return 1 + indexOfType(); + } + /** * Helper: prepend a type to an existing type sequence, diff --git a/tests/library/meta/typeseq-manip-test.cpp b/tests/library/meta/typeseq-manip-test.cpp index 9286423bd..fd57c20d3 100644 --- a/tests/library/meta/typeseq-manip-test.cpp +++ b/tests/library/meta/typeseq-manip-test.cpp @@ -32,10 +32,9 @@ #include "lib/meta/typeseq-util.hpp" #include "lib/meta/typelist-manip.hpp" #include "meta/typelist-diagnostics.hpp" +#include "lib/format-cout.hpp" using std::string; -using std::cout; -using std::endl; namespace lib { @@ -45,8 +44,6 @@ namespace test { namespace { // test data - - typedef Types< Num<1> , Num<2> , Num<3> @@ -56,7 +53,6 @@ namespace test { , Num<9> > Types2; - // see also the CountDown template in typelist-diagnostics.hpp... } // (End) test data @@ -78,6 +74,7 @@ namespace test { virtual void run (Arg) { + check_indexOf (); check_buildSeq(); check_prepend (); check_shift (); @@ -85,6 +82,17 @@ namespace test { } + void + check_indexOf() + { + CHECK ((0 == indexOfType())); + CHECK ((1 == indexOfType())); + CHECK ((2 == indexOfType())); +// indexOfType(); +// indexOfType(); // does not compile... + } + + void check_buildSeq () { diff --git a/wiki/thinkPad.ichthyo.mm b/wiki/thinkPad.ichthyo.mm index f467d568c..7e9514aae 100644 --- a/wiki/thinkPad.ichthyo.mm +++ b/wiki/thinkPad.ichthyo.mm @@ -21640,9 +21640,7 @@ - - - +

aber dieses Design ist schief @@ -22344,9 +22342,7 @@ - - - +

speziell die Umordnungen ergeben sich @@ -22797,9 +22793,7 @@ - - - +

Thema "Darstellung von Objekt-Feldern im Diff" @@ -23274,9 +23268,7 @@ - - - +

CanvasHook könnte ein konkretes mix-In sein; d.h. zumindest die DisplayMetric wäre zwar als weitere mix-in-Komponente in einem anderen Header definiert (um den Code klar zu halten), aber letztlich bereits auf Interface-Ebene komplett in der Implementierung sichtbar. Die zwei Faktoren der affin-linearen-Transformation wären mutable Variable, die per Setter geändert werden können... @@ -24417,9 +24409,7 @@ - - - +

Warum? Weil wir immer die Hilfe von GTK brauchen, um aus unseren veränderten Vorgaben eine Platz-Allokation zu machen. Und diese Hilfe können wir nicht synchron anfordern, sondern triggern sie indirekt durch setzen neuer Mindestgrößen... @@ -26507,9 +26497,7 @@ - - - +

weil dieses nämlich keine Koordinaten bekommt, und daher nicht weiß, in welchem Canvas das zu entfernde Widget steckt @@ -29943,9 +29931,7 @@ - - - +

...es kommt halt nix Spezifisches aus dem Model, aber es gäbe auch bisher gar keine entsprechenden Diff-Bindings und Model-Properties im GUI @@ -32648,9 +32634,7 @@ - - - +

  box-shadow: inset 0px 0px 0px 1px shade (@theme_bg_color, 1.15), 0px 1px 2px rgba(0, 0, 0, 0.1); } @@ -36887,9 +36871,7 @@ - - - +

...das ist für mich eine neue Einsicht. @@ -38970,9 +38952,7 @@ - - - +

  • @@ -39642,9 +39622,7 @@ - - - +

    ich meine rechts-Klick; typischerweise implementiert man den Handler dafür auf einem Canvas; aber dann ist das Problem: wie findet der Handler das konkrete Widget, und von diesem den Kontext für das pop-Up? @@ -40287,9 +40265,7 @@ - - - +

    denn aufgrund der ersten (ggfs sogar falschen Benachrichtigung) würde das ZoomWindow selber die Parameter glattziehen, was erneute Benachrichtigung zur Folge hätte @@ -40614,9 +40590,7 @@ - - - +

    ...und zwar, wenn man wirklich alle Eingangswerte zuläßt, und sich eben nicht nur auf vernünftige Eingaben verläßt. @@ -40796,9 +40770,7 @@ - - - +

    afterWin_ = startWin_ + Time{dur}; @@ -87854,6 +87826,50 @@ Date:   Thu Apr 20 18:53:17 2023 +0200
    + + + + + + +

    + ...obzwar möglich, kann man nicht sinnvollerweise vom Benutzer verlangen, daß der den Basis-Offset kennt — und obendrein wäre eine solche Angabe dann auch noch verwirrend im Code +

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

    + ...das ist hier im use-case ein wichtiges Sicherheits-Feature ... und auch generell halte ich eine solche get-index-Funktion für gefährlich, wenn sie im Fehlerfall -1 zurückgibt. +

    +

    + Konkret ist das Problem, daß die Fold-Expression von meinem Compiler nicht als constexpr akzeptiert wird (weil man ja über die Fold-Expression einen Index inkrementiert). Möglicherweise würde das dann mit C++20 gehen? +

    + + +
    +
    + + + + + + +
    +
    + + + +
    @@ -87872,8 +87888,7 @@ Date:   Thu Apr 20 18:53:17 2023 +0200
    bei Aufruf wird dann der eigentliche Storage-Frame erzeugt und  registriert

    - - +
    @@ -87905,10 +87920,10 @@ Date:   Thu Apr 20 18:53:17 2023 +0200
    und diese muß nun in einen Vorgänger-Frame geschrieben werden

    - - +
    - + + @@ -87918,6 +87933,242 @@ Date:   Thu Apr 20 18:53:17 2023 +0200
    + + + + + + + + + + + + + + + + +

    + so ein Accessor kann fest auf dem TurnoutSystem eingebaut sein, also getNominalTime(), oder er ist anderweitig kontextuell gegeben und damit ein frei stehendes Accessor-Objekt, das in der Vorbereitungs-Phase von einem HeteroData-Chain generiert wurde +

    + +
    +
    + + + + +

    + ...diese ist ein Funktor, der von gans woanders stammt — nämlich von dem Builder aus dem High-Level-Model gewrappt, z.B. Auswertung einer Bézier-Kurve +

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

    + gestern habe ich mich furchbar geplagt, weil ich fest davon überzeugt war, daß dieses Anhängen im Konstruktor untergebracht werden muß +

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

    + das Anknüpfen könnte man rückwärts gehend einleiten +

    + +
    + + + + + +

    + denn Runtime-Checks sind ausgeschlossen, da wir es uns nicht leisten können, die entsprechenden Metadaten (VTable oder Funktor) in jeder einzelnen Node-Invocation wieder zu speichern; die Info kann aber auch nicht im Aufruf-Typ untergebracht werden, denn dieser ist generisch und für alle Nodes gleich +

    + +
    +
    + + + + + + +

    + denn dieser erstellt einerseits den lokalen Daten-Record, andererseits greift man von diesem auch die Accessoren ab +

    + +
    +
    + + + + + +

    + eben weil wir im HeteroData-Chain selber (also dem TurnoutSystem) keine Metadaten unterbringen wollen +

    + +
    +
    + + + + +

    + ...dieser Check würde prüfen, ob wir nach einer vorkonfigurierten Anzahl an Schritten exakt hinter dem Ende des aktuellen Chain stehen — denn genau dann kann ein damit konform konstruierter Accessor keinen Schaden mehr anrichten: der lokale Tupel-Typ steckt ja im Kontext des Konstruktors, und wurde deshalb soeben zum Anlegen des konkreten Datentupels verwendet; solange die Vorgänger-Chain in der Länge paßt, ist es im Grunde egal, was da sonst noch für Datenwerte liegen, so lange wir nur grade am Ende der Vorgänger-Chain auf den Pointer zu unserem neu erzeugten Datenwert landen +

    + +
    +
    + + + + +

    + Konsequenz: die Funktion, die an den Chain anhängt, muß die Längen-Info haben +

    + + +
    +
    + + + + + + +

    + insofern ist es ja schon attraktiv, mit dem Konstruktor-Funktor zu »zaubern« +

    + + +
    +
    + + + + + + +

    + und könnt nur genau in einer einzigen Weise (und ein einziges Mal!) +

    +

    + an einen Chain der richtigen Länge angehängt werden +

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

    + Daten-Record wird markiert mit Template-Parameter prefixLen +

    + + +
    +
    + + + + + +

    + die kann unmittelbar die Länge prüfen und dann an's Ende gehen und den Pointer dort setzen +

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

    + weil es ja für den gesamten Teilbaum relevant ist +

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