From 8167fbff77f59710f293a9db22cd6423bdbdc459 Mon Sep 17 00:00:00 2001 From: Ichthyostega Date: Sun, 17 Apr 2016 01:07:07 +0200 Subject: [PATCH] implement fast-forward and assignment to value ...all of this implementation boils down to slightly adjusting the code written for the test-mutation-target. Insofar it pays off now having implemented this diagnostic and demonstration first. Moreover I'm implementing this basic scheme of "diff application" roughly the fourth time, thus things kindof fall into place now. What's really hard is all those layers of abstraction in between. Lesson learned (after being off for three weeks, due to LAC and other obligations): I really need to document the meaning of the closures, and I need to document the "abstract operational semantics" of diff application, otherwise no one will be able to provide the correct closures. --- .../diff/tree-mutator-collection-binding.hpp | 50 ++++++++++--------- src/lib/diff/tree-mutator.hpp | 4 +- .../diff/tree-manipulation-binding-test.cpp | 10 ++-- wiki/renderengine.html | 10 ++-- wiki/thinkPad.ichthyo.mm | 43 ++++++++++------ 5 files changed, 68 insertions(+), 49 deletions(-) diff --git a/src/lib/diff/tree-mutator-collection-binding.hpp b/src/lib/diff/tree-mutator-collection-binding.hpp index 5438de3c8..5cc6dd550 100644 --- a/src/lib/diff/tree-mutator-collection-binding.hpp +++ b/src/lib/diff/tree-mutator-collection-binding.hpp @@ -146,19 +146,31 @@ return pos; } -#if false /////////////////////////////////////////////////////////////////////////////////////////////////////////////UNIMPLEMENTED :: TICKET #992 iterator - locate (GenNode::ID const& targetID) + locate (GenNode const& targetSpec) { - if (!empty() and content_.back().matches(targetID)) + if (not collection.empty() and matches (targetSpec, collection.back())) return lastElm(); else - return search (targetID, eachElm(content_)); + return search (targetSpec, eachElm(collection)); + } + + private: + /** @internal technicality + * Our iterator is actually a Lumiera RangeIter, and thus we need + * to construct a raw collection iterator pointing to the aftmost element + * and then create a range from this iterator and the `end()` iterator. + */ + iterator + lastElm() + { + using raw_iter = typename CollectionBinding::Coll::iterator; + return iterator (raw_iter(&collection.back()), collection.end()); } -#endif /////////////////////////////////////////////////////////////////////////////////////////////////////////////UNIMPLEMENTED :: TICKET #992 }; + /** * Attach to collection: Building block for a concrete `TreeMutator`. * This decorator will be outfitted with actual binding and closures @@ -250,7 +262,6 @@ return found; } -#if false /////////////////////////////////////////////////////////////////////////////////////////////////////////////UNIMPLEMENTED :: TICKET #992 /** repeatedly accept, until after the designated location */ virtual bool accept_until (GenNode const& spec) @@ -259,25 +270,23 @@ if (spec.matches (Ref::END)) for ( ; pos_; ++pos_) - target_.inject (move(*pos_), "accept_until END"); + binding_.inject (move(*pos_)); else { - string logMsg{"accept_until "+spec.idi.getSym()}; - while (pos_ and not TestWireTap::matchSrc(spec)) + while (pos_ and not ChildCollectionMutator::matchSrc(spec)) { - target_.inject (move(*pos_), logMsg); + binding_.inject (move(*pos_)); ++pos_; } - if (TestWireTap::matchSrc(spec)) + if (ChildCollectionMutator::matchSrc(spec)) { - target_.inject (move(*pos_), logMsg); + binding_.inject (move(*pos_)); ++pos_; } else foundTarget = false; } - return PAR::accept_until(spec) - or foundTarget; + return foundTarget; } /** locate element already accepted into the target sequence @@ -285,17 +294,12 @@ virtual bool assignElm (GenNode const& spec) { - Iter targetElm = target_.locate (spec.idi); - if (targetElm) - { - string logOldPayload{render(targetElm->data)}; - *targetElm = spec; - target_.logAssignment (*targetElm, logOldPayload); - } - return PAR::assignElm(spec) - or targetElm; + Iter target_found = binding_.locate (spec); + return target_found? binding_.assign (*target_found, spec) + : false; } +#if false /////////////////////////////////////////////////////////////////////////////////////////////////////////////UNIMPLEMENTED :: TICKET #992 /** locate the designated target element and build a suitable * sub-mutator for this element into the provided target buffer */ virtual bool diff --git a/src/lib/diff/tree-mutator.hpp b/src/lib/diff/tree-mutator.hpp index 0d87405d4..a9204f5ee 100644 --- a/src/lib/diff/tree-mutator.hpp +++ b/src/lib/diff/tree-mutator.hpp @@ -106,13 +106,13 @@ namespace lib { /////////////////////////////TODO move over into opaque-holder.hpp /** * handle to allow for safe _»remote implantation«_ - * of an unknown subclass into a given OpaqueHolder buffer, + * of an unknown subclass into a given opaque InPlaceBuffer, * without having to disclose the concrete buffer type or size. * @remarks this is especially geared towards use in APIs, allowing * a not yet known implementation to implant an agent or collaboration * partner into the likewise undisclosed innards of the exposed service. * @warning the type BA must expose a virtual dtor, since the targeted - * OpaqueHolder has to take ownership of the implanted object. + * InPlaceBuffer has to take ownership of the implanted object. */ template class PlantingHandle diff --git a/tests/library/diff/tree-manipulation-binding-test.cpp b/tests/library/diff/tree-manipulation-binding-test.cpp index bf7f0561d..073284676 100644 --- a/tests/library/diff/tree-manipulation-binding-test.cpp +++ b/tests/library/diff/tree-manipulation-binding-test.cpp @@ -467,8 +467,10 @@ namespace test{ }) .assignElement ([&](Data& target, GenNode const& spec) -> bool { - UNIMPLEMENTED ("binding for assignment"); - return false; + cout << "assign "< bool { @@ -482,9 +484,9 @@ namespace test{ 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 (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 ( 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) < -
+
The TreeMutator is an intermediary to translate a generic structure pattern into heterogeneous local invocation sequences.
 within the [[diff framework|TreeDiffModel]], this is a crucial joint, since here the abstract, generic, ~DOM-like ExternalTreeDescription meeds opaque, local and undisclosed data structures.
 
