diff --git a/src/lib/diff/diff-message.hpp b/src/lib/diff/diff-message.hpp index f2adabe94..ab3ed204c 100644 --- a/src/lib/diff/diff-message.hpp +++ b/src/lib/diff/diff-message.hpp @@ -36,8 +36,9 @@ ** @todo as of 8/2017 I am still rather clueless regarding the concrete situation to generate DiffMessage, ** and as a move into the dark I'll just define it to be based on IterSource... ** + ** @see DiffMessage_test ** @see AbstractTangible_test - ** @see mutation-message.hpp + ** @see BusTerm::change() ** */ diff --git a/tests/gui/abstract-tangible-test.cpp b/tests/gui/abstract-tangible-test.cpp index 674a93fa6..af84dd3ec 100644 --- a/tests/gui/abstract-tangible-test.cpp +++ b/tests/gui/abstract-tangible-test.cpp @@ -571,6 +571,8 @@ namespace test { * * Here in this test case, we use a hard wired diff sequence, * so we can check the expected structural changes actually took place. + * + * @see DiffMessage_test */ void mutate () diff --git a/tests/library/diff/diff-complex-application-test.cpp b/tests/library/diff/diff-complex-application-test.cpp index 5b4fff122..aa5bdd033 100644 --- a/tests/library/diff/diff-complex-application-test.cpp +++ b/tests/library/diff/diff-complex-application-test.cpp @@ -21,7 +21,11 @@ * *****************************************************/ /** @file diff-complex-application-test.cpp - ** unit test \ref DiffComplexApplication_test + ** unit test \ref DiffComplexApplication_test. + ** Demonstrates the concept of tree mutation by diff messages. + ** This is an elaborate demonstration setup to highlight some + ** of the more intricate, the flexibility and support for + ** and complex opaque implementation variations. */ @@ -173,11 +177,13 @@ namespace test{ * This function builds a TreeMutator implementation into the given buffer space * @note some crucial details for this binding to work properly... * - we define several "onion layers" of binding to deal with various scopes. - * - the priority of these bindings is ordered from lowest to highest + * - the priority of these bindings is layered backwards from lowest to highest, + * i.e. the resulting mutator will fist check for attribute δ and then work + * its way down do the `collection(nestedData_)` * - actually this is a quite complicated setup, including object fields - * to represent attributes, where one special attribute which actually holds - * a nested object, then both a collection of child objects and a collection - * of data values + * to represent attributes, where only one specific attribute actually holds + * a nested object and thus needs special treatment; beyond that we have both + * a collection of child objects and a collection of child data values * - the selector predicate (`isApplicableIf`) actually decides if a binding layer * becomes responsible for a given diff verb. Here, this decision is based on * the classification of the verb or spec to be handled, either being an @@ -251,8 +257,8 @@ namespace test{ }) .mutateAttrib("δ", [&](TreeMutator::Handle buff) { - if (not delta_) // note: object managed automatically, - delta_.reset (new Opaque("δ")); // no INS-implementation necessary + if (not delta_) // note: object is managed automatically, + delta_.reset (new Opaque("δ")); // thus no INS-implementation necessary REQUIRE (delta_); delta_->buildMutator(buff); @@ -281,7 +287,7 @@ namespace test{ /***********************************************************************//** * @test Demonstration: apply a structural change to unspecified private * data structures, with the help of an [dynamic adapter](\ref TreeMutator) - * - we use private data classes, defined here in the test fixture + * - we use private data classes, defined right here in the test fixture * to represent "just some" pre-existing data structure. * - we re-assign some attribute values * - we add, re-order and delete child "elements", without knowing diff --git a/tests/library/diff/diff-message-test.cpp b/tests/library/diff/diff-message-test.cpp new file mode 100644 index 000000000..325012f98 --- /dev/null +++ b/tests/library/diff/diff-message-test.cpp @@ -0,0 +1,225 @@ +/* + DiffMessage(Test) - demonstrate the basics of tree diff representation + + Copyright (C) Lumiera.org + 2017, Hermann Vosseler + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2 of + the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +* *****************************************************/ + +/** @file diff-message-test.cpp + ** unit test \ref DiffMessage_test + */ + + +#include "lib/test/run.hpp" +#include "lib/format-util.hpp" +#include "lib/diff/tree-diff-application.hpp" +#include "lib/iter-adapter-stl.hpp" +#include "lib/time/timevalue.hpp" +#include "lib/format-util.hpp" +#include "lib/util.hpp" + +#include +#include + +using lib::iter_stl::snapshot; +using util::isnil; +using util::join; +using std::string; +using std::vector; +using lib::time::Time; + + +namespace lib { +namespace diff{ +namespace test{ + + namespace {//Test fixture.... + + // define some GenNode elements + // to act as templates within the concrete diff + // NOTE: everything in this diff language is by-value + const GenNode ATTRIB1("α", 1), // attribute α = 1 + ATTRIB2("β", int64_t(2)), // attribute α = 2L (int64_t) + ATTRIB3("γ", 3.45), // attribute γ = 3.45 (double) + TYPE_X("type", "X"), // a "magic" type attribute "X" + TYPE_Y("type", "Y"), // + 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().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 (!) + + }//(End)Test fixture + + + + + + + + + + /***********************************************************************//** + * @test properties of a container to transport a diff from an abstracted + * source generator to an abstracted consumer. + * - this covers a standard usage scenario within Lumiera, where some + * producer in the Session core detects changes in session structure + * and sends a message to make the UI conform to the new structure + * - #########TODO + * The representation is given as a linearised sequence of verb tokens. + * In addition to the verbs used for list diffing, here we additionally + * have to deal with nested scopes, which can be entered thorough a + * bracketing construct \c mut(ID)...emu(ID). + * This test demonstrates the application of such diff sequences + * - in the first step, an empty root #Record is populated + * with a type-ID, three named attribute values, three child values + * and a nested child-Record. + * - the second step demonstrates various diff language constructs + * to alter, reshape and mutate this data structure + * After applying those two diff sequences, we verify the data + * is indeed in the expected shape. + * @remarks to follow this test, you should be familiar both with our + * \link diff::Record generic data record \endlink, as well as with + * the \link diff::GenNode variant data node \endlink. The key point + * to note is the usage of Record elements as payload within GenNode, + * which allows to represent tree shaped object like data structures. + * @see AbstractTangible_test::mutate() concrete usage scenario for UI-elements + * @see DiffTreeApplication_test change a tree-like data structure by diff + * @see DiffComplexApplication_test handling arbitrary data structures + * @see DiffListApplication_test + * @see DiffMessage + * @see ui-bus.hpp + */ + class DiffMessage_test + : public Test + , TreeDiffLanguage + { + using DiffSeq = iter_stl::IterSnapshot; + + DiffSeq + populationDiff() + { + return snapshot({ins(TYPE_X) + , ins(ATTRIB1) + , ins(ATTRIB2) + , ins(ATTRIB3) + , ins(CHILD_A) + , ins(CHILD_T) + , ins(CHILD_T) + , ins(SUB_NODE) + , mut(SUB_NODE) + , ins(CHILD_B) + , ins(CHILD_A) + , emu(SUB_NODE) + }); + } + + + DiffSeq + mutationDiff() + { + // prepare for direct assignment 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) + , skip(CHILD_T) + , del(CHILD_T) + , after(Ref::END) // accept anything beyond as-is + , mut(SUB_NODE) + , ins(ATTRIB3) + , ins(ATTRIB_NODE) // attributes can also be nested objects + , find(CHILD_A) + , del(CHILD_B) + , ins(CHILD_NODE) + , ins(CHILD_T) + , skip(CHILD_A) + , mut(CHILD_NODE) + , 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) + , ins(CHILD_A) + , emu(ATTRIB_NODE) + , emu(SUB_NODE) + }); + } + + + virtual void + run (Arg) + { + Rec::Mutator target; + Rec& subject = target; + DiffApplicator application(target); + + // Part I : apply diff to populate + application.consume(populationDiff()); + + CHECK (!isnil (subject)); // nonempty -- content has been added + CHECK ("X" == subject.getType()); // type was set to "X" + CHECK (1 == subject.get("α").data.get()); // has gotten our int attribute "α" + CHECK (2L == subject.get("β").data.get()); // ... the long attribute "β" + CHECK (3.45 == subject.get("γ").data.get()); // ... and double attribute "γ" + auto scope = subject.scope(); // look into the scope contents... + CHECK ( *scope == CHILD_A); // there is CHILD_A + CHECK (*++scope == CHILD_T); // followed by a copy of CHILD_T + CHECK (*++scope == CHILD_T); // and another copy of CHILD_T + CHECK (*++scope == MakeRec().appendChild(CHILD_B) // and there is a nested Record + .appendChild(CHILD_A) // with CHILD_B + .genNode(SUB_NODE.idi.getSym())); // and CHILD_A + CHECK (isnil(++scope)); // thats all -- no more children + + // Part II : apply the second diff + application.consume(mutationDiff()); + CHECK (join (subject.keys()) == "α, β, γ"); // the attributes weren't altered + scope = subject.scope(); // but the scope was reordered + CHECK ( *scope == CHILD_T); // CHILD_T + CHECK (*++scope == CHILD_A); // CHILD_A + Rec nested = (++scope)->data.get(); // and our nested Record, which too has been altered: + CHECK (nested.get("γ").data.get() == 3.45); // it carries now an attribute "δ", which is again + CHECK (nested.get("δ") == MakeRec().appendChild(CHILD_A) // a nested Record with three children CHILD_A + .appendChild(CHILD_A) // + .appendChild(CHILD_A) // + .genNode("δ")); // + auto subScope = nested.scope(); // and within the nested sub-scope we find + 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) + CHECK (*++subScope == CHILD_T); // followed by another copy of CHILD_T + CHECK (isnil (++subScope)); // + CHECK (isnil (++scope)); // and nothing beyond that. + } + }; + + + /** Register this test class... */ + LAUNCHER (DiffMessage_test, "unit common"); + + + +}}} // namespace lib::diff::test diff --git a/tests/library/diff/diff-tree-application-test.cpp b/tests/library/diff/diff-tree-application-test.cpp index 9f16b3dea..26c061263 100644 --- a/tests/library/diff/diff-tree-application-test.cpp +++ b/tests/library/diff/diff-tree-application-test.cpp @@ -21,7 +21,9 @@ * *****************************************************/ /** @file diff-tree-application-test.cpp - ** unit test \ref DiffTreeApplication_test + ** unit test \ref DiffTreeApplication_test. + ** Demonstrates the basic concept of reshaping structured data + ** through a tree-diff sequence. */ @@ -53,7 +55,7 @@ namespace test{ // define some GenNode elements // to act as templates within the concrete diff // NOTE: everything in this diff language is by-value - const GenNode ATTRIB1("α", 1), // attribute α = 1 + const GenNode ATTRIB1("α", 1), // attribute α = 1 ATTRIB2("β", int64_t(2)), // attribute α = 2L (int64_t) ATTRIB3("γ", 3.45), // attribute γ = 3.45 (double) TYPE_X("type", "X"), // a "magic" type attribute "X" diff --git a/wiki/renderengine.html b/wiki/renderengine.html index ac86ac8e9..042db3fd5 100644 --- a/wiki/renderengine.html +++ b/wiki/renderengine.html @@ -4018,9 +4018,11 @@ As an immediate consequence of not being able to reduce processing to elementary * the PlayProcess serves to join both views, providing a single PlayController front-end, while [[dispatching|FrameDispatcher]] to single channel processing. -
+
//message on the UI-Bus to cause changes on the targeted UI-Element.//
-The UI-Bus offers a dedicated API to direct ~MutationMessages towards {{{Tangible}}} elements, as designated by the given ID. Actually, such messages serve as //capsule to transport a [[diff-sequence|TreeDiffModel]]// -- since a diff sequence as such is always concrete and tied to a specific context, we can not represent it directly as an abstract type at interface level. The receiver of a diff sequence must offer the ability to be reshaped through diff messages, which is expressed through the interface {{{DiffMutable}}}. In our case here, {{{Tangible}}} offers this interface and thus the ability to construct a concrete TreeMutator, which in turn is bound to the internals of the actual UI-Element in question. Together this allows for a generic implementation of MutationMessage handling, where the designated UI-Element is reshaped by applying an embedded concrete diff message with the help of a {{{DiffApplicator<DiffMutable>}}}, based on the TreeMutator exposed.
+The UI-Bus offers a dedicated API to direct ~MutationMessages towards {{{Tangible}}} elements, as designated by the given ID. Actually, such messages serve as //capsule to transport a [[diff-sequence|TreeDiffModel]]// -- since a diff sequence as such is always concrete and tied to a specific context, we can not represent it directly as an abstract type at interface level. The receiver of a diff sequence must offer the ability to be reshaped through diff messages, which is expressed through the interface {{{DiffMutable}}}. + +In the case at hand, the basic building block of the Lumiera UI, the {{{Tangible}}} offers this interface and thus the ability to construct a concrete TreeMutator, which in turn is bound to the internals of the actual UI-Element in question. Together this allows for a generic implementation of MutationMessage handling, where the designated UI-Element is reshaped by applying a concrete diff sequence embedded in the message with the help of a {{{DiffApplicator<DiffMutable>}}}, based on the TreeMutator exposed.
Various aspects of the individual [[render node|ProcNode]] are subject to configuration and may influence the output quality or the behaviour of the render process.
diff --git a/wiki/thinkPad.ichthyo.mm b/wiki/thinkPad.ichthyo.mm
index 28a8e8047..c58bedc92 100644
--- a/wiki/thinkPad.ichthyo.mm
+++ b/wiki/thinkPad.ichthyo.mm
@@ -914,8 +914,14 @@
 
 
 
