Library: explore design of a Sum-Type

To represent the result-model for syntax alternatives,
we need a C++ representation for a ''sum type,'' i.e.
a type that can be one from a fixed set of alternatives.
Obviously the implementation will rely on some kind of Union,
or otherwise employ an opaque buffer and perform a forced cast.
Moreover, to be actually usable, a branch-selector-ID must be
captured and stored alongside, so that code processing the results
can detect which branch of the syntax was chosen.

There seem to be several possible avenues to build and structure
an actual class template to provide this implementation model
 * a nested decorator-chain
 * using a recursive selector-function with a generic-λ

''all these look quite unattractive, unfortunately....''
This commit is contained in:
Fischlurch 2025-01-19 23:11:25 +01:00
parent cf91f167dd
commit 3e743ff3b5
3 changed files with 637 additions and 2 deletions

View file

@ -34,6 +34,9 @@
#include <optional>
#include <utility>
#include <cstddef>
#include <tuple>
#include <array>
namespace util {
namespace parse {
@ -46,12 +49,115 @@ namespace util {
using lib::meta::NullType;
using std::decay_t;
using std::tuple;
using std::array;
using StrView = std::string_view;
template<typename...TYPES>
struct _MaxBufSiz;
template<>
struct _MaxBufSiz<>
{
static constexpr size_t siz = 0;
};
template<typename T, typename...TYPES>
struct _MaxBufSiz<T,TYPES...>
{
static constexpr size_t siz = std::max (sizeof(T)
,_MaxBufSiz<TYPES...>::siz);
};
/**
/**
* Data storage base for sum type with selector
*/
template<size_t SIZ>
struct OpaqueSumType
{
size_t case_{0};
alignas(int64_t)
std::byte buffer_[SIZ];
template<size_t slot, typename T, typename...INITS>
T&
emplace (INITS&&...inits)
{
case_ = slot;
return * new(&buffer_) T(forward<INITS> (inits)...);
}
};
template<typename T, typename...TYPES>
class SumType
: private OpaqueSumType<_MaxBufSiz<T,TYPES...>::siz>
{
public:
static constexpr size_t TOP = sizeof...(TYPES);
static constexpr size_t SIZ = _MaxBufSiz<T,TYPES...>::siz;
using _Opaque = OpaqueSumType<SIZ>;
template<typename...INITS, typename = lib::meta::disable_if_self<SumType,INITS...>>
SumType (INITS&& ...inits)
{
_Opaque::template emplace<TOP,T> (forward<INITS> (inits)...);
}
template<typename TX>
TX&
access ()
{
return * std::launder (reinterpret_cast<TX*> (& _Opaque::buffer_[0]));
}
size_t
selected() const
{
return _Opaque::case_;
}
template<size_t slot>
using SlotType = std::tuple_element_t<TOP-slot, tuple<T,TYPES...>>;
template<size_t slot>
SlotType<slot>&
get()
{
return access<SlotType<slot>>();
}
template<typename TX, typename...TS, class FUN>
void
select (size_t slot, FUN&& fun)
{
REQUIRE (slot <= sizeof...(TS));
if constexpr (sizeof...(TS))
if (0 < slot)
select<TS...> (slot-1, forward<FUN>(fun));
fun (access<TX>());
}
template<typename TX>
void
destroyIt (TX& it)
{
it.~TX();
}
void
destroy (size_t slot)
{
select<T,TYPES...> (slot, [&](auto& it){ destroyIt(it); });
}
~SumType()
{
destroy (_Opaque::case_);
}
};
/**
*/
template<class RES>
struct Eval

View file

@ -77,6 +77,7 @@ namespace test {
simpleBlah();
acceptTerminal();
acceptSequential();
acceptAlternatives();
}
@ -209,6 +210,22 @@ namespace test {
CHECK (get<1>(seqModel2).str() == "world"_expect);
CHECK (get<2>(seqModel2).str() == "trade"_expect);
}
/** @test TODO define alternative syntax structures to match by parse. */
void
acceptAlternatives()
{
using Sum = SumType<ushort,char>;
SHOW_EXPR(sizeof(Sum));
Sum sumt{42};
SHOW_EXPR(sumt.selected());
SHOW_EXPR(sumt.SIZ);
SHOW_EXPR(sumt.TOP);
SHOW_TYPE(Sum::_Opaque)
SHOW_EXPR(sumt.get<1>());
SHOW_EXPR(sumt.get<0>());
}
};
LAUNCHER (Parse_test, "unit common");

View file

@ -56028,6 +56028,439 @@
</node>
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1737234396680" ID="ID_679636766" MODIFIED="1737235494542" TEXT="Alternativ-Kombinator bauen">
<icon BUILTIN="flag-yellow"/>
<node CREATED="1737235517170" ID="ID_1134480788" MODIFIED="1737235532164" TEXT="mu&#xdf; hier zuerst die Model-Mechanik entwickeln">
<node CREATED="1737235560972" ID="ID_968357989" MODIFIED="1737235564743" TEXT="Datenstruktur">
<node CREATED="1737235591344" ID="ID_96667610" MODIFIED="1737235611568" TEXT="Selektor-Feld mit Index des Falls"/>
<node CREATED="1737235565816" ID="ID_1766417786" MODIFIED="1737235627609" TEXT="gemeinsamer Variant-Pufferspeicher"/>
</node>
<node CREATED="1737235932248" ID="ID_1238923815" MODIFIED="1737235937489" TEXT="Zugangs-Modalit&#xe4;ten">
<node CREATED="1737237023488" ID="ID_766985943" MODIFIED="1737237039860" TEXT="die Einzel-Parser liegen verschachtelt-kaskadiert (wie bei Seq)"/>
<node CREATED="1737237044029" ID="ID_1564431909" MODIFIED="1737237068027" TEXT="das hei&#xdf;t im Kombinator wird jeweils ein neuer Gesamt-Model-Typ gebaut"/>
<node CREATED="1737237073242" ID="ID_1612955803" MODIFIED="1737237086796" TEXT="aber bei der Auswertung wird jeder Zweig einzeln gepr&#xfc;ft"/>
<node CREATED="1737237096366" ID="ID_1232165406" MODIFIED="1737237120960" TEXT="wenn ein Zweig zuschl&#xe4;gt, wird in dem partiellen Modell geliefert"/>
<node CREATED="1737237121907" ID="ID_36243187" MODIFIED="1737237243847" TEXT="jedoch nachfolgende Closures packen das noch x-fach um"/>
<node CREATED="1737237288477" ID="ID_401200983" MODIFIED="1737237300351" TEXT="dabei mu&#xdf; jeweils explizit getypt und dann umkopiert werden"/>
<node CREATED="1737237333495" ID="ID_1790838073" MODIFIED="1737237368558" TEXT="sp&#xe4;terer Zugriff auf die Model-Daten ebenfalls gesteuert per Selektor (runtime-value)"/>
</node>
<node CREATED="1737237437320" ID="ID_201367357" MODIFIED="1737237446604" TEXT="Konsequenzen f&#xfc;r den konkreten Zugang">
<node CREATED="1737237447951" ID="ID_364316654" MODIFIED="1737237468914" TEXT="erstmals wird das Model-Objekt in statisch typisierter Umgebung angelegt"/>
<node CREATED="1737237474908" ID="ID_518030485" MODIFIED="1737237514170" TEXT="dann erfolgt x-mal eine Kopie in einem per Selektor gew&#xe4;hlten Typkontext"/>
<node CREATED="1737237515422" ID="ID_1038704552" MODIFIED="1737237604198" TEXT="Datenzugriff per Dispatch von Selektor &#x27f6; statisch vorbereiteter Zweig"/>
</node>
<node CREATED="1737237726182" ID="ID_1444850716" MODIFIED="1737237738971" TEXT="&#x27f9; ben&#xf6;tigte Funktionalit&#xe4;t">
<node CREATED="1737237744920" ID="ID_269847251" MODIFIED="1737237787453" TEXT="Konstruktion: statisch auf den (derzeit) h&#xf6;chsten Selector-Platz"/>
<node CREATED="1737237808373" ID="ID_291088107" MODIFIED="1737237829928" TEXT="Zugriff: statisch gegebener Selector &#x27f6; typisierter Getter">
<node CREATED="1737237881741" ID="ID_183722240" MODIFIED="1737237886889" TEXT="analog wie get&lt;i&gt;(tuple)"/>
<node CREATED="1737237896668" ID="ID_286879176" MODIFIED="1737237910693" TEXT="Metafunktion i &#x27fc; Typ"/>
</node>
<node CREATED="1737238022259" ID="ID_508598643" MODIFIED="1737238026071" TEXT="up-Copy">
<node CREATED="1737238037257" ID="ID_1788967087" MODIFIED="1737238050739" TEXT="gegeben: AltModel&lt;N&gt;"/>
<node CREATED="1737238051966" ID="ID_384770143" MODIFIED="1737238076015" TEXT="zu bauen: AltModel&lt;N+1&gt; mit kopierten Daten und gleichem Selektor"/>
<node BACKGROUND_COLOR="#f8f1cb" COLOR="#a50125" CREATED="1737238094329" ID="ID_1160578555" MODIFIED="1737238106552" TEXT="braucht Trampolin f&#xfc;r konkrete Kopie">
<icon BUILTIN="messagebox_warning"/>
<node CREATED="1737238147756" ID="ID_1597388632" MODIFIED="1737238159884" TEXT="statisches Array von Funktionspointern"/>
<node CREATED="1737238206786" ID="ID_784811" MODIFIED="1737238220532" TEXT="generische Signatur void(void*,void*)"/>
<node BACKGROUND_COLOR="#fafe99" COLOR="#fa002a" CREATED="1737238386277" ID="ID_499140874" MODIFIED="1737238392082" TEXT="ineffizient">
<icon BUILTIN="broken-line"/>
<node CREATED="1737238394241" ID="ID_1786923431" MODIFIED="1737238413594" TEXT="entweder haben wir N Teil-Arrays (Speicherverschwendung)"/>
<node CREATED="1737238414398" ID="ID_1897860224" MODIFIED="1737238431951" TEXT="oder eine verkettete Liste von Closures (Laufzeitverschwendung)"/>
<node CREATED="1737238441426" ID="ID_896531017" MODIFIED="1737238466027" TEXT="und im schlimmsten Fall auch noch N consecutive copies"/>
</node>
</node>
<node BACKGROUND_COLOR="#fdfdcf" COLOR="#ff0000" CREATED="1737238578224" ID="ID_524632421" MODIFIED="1737238587563" TEXT="zu optimieren">
<icon BUILTIN="yes"/>
<node CREATED="1737238589671" ID="ID_1560551329" MODIFIED="1737238601745" TEXT="Idee: Model-Binding in zwei Schritten">
<icon BUILTIN="idea"/>
<node CREATED="1737238606619" ID="ID_1441095840" MODIFIED="1737238917781" TEXT="Teilergebnis + Selektor-Nr durchreichen">
<icon BUILTIN="full-1"/>
<node COLOR="#7846cd" CREATED="1737238827103" ID="ID_1680666125" MODIFIED="1737238877294" TEXT="die eigentliche Parser / Combinator-Auswertung">
<edge COLOR="#68278e" STYLE="sharp_linear"/>
<font NAME="SansSerif" SIZE="11"/>
</node>
</node>
<node CREATED="1737238735939" ID="ID_416803037" MODIFIED="1737238920165" TEXT="in bekanntes Gesamt-Model packen">
<icon BUILTIN="full-2"/>
<node COLOR="#7846cd" CREATED="1737238827103" HGAP="46" ID="ID_277584959" MODIFIED="1737238902426" TEXT="nachgeschalteter Model-Binding-Funktor" VSHIFT="6">
<edge COLOR="#68278e" STYLE="sharp_linear"/>
<font NAME="SansSerif" SIZE="11"/>
</node>
</node>
</node>
<node BACKGROUND_COLOR="#f8f1cb" COLOR="#a50125" CREATED="1737242122676" ID="ID_486125380" MODIFIED="1737242129558" TEXT="es ist nicht so einfach">
<icon BUILTIN="messagebox_warning"/>
<node CREATED="1737242181419" ID="ID_699910063" MODIFIED="1737242197252" TEXT="wir geben nun mal &#xfc;ber eine Kette verschachtelter Funktoren zur&#xfc;ck"/>
<node CREATED="1737242567334" ID="ID_1304062723" MODIFIED="1737242586617" TEXT="sobald der erzeugende Scope verlassen wird, ist nur noch ein Summen-Typ bekannt"/>
<node CREATED="1737242938262" ID="ID_1738913829" MODIFIED="1737242950460" TEXT="eine Copy-Closure zur Laufzeit ist unvermeidbar"/>
</node>
<node CREATED="1737243098806" ID="ID_1092129067" MODIFIED="1737243108146" TEXT="L&#xf6;sungsansatz">
<icon BUILTIN="forward"/>
<node CREATED="1737243124771" ID="ID_910400455" MODIFIED="1737243147396" TEXT="Storage-Basis verwenden: OpaqueSumType&lt;N&gt;">
<node CREATED="1737244503400" ID="ID_723769272" MODIFIED="1737244531600" TEXT="diese haben alle ein gleiches Layout-Schema"/>
<node CREATED="1737244533204" ID="ID_756232566" MODIFIED="1737244548918" TEXT="&#x27f9; k&#xf6;nnen alle untereinander cross-konstruierbar gemacht werden"/>
</node>
<node CREATED="1737243160901" ID="ID_1731989691" MODIFIED="1737243170418" TEXT="vereinfachende Annahmen">
<node CREATED="1737243171525" ID="ID_72118794" MODIFIED="1737243389913" TEXT="es sind nur wenige Zweige &#x27f9; repetitives Kopieren egal">
<richcontent TYPE="NOTE"><html>
<head>
</head>
<body>
<p>
bei der Sequenz wurde die gleiche Annahme gemacht, und da&#223; der Optimiser das schon wuppen wird
</p>
</body>
</html>
</richcontent>
</node>
<node CREATED="1737243197654" ID="ID_1244482607" MODIFIED="1737243363548" TEXT="wir kopieren grunds&#xe4;tzlich in einen gr&#xf6;&#xdf;eren Buffer &#x27f9; kein Check-and-Branch notwendig">
<richcontent TYPE="NOTE"><html>
<head>
</head>
<body>
<p>
warum? weil eine Folge zunehmend variantenreicherer Summen-Typen entsteht, und die Puffergr&#246;&#223;e ist das Maximum des ben&#246;tigten Platzes
</p>
</body>
</html>
</richcontent>
</node>
</node>
<node BACKGROUND_COLOR="#f0d5c5" COLOR="#990033" CREATED="1737244421643" ID="ID_1284583110" MODIFIED="1737245500026" TEXT="intermedi&#xe4;rer Ergebnis-Typ: BranchResultClosure">
<icon BUILTIN="help"/>
<node CREATED="1737245502249" ID="ID_1174923923" MODIFIED="1737245508829" TEXT="noch nicht klar ob notwendig">
<node CREATED="1737308551745" ID="ID_1909384704" MODIFIED="1737308569043" TEXT="denn Closure &#x2259; dynamischer Dispatch"/>
<node CREATED="1737308586765" ID="ID_1360651233" MODIFIED="1737308606555" TEXT="die ganze sonstiger &#xbb;Parser-Code-Insel&#xab; ist rein-statitsch typisiert"/>
<node CREATED="1737308671866" ID="ID_1034537096" MODIFIED="1737308702736" TEXT="Zahl der Branches klein &#x27f9; statische Impl im Vorteil"/>
</node>
<node CREATED="1737245511448" ID="ID_396620339" MODIFIED="1737245792925" TEXT="Alternativ: R&#xfc;ck&#xfc;bersetzung Selector &#x27fc; Typ-Kontext durch rekursive Funktionen">
<richcontent TYPE="NOTE"><html>
<head>
</head>
<body>
<p>
das ist &#228;hnlich zu einer <i>persistenten Datenstruktur:</i>&#160;man fragt den jeweiligen Vorg&#228;nger-Datentyp mit dem dekrementierten Selektor an; ist der Selektor 0, wird der dort fest gecodete Typ-Zugriff verwendet
</p>
</body>
</html>
</richcontent>
</node>
</node>
</node>
</node>
</node>
</node>
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1737245801576" ID="ID_1738176168" MODIFIED="1737245808157" TEXT="Skizze Datentyp">
<icon BUILTIN="flag-yellow"/>
<node CREATED="1737308328478" ID="ID_993665414" MODIFIED="1737308352116" TEXT="erst mal einen uninitialised byte-Puffer in Basisklasse"/>
<node CREATED="1737308370978" ID="ID_1202779435" MODIFIED="1737308383699" TEXT="typisierter Summentyp dar&#xfc;bergelegt"/>
<node CREATED="1737308384535" ID="ID_1448196900" MODIFIED="1737308394626" TEXT="Anordnung der Typ-Parameter: R&#xfc;ckw&#xe4;rts gehend">
<node CREATED="1737308397038" ID="ID_977244135" MODIFIED="1737308410928" TEXT="also der letzte / h&#xf6;chste Zweig zuerst"/>
<node CREATED="1737308411588" ID="ID_1539400054" MODIFIED="1737308423294" TEXT="damit rekursiv-delegierende Implementierung m&#xf6;glich"/>
</node>
<node CREATED="1737309034680" ID="ID_1283731567" MODIFIED="1737309052170" TEXT="Code-Struktur &#xfc;berlegen">
<node CREATED="1737309053966" ID="ID_1359722232" MODIFIED="1737309190105" TEXT="Destuktor aufrufen ?">
<node BACKGROUND_COLOR="#fefc4e" COLOR="#351d75" CREATED="1737309093248" ID="ID_321904108" MODIFIED="1737309152195" TEXT="&#xd83e;&#xdc46; Invariante: stets ein Zweig belegt">
<font BOLD="true" NAME="SansSerif" SIZE="12"/>
</node>
<node CREATED="1737309159423" ID="ID_483153602" MODIFIED="1737309168193" TEXT="&#x27f9; mu&#xdf; RAII sein"/>
</node>
<node CREATED="1737309211412" ID="ID_150276417" MODIFIED="1737309241998" TEXT="Opaque-Buffer als Basis ist nicht eigenst&#xe4;ndig">
<node CREATED="1737309245044" ID="ID_1229816718" MODIFIED="1737309255638" TEXT="er m&#xfc;&#xdf;te n&#xe4;mlich den Typ im Buffer kennen"/>
<node CREATED="1737309258330" ID="ID_414435446" MODIFIED="1737309277292" TEXT="sonst ist es mehr wie eine Member-Komponente"/>
</node>
<node CREATED="1737309306808" ID="ID_1247810717" MODIFIED="1737309311710" TEXT="zwei Alternativen...">
<node CREATED="1737309312755" ID="ID_1765693019" MODIFIED="1737323819640" TEXT="inkrementeller Dekorator">
<icon BUILTIN="full-1"/>
<node CREATED="1737309344095" ID="ID_1218238487" MODIFIED="1737309351610" TEXT="Buffer ist tats&#xe4;chlich Basis"/>
<node CREATED="1737309352558" ID="ID_852458357" MODIFIED="1737309371391" TEXT="Sequenz von Summen-Typen &#xfc;bereinander geschichtet"/>
<node CREATED="1737309372075" ID="ID_20092425" MODIFIED="1737309385022" TEXT="parent-Delegation f&#xfc;r alle Selektor-Zugriffe"/>
<node CREATED="1737309428107" ID="ID_1180369791" MODIFIED="1737309503361" TEXT="operiert wird stets nur auf dem Head-Typ">
<richcontent TYPE="NOTE"><html>
<head>
</head>
<body>
<p>
das hei&#223;t, die Operationen f&#252;hrt stets derjenige partielle Summen-Typ aus, bei dem der aktive Zweig auf der Top-Position (am Anfang) steht; der aktuelle Selektor-Wert legt also das &#187;Stockwerk&#171; fest, auf dem gearbeitet wird
</p>
</body>
</html>
</richcontent>
</node>
</node>
<node CREATED="1737309505461" ID="ID_1831957279" MODIFIED="1737323816537" TEXT="ein Objekt mit Typ-Projektion">
<icon BUILTIN="full-2"/>
<node CREATED="1737309866960" ID="ID_1933240925" MODIFIED="1737309878323" TEXT="es gibt nur ein Objekt, das den Buffer direkt (private) h&#xe4;lt"/>
<node CREATED="1737309879188" ID="ID_1269779979" MODIFIED="1737309905040" TEXT="f&#xfc;r jeden Aufruf wird rekursiv eine Typ-Projektion dar&#xfc;bergelegt f&#xfc;r die Zugriffe"/>
<node BACKGROUND_COLOR="#eef0c5" COLOR="#990000" CREATED="1737309983889" ID="ID_217989124" MODIFIED="1737309993912" TEXT="Machbarkeit nicht klar &#x27f9; Prototyping">
<icon BUILTIN="pencil"/>
<node CREATED="1737309995672" ID="ID_317094642" MODIFIED="1737310007874" TEXT="brauche rekursiv getypte Hilfsfunktionen">
<node CREATED="1737310409584" ID="ID_1587656830" MODIFIED="1737310412828" TEXT="emplace"/>
<node CREATED="1737310413472" ID="ID_190878994" MODIFIED="1737310416083" TEXT="destroy"/>
<node CREATED="1737310416903" ID="ID_1254677447" MODIFIED="1737310419299" TEXT="access"/>
</node>
<node CREATED="1737310430861" ID="ID_1290238201" MODIFIED="1737310442847" TEXT="jede dieser mu&#xdf; mit einem Laufzeit-Selektor arbeiten k&#xf6;nnen"/>
<node CREATED="1737313328618" ID="ID_233931368" MODIFIED="1737313650810" TEXT="mu&#xdf; eine statisch stets greifende Abbruchbedingung haben">
<richcontent TYPE="NOTE"><html>
<head>
</head>
<body>
<p>
...weil der Compiler ja nichts &#252;ber den Selektor-Wert wei&#223;, mu&#223; er in jedem Fall die gesamte rekursive Kette instantiieren; das Ende der Typ-Sequenz stellt also eine zweite Abbruchbedinung der Rekursion bereit, und diese mu&#223; so in die Kontrollstruktur eingebunden sein, da&#223; die rekursiven Instantiierungen wirklich aufh&#246;ren
</p>
</body>
</html>
</richcontent>
<linktarget COLOR="#da0053" DESTINATION="ID_233931368" ENDARROW="Default" ENDINCLINATION="-3;35;" ID="Arrow_ID_30602748" SOURCE="ID_630615529" STARTARROW="None" STARTINCLINATION="18;-29;"/>
</node>
<node CREATED="1737313501332" ID="ID_445073584" MODIFIED="1737313526988" TEXT="dann k&#xf6;nnte man eine generische select(&#x3bb;)-Funktion schreiben">
<node CREATED="1737313532583" ID="ID_551947957" MODIFIED="1737313549006" TEXT="diese w&#xfc;rde ein generisches Lambda anwenden"/>
<node CREATED="1737313550228" ID="ID_1449505888" MODIFIED="1737313565790" TEXT="und zwar auf den jeweiligen Slot"/>
<node CREATED="1737313587192" ID="ID_1083828956" MODIFIED="1737313594083" TEXT="alle anderen Funktionen bauen darauf auf"/>
</node>
<node CREATED="1737313611808" ID="ID_630615529" MODIFIED="1737313650810" TEXT="Knackpunkt ist die Abbruchbedingung">
<arrowlink COLOR="#da0053" DESTINATION="ID_233931368" ENDARROW="Default" ENDINCLINATION="-3;35;" ID="Arrow_ID_30602748" STARTARROW="None" STARTINCLINATION="18;-29;"/>
<node COLOR="#435e98" CREATED="1737315575847" ID="ID_282722668" MODIFIED="1737323740177" TEXT="auf Realisierbarkeit zu pr&#xfc;fen....">
<icon BUILTIN="yes"/>
</node>
<node COLOR="#338800" CREATED="1737315599659" ID="ID_708076944" MODIFIED="1737315613568" TEXT="syntaktisch als member-Funktion formulierbar">
<icon BUILTIN="button_ok"/>
</node>
<node COLOR="#338800" CREATED="1737315615296" ID="ID_114262607" MODIFIED="1737323424452" TEXT="im konkreten Fall mit generischem Lambda aufrufbar">
<icon BUILTIN="button_ok"/>
</node>
<node BACKGROUND_COLOR="#e0ceaa" COLOR="#690f14" CREATED="1737323429607" ID="ID_682744286" MODIFIED="1737323473741" TEXT="sehr spezielle Formulierung notwendig">
<arrowlink COLOR="#fefdc5" DESTINATION="ID_1252837255" ENDARROW="Default" ENDINCLINATION="-21;-80;" ID="Arrow_ID_1920999900" STARTARROW="None" STARTINCLINATION="208;15;"/>
<icon BUILTIN="messagebox_warning"/>
</node>
</node>
<node COLOR="#435e98" CREATED="1737323750132" ID="ID_1119046705" MODIFIED="1737323785033">
<richcontent TYPE="NODE"><html>
<head>
</head>
<body>
<p>
<b>Fazit</b>: mit Einschr&#228;nkumg umsetzbar...
</p>
</body>
</html>
</richcontent>
<icon BUILTIN="forward"/>
</node>
<node BACKGROUND_COLOR="#f8f1cb" COLOR="#a50125" CREATED="1737317456624" ID="ID_846126551" MODIFIED="1737317483349" TEXT="grunds&#xe4;tzliches Problem: Variant-Returntype nicht m&#xf6;glich">
<icon BUILTIN="messagebox_warning"/>
<node COLOR="#5b280f" CREATED="1737317489124" ID="ID_233312745" MODIFIED="1737317528208" TEXT="Funktion kann keinen vom Parameter abh&#xe4;ngigen R&#xfc;ckgabetyp haben">
<icon BUILTIN="closed"/>
</node>
<node BACKGROUND_COLOR="#fafe99" COLOR="#fa002a" CREATED="1737317639568" ID="ID_526309958" MODIFIED="1737317717888" TEXT="diese Einschr&#xe4;nkung betrifft jedes Konstrukt f&#xfc;r einen Summen-Typ (in C++)">
<arrowlink COLOR="#d2005b" DESTINATION="ID_1314826159" ENDARROW="Default" ENDINCLINATION="58;-95;" ID="Arrow_ID_1280018433" STARTARROW="None" STARTINCLINATION="-542;20;"/>
<icon BUILTIN="clanbomber"/>
</node>
</node>
</node>
</node>
<node CREATED="1737323796942" ID="ID_1671873045" MODIFIED="1737323808699" TEXT="Diskussion">
<icon BUILTIN="yes"/>
<node CREATED="1737323821990" ID="ID_1562513052" MODIFIED="1737323951827" TEXT="die Variante-2 erschien mir zun&#xe4;chst attraktiver">
<richcontent TYPE="NOTE"><html>
<head>
</head>
<body>
<p>
Und zwar im Bezug auf allgemeine Handwerksregeln...
</p>
<ul>
<li>
man k&#246;nnte ohne Basisklasse auskommen
</li>
<li>
der opaque-Bufer w&#228;re als Implementierungsdetail direkt im private-Scope
</li>
<li>
es wird nur eine einzige Klasse (pro Typ-Signatur) tats&#228;chlich instantiiert
</li>
</ul>
</body>
</html>
</richcontent>
</node>
<node CREATED="1737323954705" ID="ID_277050708" MODIFIED="1737324325847" TEXT="tats&#xe4;chlich wird das aber durchaus h&#xe4;sslich...">
<richcontent TYPE="NOTE"><html>
<head>
</head>
<body>
<p>
Das f&#228;ngt schon damit an, da&#223; man doch noch getemplatete Funktionen f&#252;r die Elementar-Operationen schreiben mu&#223; (zumindest in C++17). Dazu kommt dann diese doch einigerma&#223;en trickreiche generische select-Operation
</p>
</body>
</html>
</richcontent>
</node>
</node>
</node>
<node BACKGROUND_COLOR="#f8f1cb" COLOR="#a50125" CREATED="1737317603366" ID="ID_1314826159" MODIFIED="1737317708664" TEXT="grunds&#xe4;tzliche Einschr&#xe4;nkung: Zugriff erfordert statisch bekannten Typ">
<linktarget COLOR="#d2005b" DESTINATION="ID_1314826159" ENDARROW="Default" ENDINCLINATION="58;-95;" ID="Arrow_ID_1280018433" SOURCE="ID_526309958" STARTARROW="None" STARTINCLINATION="-542;20;"/>
<icon BUILTIN="messagebox_warning"/>
<node CREATED="1737317726468" ID="ID_1400201299" MODIFIED="1737317872607" TEXT="jeder &#xbb;Varant&#xab;-Type (und auch Union) unterliegt dieser Einschr&#xe4;nkung"/>
<node CREATED="1737317755916" ID="ID_272257779" MODIFIED="1737317775825" TEXT="einziger Ausweg ist double-Dispatch (ein Variant-Visitor)"/>
<node CREATED="1737317782298" ID="ID_1880951449" MODIFIED="1737318163297">
<richcontent TYPE="NODE"><html>
<head>
</head>
<body>
<p>
konkret stellt das <i>zuf&#228;lligerweise</i>&#160;kein Problem dar
</p>
</body>
</html>
</richcontent>
<node CREATED="1737317782298" ID="ID_530599192" MODIFIED="1737320455593" TEXT="ist tats&#xe4;chlich kein Zufall">
<richcontent TYPE="NOTE"><html>
<head>
</head>
<body>
<p>
das erscheint zun&#228;chst wie &#187;gl&#252;ckliche Umst&#228;nde&#171;;
</p>
<p>
bei genauerer &#220;berlegung wird aber klar, da&#223; ich diese Einsicht bereits intuitiv angewendet hatte, als ich von Vornherein auch ein Selektor-Feld mit disponierte; es ist n&#228;mlich so, da&#223; wir uns verm&#246;ge des Selektor-Feldes <i>genau diese explizite Info zur Compile-Zeit beschaffen </i>k&#246;nnen, indem der aufrufende Code ein switch-case auf den Selector macht.
</p>
</body>
</html>
</richcontent>
</node>
<node CREATED="1737318234275" ID="ID_812162501" MODIFIED="1737318327026">
<richcontent TYPE="NODE"><html>
<head>
</head>
<body>
<p>
das im Prototyp entworfene select(&#955;) ist ein <b>Variant-Visitor</b>
</p>
</body>
</html>
</richcontent>
<icon BUILTIN="idea"/>
</node>
<node CREATED="1737318376446" ID="ID_779074690" MODIFIED="1737320326450" TEXT="und zwar mit statischem Dispatch &#x27f9; neuer Beitrag zur Visitor-Diskussion">
<arrowlink COLOR="#777dc0" DESTINATION="ID_84646881" ENDARROW="Default" ENDINCLINATION="-1890;189;" ID="Arrow_ID_190224326" STARTARROW="None" STARTINCLINATION="-3213;124;"/>
<node CREATED="1737323034903" ID="ID_1252837255" MODIFIED="1737323468357" STYLE="bubble">
<richcontent TYPE="NODE"><html>
<head>
</head>
<body>
<p>
<font face="Monospaced" size="2">template&lt;typename </font><font color="#a30303" face="Monospaced" size="2"><u>TX</u></font><font face="Monospaced" size="2">, typename...</font><font color="#a30303" face="Monospaced" size="2"><u>TS</u></font><font face="Monospaced" size="2">, class </font><font color="#a30303" face="Monospaced" size="2"><u>FUN</u></font><font face="Monospaced" size="2">&gt; </font>
</p>
<p>
<font face="Monospaced" size="2">void </font>
</p>
<p>
<font face="Monospaced" size="2"><b>select</b>&#160;(size_t </font><font color="#230dda" face="Monospaced" size="2">slot</font><font face="Monospaced" size="2">, </font><font color="#a30303" face="Monospaced" size="2"><u>FUN</u></font><font face="Monospaced" size="2">&amp;&amp; fun) </font>
</p>
<p>
<font face="Monospaced" size="2">&#160;&#160;{ </font>
</p>
<p>
<font face="Monospaced" size="2">&#160;&#160;&#160;&#160;REQUIRE (slot &lt;= sizeof...(</font><font color="#a30303" face="Monospaced" size="2"><u>TS</u></font><font face="Monospaced" size="2">)); </font>
</p>
<p>
<font face="Monospaced" size="2">&#160;&#160;&#160;&#160;if constexpr (sizeof...(</font><font color="#a30303" face="Monospaced" size="2"><u>TS</u></font><font face="Monospaced" size="2">)) </font>
</p>
<p>
<font face="Monospaced" size="2">&#160;&#160;&#160;&#160;&#160;&#160;if (0 &lt; </font><font color="#230dda" face="Monospaced" size="2">slot</font><font face="Monospaced" size="2">) </font>
</p>
<p>
<font face="Monospaced" size="2">&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;<b>select</b>&lt;</font><font color="#a30303" face="Monospaced" size="2"><u>TS</u></font><font face="Monospaced" size="2">..&gt; (</font><font color="#230dda" face="Monospaced" size="2">slot</font><font face="Monospaced" size="2">-1, forward&lt;</font><font color="#a30303" face="Monospaced" size="2"><u>FUN</u></font><font face="Monospaced" size="2">&gt;(fun)); </font>
</p>
<p>
<font face="Monospaced" size="2">&#160;&#160;&#160;&#160;fun (<b>access</b>&lt;</font><font color="#a30303" face="Monospaced" size="2"><u>TX</u></font><font face="Monospaced" size="2">&gt;()); </font>
</p>
<p>
<font face="Monospaced" size="2">&#160;&#160;} </font>
</p>
</body>
</html>
</richcontent>
<linktarget COLOR="#fefdc5" DESTINATION="ID_1252837255" ENDARROW="Default" ENDINCLINATION="-21;-80;" ID="Arrow_ID_1920999900" SOURCE="ID_682744286" STARTARROW="None" STARTINCLINATION="208;15;"/>
<node CREATED="1737323483195" HGAP="35" ID="ID_824149036" MODIFIED="1737323703635" STYLE="fork" TEXT="subtile Details...." VSHIFT="-7">
<richcontent TYPE="NOTE"><html>
<head>
</head>
<body>
<p>
Das funktioniert nur wenn man einige subtile Details richtig hinbekommt....
</p>
<ul>
<li>
die Abbruchbedingung mu&#223; f&#252;r den Compiler sichtbar sein, daher als constexpr-if zu formulieren
</li>
<li>
der Funktor oder das Lambda mu&#223; wirklich per offenem Template-Argument &#252;bergeben werden, weil es tats&#228;chlich selber ein Template sein mu&#223; (generische Lambda bieten hierf&#252;r eine abgek&#252;rzte Schreibweise)
</li>
<li>
der Zugriff ist trotzdem <b>komplett ungesch&#252;tzt</b>
</li>
<li>
man mu&#223; also anderweitig daf&#252;r sorgen, da&#223; die slot-# tats&#228;chlich korrekt belegt ist
</li>
</ul>
</body>
</html>
</richcontent>
<icon BUILTIN="messagebox_warning"/>
</node>
</node>
<node BACKGROUND_COLOR="#e0ceaa" COLOR="#690f14" CREATED="1737323283172" HGAP="21" ID="ID_1701981725" MODIFIED="1737323312863" TEXT="generic-&#x3bb; als Argument" VSHIFT="4">
<icon BUILTIN="idea"/>
</node>
</node>
<node BACKGROUND_COLOR="#ccb59b" COLOR="#6e2a38" CREATED="1737320465671" ID="ID_1253903906" MODIFIED="1737320483799" TEXT="pragmatische Grundhaltung &#x27f9; als M&#xf6;glichkeit bieten">
<font ITALIC="true" NAME="SansSerif" SIZE="14"/>
<icon BUILTIN="yes"/>
<node CREATED="1737320506752" ID="ID_437252539" MODIFIED="1737320793444" TEXT="switch-by-selector ist hier offensichtlich naheliegend">
<richcontent TYPE="NOTE"><html>
<head>
</head>
<body>
<p>
wenn man ohnehin eine bestimmte Syntax parsen m&#246;chte, ist es naheliegend und nat&#252;rlich, auf den vorliegenden konkreten Zweig zu pr&#252;fen und zu verzweigen; in dieser Form erscheint das eine vertretbare und nicht weiter gef&#228;hrliche Herangehensweise. Dieser Ansatz kann allerdings durchaus in einen schwer wartbaren Zustand abgleiten, wenn die Syntax komplex und heterogen strukturiert ist; dann mu&#223; man die Varianten mehr oder weniger im Kopf haben. <i>F&#252;r dieses Problem sehe ich keine allgemeing&#252;ltige L&#246;sung...</i>
</p>
</body>
</html>
</richcontent>
</node>
<node CREATED="1737320521062" ID="ID_819937863" MODIFIED="1737321052072" TEXT="einen by-type-Visitor-Mechanismus als Alternative bieten">
<richcontent TYPE="NOTE"><html>
<head>
</head>
<body>
<p>
Das ist eine sch&#246;ne neue M&#246;glichkeit, die sich durch die generischen Lambdas auftut; durchaus m&#246;glich, da&#223; in manchen F&#228;llen eine solche Formulierung eine drastische Vereinfachung darstellt, beispielsweise wenn alle Zweige jeweils einen RegExp-Match mit &#228;quivalent angeordneten Capture-Groups beinhalten; die Einzelf&#228;lle w&#252;rden damit sozusagen <i>transparent verschmolzen.</i>
</p>
</body>
</html>
</richcontent>
</node>
</node>
</node>
</node>
</node>
</node>
</node>
</node>
<node CREATED="1737048820482" ID="ID_235554745" MODIFIED="1737048832524" TEXT="generisches Model-Binding"/>
</node>
@ -69239,6 +69672,10 @@
</node>
</node>
</node>
<node BACKGROUND_COLOR="#f0d5c5" COLOR="#990033" CREATED="1737318668958" ID="ID_627954659" MODIFIED="1737319274847" TEXT="Design-Entscheidungen">
<linktarget COLOR="#5f3947" DESTINATION="ID_627954659" ENDARROW="Default" ENDINCLINATION="-1576;173;" ID="Arrow_ID_137322402" SOURCE="ID_1971507664" STARTARROW="None" STARTINCLINATION="-2020;303;"/>
<icon BUILTIN="yes"/>
</node>
<node CREATED="1531419748046" ID="ID_1791265013" MODIFIED="1557498707236" TEXT="Lebenszyklus">
<node COLOR="#338800" CREATED="1531419790153" ID="ID_1605635763" MODIFIED="1582443076662" TEXT="#1145 define startup sequence">
<icon BUILTIN="button_ok"/>
@ -152710,6 +153147,81 @@ unsigned int ThreadIdAsInt = *static_cast&lt;unsigned int*&gt;(static_cast&lt;vo
<edge COLOR="#9e7171" STYLE="linear"/>
<font NAME="SansSerif" SIZE="16"/>
<node CREATED="1522933436743" ID="ID_669941386" MODIFIED="1557498707241" TEXT="Architektur">
<node BACKGROUND_COLOR="#f0d5c5" COLOR="#990033" CREATED="1737318517999" HGAP="-32" ID="ID_1971507664" MODIFIED="1737319274847" TEXT="Design-Fragen" VSHIFT="-53">
<cloud COLOR="#d6c0a2"/>
<arrowlink COLOR="#5f3947" DESTINATION="ID_627954659" ENDARROW="Default" ENDINCLINATION="-1576;173;" ID="Arrow_ID_137322402" STARTARROW="None" STARTINCLINATION="-2020;303;"/>
<icon BUILTIN="help"/>
<node CREATED="1737318409369" ID="ID_84646881" MODIFIED="1737320326450">
<richcontent TYPE="NODE"><html>
<head/>
<body>
<p>
Design-Diskussion &#187;<b>Visitor</b>&#171;
</p>
</body>
</html></richcontent>
<linktarget COLOR="#777dc0" DESTINATION="ID_84646881" ENDARROW="Default" ENDINCLINATION="-1890;189;" ID="Arrow_ID_190224326" SOURCE="ID_779074690" STARTARROW="None" STARTINCLINATION="-3213;124;"/>
<node CREATED="1737319315584" ID="ID_1690754176" MODIFIED="1737319683732" TEXT="von Anfang an ein Grundthema f&#xfc;r mich">
<richcontent TYPE="NOTE"><html>
<head/>
<body>
<p>
Die &#220;berlegungen zum Visitor und double-Dispatch tauchten bereits in meinen allerersten Design-Studien zu Lumiera auf. Zun&#228;chst war mir nur undeutlich ein Zusammenhang klar, warum ich in diese Richtung strebte, erst im Lauf der Jahre enth&#252;llte sich ein gr&#246;&#223;erer Zusammenhang: es ist die Suche nach einer Struktur, die weder von Anbeginn an feste Setzungen macht, aber auch nicht blo&#223; vom Einzelfall getrieben ist. Wie kann man eine gestaltete Struktur bauen und halten, ohne mit einer gewaltsamen Setzung zu beginnen, die im Weitergehen doch zwansl&#228;ufig zuschanden werden mu&#223;? Wie verhindert man, sich in eine Sackgasse zu bringen, indem man sich einfach am naheliegend gegebenen entlanghangelt? Wie vermeidet man Ideenflucht und das &#8222;we'll figure it out&#8220;-Syndrom?
</p>
</body>
</html></richcontent>
</node>
<node CREATED="1737319727440" ID="ID_1793365426" MODIFIED="1737319730564" TEXT="Belange">
<node CREATED="1737320124539" ID="ID_1469328079" MODIFIED="1737320139623" TEXT="Expression-Problem: Modell mit mehreren offenen Dimensionen"/>
<node CREATED="1737319821436" ID="ID_202480911" MODIFIED="1737319826583" TEXT="Umgang mit offener Typisierung">
<node CREATED="1737320066042" ID="ID_1094834792" MODIFIED="1737320083380" TEXT="Gefahr der switch-case-Hell">
<icon BUILTIN="messagebox_warning"/>
</node>
</node>
</node>
<node CREATED="1737319731887" ID="ID_206811869" MODIFIED="1737319744778" TEXT="Konkrete Aufgaben">
<node CREATED="1737319753869" ID="ID_324187249" MODIFIED="1737319764815" TEXT="Aktionen auf einem Syntax-Modell">
<node CREATED="1737320015898" ID="ID_564243774" MODIFIED="1737320050802">
<richcontent TYPE="NODE"><html>
<head/>
<body>
<p style="text-align: right">
wie kann man einen Compiler anlegen,
</p>
<p style="text-align: right">
ohne bereits zu wissen, was compiliert wird?
</p>
</body>
</html></richcontent>
<icon BUILTIN="help"/>
</node>
</node>
<node CREATED="1737319887251" ID="ID_556869455" MODIFIED="1737319899245" TEXT="offene Befehls-Spezifikation"/>
<node CREATED="1737320216607" ID="ID_900361053" MODIFIED="1737320223218" TEXT="algebraische Terme"/>
</node>
</node>
<node CREATED="1737319070929" ID="ID_1581929006" MODIFIED="1737319192871">
<richcontent TYPE="NODE"><html>
<head/>
<body>
<p>
<u>Problem</u>: &#187;<b>Event</b>&#171;-getriebene Struktur
</p>
</body>
</html></richcontent>
<node CREATED="1737319089055" ID="ID_184966462" MODIFIED="1737319101788" TEXT="Gefahr der &#xbb;pinball-Machine&#xab;"/>
</node>
<node CREATED="1737319142807" ID="ID_698251911" MODIFIED="1737319218171">
<richcontent TYPE="NODE"><html>
<head/>
<body>
<p>
multiple &#187;<b>Domain Ontologies</b>&#171;?
</p>
</body>
</html></richcontent>
</node>
</node>
<node CREATED="1522933471266" ID="ID_1652255203" MODIFIED="1557498707241" TEXT="GUI">
<node COLOR="#435e98" CREATED="1522933474914" FOLDED="true" ID="ID_1612113311" MODIFIED="1561238415968" TEXT="Backbone">
<linktarget COLOR="#6278c0" DESTINATION="ID_1612113311" ENDARROW="Default" ENDINCLINATION="94;100;" ID="Arrow_ID_879038794" SOURCE="ID_1835644126" STARTARROW="None" STARTINCLINATION="-3;-77;"/>