@@ -8238,10 +8238,12 @@ This means, we do not share a data model -- rather we exchange ''diff messages''
 
 So, from the usage side, some kind of implementation data structure will build a TreeMutator and tie itself into its binding Then, by exposing this {{{TreeMutator}}} implementation, this client data structure gets the ability to receive diff messages, which means this local and undisclosed data structure can be attached to and  collaborate with some other subsystem; it can be altered, extended and reshaped remotely, without the need to share implementation details.
 
-Incidentally, the ''diff language'' itself is meant to be readable and expressive. On the //sending side,// typically diff messages will be constructed direcly in code. To this end, the GenNode offers a constructor and mutator syntax specifically crafted to allow writing clear and compact diff messages. Since the tree diff language embedds a simple list diff language as a subset, it is possible to generate structural changes by observing changes on data collections. Such //detected diffs// may be embedded within explicitly written diff message sequences.
+Incidentally, the ''diff language'' itself is meant to be readable and expressive. On the //sending side,// typically diff messages will be constructed directly in code. To this end, the GenNode offers a constructor and mutator syntax specifically crafted to allow writing clear and compact diff messages. Since the tree diff language embeds a simple list diff language as a subset, it is possible to generate structural changes by observing changes on data collections. Such //detected diffs// may be embedded within explicitly written diff message sequences.
 
-The cannonical example are changes to the editing session. After maybe running some resolution steps, an actual effective change is determined within the session. At this point, a minimal diff message to describe this effective change will be created. This diff message can be logged, to make the change persistent. And then this message will be "cast towards the UI". There is a communication structure, the UI-Bus, which allows to "cast" such a message towards an element only known and designated by its ID. In fact, this receiver element will be a widget within the UI, and this widget exposes a custom configured TreeMutator to consume this message and effect the corresponding changes within the widget structure of the UI.
-
+The canonical example are changes to the editing session. After maybe running some resolution steps, an actual effective change is determined within the session. At this point, a minimal diff message to describe this effective change will be created. This diff message can be logged, to make the change persistent. And then this message will be "cast towards the UI". There is a communication structure, the UI-Bus, which allows to "direct" such a message towards an element only known and designated by its ID. In fact, this receiver element will be a widget within the UI, and this widget exposes a custom configured TreeMutator to consume this message and effect the corresponding changes within the widget structure of the UI. + +!Semantics +The TreeMutator is an //adapter,// allowing the diff language to perform some abstracted generic operations, and at the same time enabling access to an (not further disclosed) implementation data structure in a standardised way.
The TreeMutator is an intermediary to translate a generic structure pattern into heterogeneous local invocation sequences.
diff --git a/wiki/thinkPad.ichthyo.mm b/wiki/thinkPad.ichthyo.mm
index c98fae9b1..cb2a8ed8d 100644
--- a/wiki/thinkPad.ichthyo.mm
+++ b/wiki/thinkPad.ichthyo.mm
@@ -497,8 +497,7 @@
       Und ich muß das in einem Test zumindest emulieren können!
     

- - + @@ -2126,8 +2125,7 @@ "target matches spec"

- - +
@@ -2149,8 +2147,7 @@ aber existiert nominell und kontext-abhängig

- - +
@@ -2446,8 +2443,7 @@ sofern es gelingt, die Funktionalität gutmütig zu degradieren.

- - + @@ -2522,8 +2518,7 @@ erfordert wirklich Kooperation

- - + @@ -2569,8 +2564,7 @@ daneben auf die grüne Wiese stellen. Ist ja nur ein Test :-D

- - +
@@ -2589,8 +2583,7 @@ dessen payload per default-konstruktor zu erzeugen.

- - +
@@ -2675,8 +2668,7 @@ Typisches Beispiel: eine STL-Collection von Strings.

- - + @@ -2724,6 +2716,25 @@ + + + + + + +

+ ...sonst wird niemand Lambdas bereitstellen können, oder gar Diff-Nachrichten erzeugen. +

+

+ Das ist nun kein spezielles Problem der gewählten Implementierungs-Technik, sondern rührt daher, +

+

+ daß der Client hier eigentlich ein Protokoll implementieren muß. +

+ + +
+