draft third round of mutation operations to be implemented

...now about opening a sub mutator within a nested scope
This commit is contained in:
Fischlurch 2016-04-16 02:20:23 +02:00
parent 54fb335a9c
commit 7f42b9b7e7
4 changed files with 179 additions and 10 deletions

View file

@ -99,7 +99,7 @@
ASSERT_VALID_SIGNATURE (CTR, Elm (GenNode const&))
ASSERT_VALID_SIGNATURE (SEL, bool(GenNode const&))
ASSERT_VALID_SIGNATURE (ASS, bool(Elm&, GenNode const&))
ASSERT_VALID_SIGNATURE (MUT, bool(Elm&, TreeMutator::MutatorBuffer))
ASSERT_VALID_SIGNATURE (MUT, bool(Elm&, GenNode::ID const&, TreeMutator::MutatorBuffer))
Coll& collection;
@ -332,7 +332,7 @@
template<class FUN>
CollectionBindingBuilder<COLL, FUN ,CTR,SEL,ASS,MUT>
matchElement(FUN matcher)
matchElement (FUN matcher)
{
return { this->collection
, matcher
@ -345,7 +345,7 @@
template<class FUN>
CollectionBindingBuilder<COLL,MAT, FUN ,SEL,ASS,MUT>
constructFrom(FUN constructor)
constructFrom (FUN constructor)
{
return { this->collection
, this->matches
@ -358,7 +358,7 @@
template<class FUN>
CollectionBindingBuilder<COLL,MAT,CTR, FUN ,ASS,MUT>
isApplicableIf(FUN selector)
isApplicableIf (FUN selector)
{
return { this->collection
, this->matches
@ -371,7 +371,7 @@
template<class FUN>
CollectionBindingBuilder<COLL,MAT,CTR,SEL, FUN ,MUT>
assignElement(FUN setter)
assignElement (FUN setter)
{
return { this->collection
, this->matches
@ -384,7 +384,7 @@
template<class FUN>
CollectionBindingBuilder<COLL,MAT,CTR,SEL,ASS, FUN >
buildChildMutator(FUN childMutationBuilder)
buildChildMutator (FUN childMutationBuilder)
{
return { this->collection
, this->matches
@ -465,7 +465,7 @@
}
static bool
disable_childMutation (Elm&, TreeMutator::MutatorBuffer)
disable_childMutation (Elm&, GenNode::ID const&, TreeMutator::MutatorBuffer)
{
return false;
}

View file

@ -125,7 +125,7 @@ namespace test{
DiffSeq
mutationDiff()
{
// prepare for direkt assignement of new value
// prepare for direct assignment of new value
// NOTE: the target ID will be reconstructed, including hash
GenNode childA_upper(CHILD_A.idi.getSym(), "A");

View file

@ -71,7 +71,7 @@ namespace test{
CHILD_A("a"), // unnamed string child node
CHILD_B('b'), // unnamed char child node
CHILD_T(Time(12,34,56,78)), // unnamed time value child
SUB_NODE = MakeRec().type("ω").genNode(),// empty anonymous node used to open a sub scope
SUB_NODE = MakeRec().genNode(), // empty anonymous node used to open a sub scope
ATTRIB_NODE = MakeRec().genNode("δ"), // empty named node to be attached as attribute δ
CHILD_NODE = SUB_NODE, // yet another child node, same ID as SUB_NODE (!)
GAMMA_PI("γ", 3.14159265); // happens to have the same identity (ID) as ATTRIB3AS
@ -313,6 +313,7 @@ namespace test{
using MapD = std::map<string, VecD>;
VecD target;
MapD subScopes;
// now set up a binding to these opaque private structures...
auto mutator =
@ -441,6 +442,90 @@ namespace test{
cout << "Content after reordering...."
<< join(target) <<endl;
// --- third round: mutate data and sub-scopes ---
// This time we build the Mutator bindings in a way to allow mutation
// For one, "mutation" means to assign a changed value to a simple node / attribute.
// And beyond that, mutation entails to open a nested scope and delve into that recursively.
// Here, as this is really just a test and demonstration, we implement those nested scopes aside
// managed within a map and keyed by the sub node's ID.
auto mutator3 =
TreeMutator::build()
.attach (collection(target)
.constructFrom ([&](GenNode const& spec) -> Data
{
cout << "constructor invoked on "<<spec<<endl;
return {spec.idi.getSym(), render(spec.data)};
})
.matchElement ([&](GenNode const& spec, Data const& elm) -> bool
{
cout << "match? "<<spec.idi.getSym()<<"=?="<<elm.key<<endl;
return spec.idi.getSym() == elm.key;
})
.assignElement ([&](Data& target, GenNode const& spec) -> bool
{
UNIMPLEMENTED ("binding for assignment");
return false;
})
.buildChildMutator ([&](Data& target, GenNode::ID const& subID, TreeMutator::MutatorBuffer buff) -> bool
{
UNIMPLEMENTED ("binding for sub-scope mutation");
return false;
}));
CHECK (isnil (target));
CHECK (mutator3.matchSrc (ATTRIB3)); // new mutator starts out anew at the beginning
CHECK (mutator3.accept_until (ATTRIB2)); // fast forward behind attribute β
CHECK (mutator3.acceptSrc (ATTRIB3)); // and accept the second copy of attribute γ
CHECK (mutator3.matchSrc (SUB_NODE)); // this /would/ be the next source element, but...
CHECK (not contains(join(target), "γ = 3.1415927"));
CHECK (mutator3.assignElm(GAMMA_PI)); // ...we assign a new payload to the current element first
CHECK ( contains(join(target), "γ = 3.1415927"));
CHECK (mutator3.accept_until (Ref::END)); // fast forward, since we do not want to re-order anything
cout << "Content after assignment; "
<< join(target) <<endl;
// prepare for recursion into sub scope..
// Since this is a demonstration, we do not actually recurse into anything,
// rather we invoke the operations on a nested mutator right from here.
InPlaceBuffer<TreeMutator, sizeof(mutator3)> subMutatorBuffer;
TreeMutator::MutatorBuffer placementHandle(subMutatorBuffer);
CHECK (mutator3.mutateChild (SUB_NODE, placementHandle));
CHECK (isnil (subScopes[SUB_NODE])); // ...this is where the nested mutator is expected to work on
CHECK (subMutatorBuffer->emptySrc());
// now use the Mutator *interface* to talk to the nested mutator...
// This code might be confusing, because in fact we're playing two roles here!
// For one, above, in the definition of mutator3 and in the declaration of MapD subScopes,
// the test code represents what a private data structure and binding would do.
// But below we enact the TreeDiffAplicattor, which *would* use the Mutator interface
// to talk to an otherwise opaque nested mutator implementation. Actually, here this
// nested opaque mutator is created on-the-fly, embedded within the .buildChildMutator(..lambda...)
subMutatorBuffer->injectNew (TYPE_X);
subMutatorBuffer->injectNew (ATTRIB3);
subMutatorBuffer->injectNew (CHILD_B);
subMutatorBuffer->injectNew (CHILD_A);
CHECK (not subMutatorBuffer->emptySrc());
CHECK (not isnil (subScopes[SUB_NODE])); // ...and "magically" these instructions happened to insert
CHECK (join(subScopes[SUB_NODE]) == "β = 2, b, a"); // some new content into our implementation defined sub scope!
// now back to parent scope....
// error handling: assignment might throw
GenNode differentTime{CHILD_T.idi.getSym(), Time(11,22)};
VERIFY_ERROR (LOGIC, mutator3.assignElm (differentTime));
CHECK (join(target) == "γ = 3.45, α = 1, β = 2, γ = 3.1415927, Rec(ξ| β = 2 |{b, a}), b, 78:56:34.012");
}

View file

@ -1970,7 +1970,8 @@
<icon BUILTIN="flag-yellow"/>
<node CREATED="1457741609884" ID="ID_1827838196" MODIFIED="1457741617108" TEXT="bin ich zust&#xe4;ndig?">
<node CREATED="1458094312266" ID="ID_233521483" MODIFIED="1458094316157" TEXT="isApplicable"/>
<node CREATED="1458094316697" ID="ID_839136400" MODIFIED="1458094326204" TEXT="Festlegung:">
<node CREATED="1458094316697" ID="ID_839136400" MODIFIED="1460755327191" TEXT="Festlegung:">
<icon BUILTIN="yes"/>
<node CREATED="1458094327095" ID="ID_306307671" MODIFIED="1458094334354" TEXT="nur auf Basis der spec"/>
<node CREATED="1458094334991" ID="ID_903070750" MODIFIED="1458094343401" TEXT="ohne Daten-Introspektion"/>
</node>
@ -2510,6 +2511,89 @@
<icon BUILTIN="help"/>
</node>
</node>
<node CREATED="1460762013033" ID="ID_758721262" MODIFIED="1460762015093" TEXT="Mutation">
<node CREATED="1460762015777" ID="ID_59179895" MODIFIED="1460762061424">
<richcontent TYPE="NODE"><html>
<head>
</head>
<body>
<p>
erfordert <i>wirklich</i>&#160;Kooperation
</p>
</body>
</html>
</richcontent>
<icon BUILTIN="idea"/>
<node CREATED="1460762025520" ID="ID_955853878" MODIFIED="1460762032675" TEXT="zwischen dem gesendeten Diff"/>
<node CREATED="1460762033119" ID="ID_863964003" MODIFIED="1460762045704" TEXT="und der empfangenden Implementierungs-Datenstruktur"/>
</node>
<node CREATED="1460762065371" ID="ID_698989532" MODIFIED="1460762096048" TEXT="brauche wohl &quot;Introspection light&quot;">
<icon BUILTIN="smily_bad"/>
<node CREATED="1460762101046" ID="ID_1593562435" MODIFIED="1460762111448" TEXT="damit ich einen Sub-Scope vorbereiten kann"/>
<node CREATED="1460762111924" ID="ID_125430023" MODIFIED="1460762120759" TEXT="in separater privater Datenstrukcur"/>
<node CREATED="1460762121259" ID="ID_1558869553" MODIFIED="1460762308964" TEXT="ist aber nur rein hier im Test ein Problem">
<richcontent TYPE="NOTE"><html>
<head>
</head>
<body>
<p>
...denn wir verwenden hier als &quot;private&quot; Datenstruktur
</p>
<p>
eine etwas komische Collection von Strings,
</p>
<p>
in die wir die String-Repr&#228;sentation der Spec-Payload schreiben.
</p>
<p>
</p>
<p>
In der Praxis dagegen w&#252;rde man wirklich einen privaten Datentyp verwenden,
</p>
<p>
und dann auch voraussetzen, da&#223; man <i>nur</i>&#160;Kinder dieses Typs (oder zuweisungskompatibel) bekommt.
</p>
<p>
</p>
<p>
Mein Poblem hier ist, da&#223; ich in dieser Demonstrations-Datenstruktur keine nested scopes repr&#228;sentieren kann.
</p>
<p>
Aber hey!, es ist meine private Datenstruktur -- also kann ich einfach eine Map von nested scopes
</p>
<p>
daneben auf die gr&#252;ne Wiese stellen. Ist ja nur ein Test :-D
</p>
</body>
</html>
</richcontent>
</node>
</node>
<node CREATED="1460762330487" ID="ID_914518092" MODIFIED="1460762395843" TEXT="Nein! Schwein gehabt">
<richcontent TYPE="NOTE"><html>
<head>
</head>
<body>
<p>
...dankenswerterweise hat der subscript-Operator von std::Map
</p>
<p>
die nette Eigenschaft, beim ersten Zugriff auf einen neuen Key
</p>
<p>
dessen payload per default-konstruktor zu erzeugen.
</p>
</body>
</html>
</richcontent>
<icon BUILTIN="ksmiletris"/>
</node>
</node>
</node>
<node CREATED="1458868836883" ID="ID_717368167" MODIFIED="1458868851053" TEXT="Beobachtungen">
<node CREATED="1458868852849" ID="ID_1641586585" MODIFIED="1458869076689" TEXT="Sonderbarer &quot;this&quot;-Typ">