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:
parent
cf91f167dd
commit
3e743ff3b5
3 changed files with 637 additions and 2 deletions
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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");
|
||||
|
|
|
|||
|
|
@ -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ß 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ä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ß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üft"/>
|
||||
<node CREATED="1737237096366" ID="ID_1232165406" MODIFIED="1737237120960" TEXT="wenn ein Zweig zuschlä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ß jeweils explizit getypt und dann umkopiert werden"/>
|
||||
<node CREATED="1737237333495" ID="ID_1790838073" MODIFIED="1737237368558" TEXT="späterer Zugriff auf die Model-Daten ebenfalls gesteuert per Selektor (runtime-value)"/>
|
||||
</node>
|
||||
<node CREATED="1737237437320" ID="ID_201367357" MODIFIED="1737237446604" TEXT="Konsequenzen fü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ählten Typkontext"/>
|
||||
<node CREATED="1737237515422" ID="ID_1038704552" MODIFIED="1737237604198" TEXT="Datenzugriff per Dispatch von Selektor ⟶ statisch vorbereiteter Zweig"/>
|
||||
</node>
|
||||
<node CREATED="1737237726182" ID="ID_1444850716" MODIFIED="1737237738971" TEXT="⟹ benötigte Funktionalität">
|
||||
<node CREATED="1737237744920" ID="ID_269847251" MODIFIED="1737237787453" TEXT="Konstruktion: statisch auf den (derzeit) höchsten Selector-Platz"/>
|
||||
<node CREATED="1737237808373" ID="ID_291088107" MODIFIED="1737237829928" TEXT="Zugriff: statisch gegebener Selector ⟶ typisierter Getter">
|
||||
<node CREATED="1737237881741" ID="ID_183722240" MODIFIED="1737237886889" TEXT="analog wie get<i>(tuple)"/>
|
||||
<node CREATED="1737237896668" ID="ID_286879176" MODIFIED="1737237910693" TEXT="Metafunktion i ⟼ Typ"/>
|
||||
</node>
|
||||
<node CREATED="1737238022259" ID="ID_508598643" MODIFIED="1737238026071" TEXT="up-Copy">
|
||||
<node CREATED="1737238037257" ID="ID_1788967087" MODIFIED="1737238050739" TEXT="gegeben: AltModel<N>"/>
|
||||
<node CREATED="1737238051966" ID="ID_384770143" MODIFIED="1737238076015" TEXT="zu bauen: AltModel<N+1> mit kopierten Daten und gleichem Selektor"/>
|
||||
<node BACKGROUND_COLOR="#f8f1cb" COLOR="#a50125" CREATED="1737238094329" ID="ID_1160578555" MODIFIED="1737238106552" TEXT="braucht Trampolin fü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 über eine Kette verschachtelter Funktoren zurü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ösungsansatz">
|
||||
<icon BUILTIN="forward"/>
|
||||
<node CREATED="1737243124771" ID="ID_910400455" MODIFIED="1737243147396" TEXT="Storage-Basis verwenden: OpaqueSumType<N>">
|
||||
<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="⟹ kö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 ⟹ repetitives Kopieren egal">
|
||||
<richcontent TYPE="NOTE"><html>
|
||||
<head>
|
||||
|
||||
</head>
|
||||
<body>
|
||||
<p>
|
||||
bei der Sequenz wurde die gleiche Annahme gemacht, und daß der Optimiser das schon wuppen wird
|
||||
</p>
|
||||
</body>
|
||||
</html>
|
||||
</richcontent>
|
||||
</node>
|
||||
<node CREATED="1737243197654" ID="ID_1244482607" MODIFIED="1737243363548" TEXT="wir kopieren grundsätzlich in einen größeren Buffer ⟹ 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öße ist das Maximum des benötigten Platzes
|
||||
</p>
|
||||
</body>
|
||||
</html>
|
||||
</richcontent>
|
||||
</node>
|
||||
</node>
|
||||
<node BACKGROUND_COLOR="#f0d5c5" COLOR="#990033" CREATED="1737244421643" ID="ID_1284583110" MODIFIED="1737245500026" TEXT="intermediä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 ≙ dynamischer Dispatch"/>
|
||||
<node CREATED="1737308586765" ID="ID_1360651233" MODIFIED="1737308606555" TEXT="die ganze sonstiger »Parser-Code-Insel« ist rein-statitsch typisiert"/>
|
||||
<node CREATED="1737308671866" ID="ID_1034537096" MODIFIED="1737308702736" TEXT="Zahl der Branches klein ⟹ statische Impl im Vorteil"/>
|
||||
</node>
|
||||
<node CREATED="1737245511448" ID="ID_396620339" MODIFIED="1737245792925" TEXT="Alternativ: Rückübersetzung Selector ⟼ Typ-Kontext durch rekursive Funktionen">
|
||||
<richcontent TYPE="NOTE"><html>
|
||||
<head>
|
||||
|
||||
</head>
|
||||
<body>
|
||||
<p>
|
||||
das ist ähnlich zu einer <i>persistenten Datenstruktur:</i> man fragt den jeweiligen Vorgä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übergelegt"/>
|
||||
<node CREATED="1737308384535" ID="ID_1448196900" MODIFIED="1737308394626" TEXT="Anordnung der Typ-Parameter: Rückwärts gehend">
|
||||
<node CREATED="1737308397038" ID="ID_977244135" MODIFIED="1737308410928" TEXT="also der letzte / höchste Zweig zuerst"/>
|
||||
<node CREATED="1737308411588" ID="ID_1539400054" MODIFIED="1737308423294" TEXT="damit rekursiv-delegierende Implementierung möglich"/>
|
||||
</node>
|
||||
<node CREATED="1737309034680" ID="ID_1283731567" MODIFIED="1737309052170" TEXT="Code-Struktur ü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="�� Invariante: stets ein Zweig belegt">
|
||||
<font BOLD="true" NAME="SansSerif" SIZE="12"/>
|
||||
</node>
|
||||
<node CREATED="1737309159423" ID="ID_483153602" MODIFIED="1737309168193" TEXT="⟹ muß RAII sein"/>
|
||||
</node>
|
||||
<node CREATED="1737309211412" ID="ID_150276417" MODIFIED="1737309241998" TEXT="Opaque-Buffer als Basis ist nicht eigenständig">
|
||||
<node CREATED="1737309245044" ID="ID_1229816718" MODIFIED="1737309255638" TEXT="er müßte nä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ächlich Basis"/>
|
||||
<node CREATED="1737309352558" ID="ID_852458357" MODIFIED="1737309371391" TEXT="Sequenz von Summen-Typen übereinander geschichtet"/>
|
||||
<node CREATED="1737309372075" ID="ID_20092425" MODIFIED="1737309385022" TEXT="parent-Delegation fü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ßt, die Operationen fü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 »Stockwerk« 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ält"/>
|
||||
<node CREATED="1737309879188" ID="ID_1269779979" MODIFIED="1737309905040" TEXT="für jeden Aufruf wird rekursiv eine Typ-Projektion darübergelegt für die Zugriffe"/>
|
||||
<node BACKGROUND_COLOR="#eef0c5" COLOR="#990000" CREATED="1737309983889" ID="ID_217989124" MODIFIED="1737309993912" TEXT="Machbarkeit nicht klar ⟹ 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ß mit einem Laufzeit-Selektor arbeiten können"/>
|
||||
<node CREATED="1737313328618" ID="ID_233931368" MODIFIED="1737313650810" TEXT="muß eine statisch stets greifende Abbruchbedingung haben">
|
||||
<richcontent TYPE="NOTE"><html>
|
||||
<head>
|
||||
|
||||
</head>
|
||||
<body>
|
||||
<p>
|
||||
...weil der Compiler ja nichts über den Selektor-Wert weiß, muß 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ß so in die Kontrollstruktur eingebunden sein, daß die rekursiven Instantiierungen wirklich aufhö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önnte man eine generische select(λ)-Funktion schreiben">
|
||||
<node CREATED="1737313532583" ID="ID_551947957" MODIFIED="1737313549006" TEXT="diese wü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ü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ä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ätzliches Problem: Variant-Returntype nicht möglich">
|
||||
<icon BUILTIN="messagebox_warning"/>
|
||||
<node COLOR="#5b280f" CREATED="1737317489124" ID="ID_233312745" MODIFIED="1737317528208" TEXT="Funktion kann keinen vom Parameter abhängigen Rückgabetyp haben">
|
||||
<icon BUILTIN="closed"/>
|
||||
</node>
|
||||
<node BACKGROUND_COLOR="#fafe99" COLOR="#fa002a" CREATED="1737317639568" ID="ID_526309958" MODIFIED="1737317717888" TEXT="diese Einschränkung betrifft jedes Konstrukt fü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ächst attraktiver">
|
||||
<richcontent TYPE="NOTE"><html>
|
||||
<head>
|
||||
|
||||
</head>
|
||||
<body>
|
||||
<p>
|
||||
Und zwar im Bezug auf allgemeine Handwerksregeln...
|
||||
</p>
|
||||
<ul>
|
||||
<li>
|
||||
man könnte ohne Basisklasse auskommen
|
||||
</li>
|
||||
<li>
|
||||
der opaque-Bufer wäre als Implementierungsdetail direkt im private-Scope
|
||||
</li>
|
||||
<li>
|
||||
es wird nur eine einzige Klasse (pro Typ-Signatur) tatsächlich instantiiert
|
||||
</li>
|
||||
</ul>
|
||||
</body>
|
||||
</html>
|
||||
</richcontent>
|
||||
</node>
|
||||
<node CREATED="1737323954705" ID="ID_277050708" MODIFIED="1737324325847" TEXT="tatsächlich wird das aber durchaus hässlich...">
|
||||
<richcontent TYPE="NOTE"><html>
|
||||
<head>
|
||||
|
||||
</head>
|
||||
<body>
|
||||
<p>
|
||||
Das fängt schon damit an, daß man doch noch getemplatete Funktionen für die Elementar-Operationen schreiben muß (zumindest in C++17). Dazu kommt dann diese doch einigermaß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ätzliche Einschrä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 »Varant«-Type (und auch Union) unterliegt dieser Einschrä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älligerweise</i> kein Problem dar
|
||||
</p>
|
||||
</body>
|
||||
</html>
|
||||
</richcontent>
|
||||
<node CREATED="1737317782298" ID="ID_530599192" MODIFIED="1737320455593" TEXT="ist tatsächlich kein Zufall">
|
||||
<richcontent TYPE="NOTE"><html>
|
||||
<head>
|
||||
|
||||
</head>
|
||||
<body>
|
||||
<p>
|
||||
das erscheint zunächst wie »glückliche Umstände«;
|
||||
</p>
|
||||
<p>
|
||||
bei genauerer Überlegung wird aber klar, daß ich diese Einsicht bereits intuitiv angewendet hatte, als ich von Vornherein auch ein Selektor-Feld mit disponierte; es ist nämlich so, daß wir uns vermöge des Selektor-Feldes <i>genau diese explizite Info zur Compile-Zeit beschaffen </i>kö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(λ) 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 ⟹ 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<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">> </font>
|
||||
</p>
|
||||
<p>
|
||||
<font face="Monospaced" size="2">void </font>
|
||||
</p>
|
||||
<p>
|
||||
<font face="Monospaced" size="2"><b>select</b> (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">&& fun) </font>
|
||||
</p>
|
||||
<p>
|
||||
<font face="Monospaced" size="2">  { </font>
|
||||
</p>
|
||||
<p>
|
||||
<font face="Monospaced" size="2">    REQUIRE (slot <= 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">    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">      if (0 < </font><font color="#230dda" face="Monospaced" size="2">slot</font><font face="Monospaced" size="2">) </font>
|
||||
</p>
|
||||
<p>
|
||||
<font face="Monospaced" size="2">        <b>select</b><</font><font color="#a30303" face="Monospaced" size="2"><u>TS</u></font><font face="Monospaced" size="2">..> (</font><font color="#230dda" face="Monospaced" size="2">slot</font><font face="Monospaced" size="2">-1, forward<</font><font color="#a30303" face="Monospaced" size="2"><u>FUN</u></font><font face="Monospaced" size="2">>(fun)); </font>
|
||||
</p>
|
||||
<p>
|
||||
<font face="Monospaced" size="2">    fun (<b>access</b><</font><font color="#a30303" face="Monospaced" size="2"><u>TX</u></font><font face="Monospaced" size="2">>()); </font>
|
||||
</p>
|
||||
<p>
|
||||
<font face="Monospaced" size="2">  } </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ß für den Compiler sichtbar sein, daher als constexpr-if zu formulieren
|
||||
</li>
|
||||
<li>
|
||||
der Funktor oder das Lambda muß wirklich per offenem Template-Argument übergeben werden, weil es tatsächlich selber ein Template sein muß (generische Lambda bieten hierfür eine abgekürzte Schreibweise)
|
||||
</li>
|
||||
<li>
|
||||
der Zugriff ist trotzdem <b>komplett ungeschützt</b>
|
||||
</li>
|
||||
<li>
|
||||
man muß also anderweitig dafür sorgen, daß die slot-# tatsä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-λ 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 ⟹ als Mö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öchte, ist es naheliegend und natürlich, auf den vorliegenden konkreten Zweig zu prüfen und zu verzweigen; in dieser Form erscheint das eine vertretbare und nicht weiter gefährliche Herangehensweise. Dieser Ansatz kann allerdings durchaus in einen schwer wartbaren Zustand abgleiten, wenn die Syntax komplex und heterogen strukturiert ist; dann muß man die Varianten mehr oder weniger im Kopf haben. <i>Für dieses Problem sehe ich keine allgemeingültige Lö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öne neue Möglichkeit, die sich durch die generischen Lambdas auftut; durchaus möglich, daß in manchen Fällen eine solche Formulierung eine drastische Vereinfachung darstellt, beispielsweise wenn alle Zweige jeweils einen RegExp-Match mit äquivalent angeordneten Capture-Groups beinhalten; die Einzelfälle wü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<unsigned int*>(static_cast<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 »<b>Visitor</b>«
|
||||
</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ür mich">
|
||||
<richcontent TYPE="NOTE"><html>
|
||||
<head/>
|
||||
<body>
|
||||
<p>
|
||||
Die Überlegungen zum Visitor und double-Dispatch tauchten bereits in meinen allerersten Design-Studien zu Lumiera auf. Zunächst war mir nur undeutlich ein Zusammenhang klar, warum ich in diese Richtung strebte, erst im Lauf der Jahre enthüllte sich ein größerer Zusammenhang: es ist die Suche nach einer Struktur, die weder von Anbeginn an feste Setzungen macht, aber auch nicht bloß 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äufig zuschanden werden muß? Wie verhindert man, sich in eine Sackgasse zu bringen, indem man sich einfach am naheliegend gegebenen entlanghangelt? Wie vermeidet man Ideenflucht und das „we'll figure it out“-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>: »<b>Event</b>«-getriebene Struktur
|
||||
</p>
|
||||
</body>
|
||||
</html></richcontent>
|
||||
<node CREATED="1737319089055" ID="ID_184966462" MODIFIED="1737319101788" TEXT="Gefahr der »pinball-Machine«"/>
|
||||
</node>
|
||||
<node CREATED="1737319142807" ID="ID_698251911" MODIFIED="1737319218171">
|
||||
<richcontent TYPE="NODE"><html>
|
||||
<head/>
|
||||
<body>
|
||||
<p>
|
||||
multiple »<b>Domain Ontologies</b>«?
|
||||
</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;"/>
|
||||
|
|
|
|||
Loading…
Reference in a new issue