-
-
+
+
+
+
+
+
+
+
 
 
 
@@ -5813,7 +5819,7 @@
 
 
 
-
+
 
 
 
@@ -5833,7 +5839,7 @@
 
 
 
-
+
 
 
   
@@ -6246,16 +6252,16 @@
 
 
 
-
+
 
 
-
+
 
 
 
 
-
-
+
+
 
 
 
@@ -6328,7 +6334,7 @@
 
 
 
-
+
 
   
     
@@ -10869,9 +10875,9 @@
 
 
 
-
+
 
-
+
 
 
 
@@ -10931,11 +10937,13 @@
 
 
 
-
+
+
+
 
 
 
-
+
 
 
 
@@ -10948,26 +10956,29 @@
 
 
 
-
+
 
 
 
 
-
-
+
+
 
 
 
 
 
 
-
+
+
 
 
 
 
-
+
 
+
+
 
 
   
@@ -11018,15 +11029,59 @@
 
 
 
-
-
-
+
+
 
 
 
 
 
 
+
+
+
+
+
+
+
+
+
+
+
+
+  
+    
+  
+  
+    

+ Abstraktion +

+

+ nach beiden Setien +

+ + +
+ + + + + + + + + + + + + + + + + + + + @@ -11216,11 +11271,15 @@ - + - + + + + + @@ -11670,7 +11729,7 @@
- + @@ -11737,7 +11796,7 @@ - + @@ -11908,7 +11967,7 @@ - + @@ -11944,6 +12003,24 @@ + + + + + + + + + + + + + + + + + + @@ -15597,8 +15674,9 @@ - + + @@ -16628,6 +16706,63 @@ + + + + + + + + + + + + + + + + +

+ Diff ist eine abstrakte Quelle, +

+

+ die nur einmal verbraucht werden kann +

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

+ Dekorator-Prinzip. +

+

+ Paßt hier, da IterSource genau dieses Vorgehen nahelegt +

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