From d22cc18c1341328a8f0e9436a753f34a821b0e95 Mon Sep 17 00:00:00 2001 From: Ichthyostega Date: Fri, 19 Feb 2016 17:22:41 +0100 Subject: [PATCH] introduce a value assignment verb into the tree-diff-language after sleeping one night over the problem, this seems to be the most natural solution, since the possibility of assignment naturally arises from the fact that, for tree diff, we have to distinguish between the *identity* of an element node and its payload (which could be recursive). Thus, IFF the payoad is an assignable value, why not allow to assign it. Doing so elegnatly solves the problem with assignment of attributes Signed-off-by: Ichthyostega --- src/lib/diff/gen-node.cpp | 2 +- src/lib/diff/tree-diff-application.hpp | 8 +++ src/lib/diff/tree-diff.hpp | 17 ++++- .../diff/diff-tree-application-test.cpp | 9 ++- wiki/renderengine.html | 3 +- wiki/thinkPad.ichthyo.mm | 68 ++++++++++++++++--- 6 files changed, 92 insertions(+), 15 deletions(-) diff --git a/src/lib/diff/gen-node.cpp b/src/lib/diff/gen-node.cpp index e6eb9ead8..ba930a329 100644 --- a/src/lib/diff/gen-node.cpp +++ b/src/lib/diff/gen-node.cpp @@ -73,7 +73,7 @@ namespace diff{ - /** Implementation of content equality test + /** Implementation of content equality test, delgating to content * @throws error::Logic when the given other DataCap * does not hold a value of the same type than * this DataCap. diff --git a/src/lib/diff/tree-diff-application.hpp b/src/lib/diff/tree-diff-application.hpp index 7105a9757..399f0da51 100644 --- a/src/lib/diff/tree-diff-application.hpp +++ b/src/lib/diff/tree-diff-application.hpp @@ -363,6 +363,14 @@ namespace diff{ ++src(); // get /after/ an explicitly given position } + /** assignement of changed value in one step */ + virtual void + set (GenNode const& n) override + { + GenNode const& elm = find_child (n.idi); + unConst(elm).data = n.data; + } + /** open nested scope to apply diff to child object */ virtual void mut (GenNode const& n) override diff --git a/src/lib/diff/tree-diff.hpp b/src/lib/diff/tree-diff.hpp index d39f458b0..329001661 100644 --- a/src/lib/diff/tree-diff.hpp +++ b/src/lib/diff/tree-diff.hpp @@ -40,8 +40,13 @@ ** a \em nested record ("nested child object"). ** - the typing of the elements is outside the scope of the diff language; it is ** assumed that the receiver knows what types to expect and how to deal with them. - ** - only nested records may be \em mutated by the diff. All other elements can - ** only be inserted, moved or deleted (like elements in list diff) + ** - there is a notion of changing or mutating the data content, while retaining + ** the identity of the element. Of course this requires the data content to be + ** assignalbe, which makes content mutation an optional feature. + ** - beyond that, like in list diff, elements might be changed through a sequence of + ** deletion and insertion of a changed element with the same identity. + ** - since the tree like data structure is _recursive_, mutation of nested records + ** os represented by "opening" the nested record, followed by a recursive diff. ** By implementing the #TreeDiffInterpreter interface (visitor), a concrete usage ** can receive a diff description and possibly apply it to suitable target data. ** @@ -97,6 +102,12 @@ namespace diff{ * to the first child element, while \c after(Ref::END) means to accept * all of the existing data contents as-is (presumably to append further * elements beyond that point). + * - \c set assign a new value to the element designated element. + * This is primarily intended for primitive data values and requires + * the payload type to be assignable, without changing the element's + * identity. The element is identified by the payload's ID and needs + * to be present already, i.e. it has to be mentioned by preceding + * order defining verbs (the list diff verbs, `pick`, or `find`). * - \c mut bracketing construct to open a nested sub scope, for mutation. * The element designated by the ID of the argument needs to be a * ["nested child object"](\ref Record). Moreover, this element must @@ -132,6 +143,7 @@ namespace diff{ virtual void skip(GenNode const& n) =0; virtual void after(GenNode const&n) =0; + virtual void set (GenNode const&n) =0; virtual void mut (GenNode const& n) =0; virtual void emu (GenNode const& n) =0; }; @@ -150,6 +162,7 @@ namespace diff{ // Tree structure verbs DiffStep_CTOR(after); + DiffStep_CTOR(set); DiffStep_CTOR(mut); DiffStep_CTOR(emu); }; diff --git a/tests/library/diff/diff-tree-application-test.cpp b/tests/library/diff/diff-tree-application-test.cpp index 2b2d77c4f..3b461563b 100644 --- a/tests/library/diff/diff-tree-application-test.cpp +++ b/tests/library/diff/diff-tree-application-test.cpp @@ -124,6 +124,10 @@ namespace test{ DiffSeq mutationDiff() { + // prepare for direkt assignement of new value + // NOTE: the target ID will be reconstructed, including hash + GenNode childA_upper(CHILD_A.idi.getSym(), "A"); + return snapshot({after(Ref::ATTRIBS) // fast forward to the first child , find(CHILD_T) , pick(CHILD_A) @@ -142,6 +146,7 @@ namespace test{ , ins(TYPE_Y) , ins(ATTRIB2) , emu(CHILD_NODE) + , set(childA_upper) // direct assignment, target found by ID (out of order) , mut(ATTRIB_NODE) // mutation can be out-of order, target found by ID , ins(CHILD_A) , ins(CHILD_A) @@ -189,7 +194,9 @@ namespace test{ .appendChild(CHILD_A) // .genNode("δ")); // auto subScope = nested.scope(); // and within the nested sub-scope we find - CHECK ( *subScope == CHILD_A); // CHILD_A + CHECK ( *subScope != CHILD_A); // CHILD_A has been altered by assigment + CHECK (CHILD_A.idi == subScope->idi); // ...: same ID as CHILD_A + CHECK ("A" == subScope->data.get()); // ...: but mutated payload CHECK (*++subScope == MakeRec().type("Y") // a yet-again nested sub-Record of type "Y" .set("β", int64_t(2)) // with just an attribute "β" == 2L .genNode(CHILD_NODE.idi.getSym())); // (and an empty child scope) diff --git a/wiki/renderengine.html b/wiki/renderengine.html index 8ab20075d..7b6aa77ef 100644 --- a/wiki/renderengine.html +++ b/wiki/renderengine.html @@ -8128,7 +8128,7 @@ Within the context of GuiModelUpdate, we discern two distinct situations necessi the second case is what poses the real challenge in terms of writing well organised code. Since in that case, the receiver side has to translate generic diff verbs into operations on hard wired language level data structures -- structures, we can not control, predict or limit beforhand. We deal with this situation by introducing a specific intermediary, the → TreeMutator. -
+
for the purpose of handling updates in the GUI timeline display efficiently, we need to determine and represent //structural differences//
 This leads to what could be considered the very opposite of data-centric programming. Instead of embody »the truth« into a central data model with predefined layout, we base our achitecture on a set of actors and their collaboration. In the mentioned example this would be the high-level view in the Session, the Builder, the UI-Bus and the presentation elements within the timeline view. Underlying to each such collaboration is a shared conception of data. There is no need to //actually represent that data// -- it can be conceived to exist in a more descriptive, declarative [[external tree description (ETD)|ExternalTreeDescription]]. In fact, what we //do represent// is a ''diff'' against such an external rendering.
 
@@ -8180,6 +8180,7 @@ Diff description and diff handling can be applied to tree-like data structures a
 Basically the transition from text diffing to changes on data structures is achieved by exchanging the //type of the tokens.// Instead of words, or lines of text, we now use //data elements.// To do so, we introduce a symbolic ExternalTreeDescription of tree-like core data structures. The elementary token element used in this tree diff, the GenNode, embodies either simple plain data elements (numbers, strings, booleans, id-hashes, time values) -- or it describes a //recursive data element,// given as {{{Record<GenNode>}}}. Such a recursive data element describes object-like entities as a sequence of metadata, named attributes and ordered child-nodes -- it is handled in two phases: the first step is to treat the presence and ordering of child data elements, insertions and deletes. The second phase opens for each structurally changed child data element a recursive bracketing construct, as indicated  by explicit (and slightly redundant) //bracketing tokens://
 *{{{mut}}}(node-ID)  : recurse into the designated node, which must be present already as result of the preceding changes. The following diff tokens describe //mutations// of the child
 *{{{emu}}}(node-ID)  : close the current node context and return one step up; the node-ID is given for verification, but can be used to restore the working position at parent level
+*{{{set}}}(node)  : shortcut notation for simple value elements; assign the new payload value to the designated element, retaining identity
 In addition, in a future extension, we might consider to introduce up/down folding primitives
 *{{{fold}}}(node-ID) : pick the following elements and fold them down into a new child with given node-ID. The downfolding continues until the next {{{emu}}} token
 *{{{lift}}}(node-ID) : remove the next child node, which must be node-ID, and insert its children at current position
diff --git a/wiki/thinkPad.ichthyo.mm b/wiki/thinkPad.ichthyo.mm
index f8ae17b0f..4d9f203f1 100644
--- a/wiki/thinkPad.ichthyo.mm
+++ b/wiki/thinkPad.ichthyo.mm
@@ -474,7 +474,7 @@
 
 
 
-
+
 
 
 
@@ -560,7 +560,8 @@
 
 
 
-
+
+
 
 
 
@@ -577,9 +578,15 @@
 
 
 
-
-
-
+
+
+
+
+
+
+
+
+
 
   
     
@@ -591,23 +598,64 @@
   
 
 
+
 
 
 
-
-
+
+
+
+
 
 
 
 
-
+
+
 
 
 
 
 
-
-
+
+
+
+
+
+  
+    
+  
+  
+    

+ Nein +

+ + +
+ + + + + + + +

+ aber was dann wenn out-of-order +

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