From fb93e349da4ae5a65a0a486af44e5c7a1a37b810 Mon Sep 17 00:00:00 2001 From: Ichthyostega Date: Thu, 11 Oct 2018 23:56:33 +0200 Subject: [PATCH] TreeMutator: conjure up a black hole mutator ...which is a somewhat involved version of /dev/null --- .../diff/tree-mutator-gen-node-binding.hpp | 2 +- src/lib/diff/tree-mutator-noop-binding.hpp | 102 ++++++++++ src/lib/diff/tree-mutator.hpp | 6 +- tests/15library.tests | 5 + .../library/diff/diff-ignore-changes-test.cpp | 187 ++++++++++++++++++ wiki/thinkPad.ichthyo.mm | 60 ++++++ 6 files changed, 360 insertions(+), 2 deletions(-) create mode 100644 src/lib/diff/tree-mutator-noop-binding.hpp create mode 100644 tests/library/diff/diff-ignore-changes-test.cpp diff --git a/src/lib/diff/tree-mutator-gen-node-binding.hpp b/src/lib/diff/tree-mutator-gen-node-binding.hpp index 914c23aed..95f063edf 100644 --- a/src/lib/diff/tree-mutator-gen-node-binding.hpp +++ b/src/lib/diff/tree-mutator-gen-node-binding.hpp @@ -23,7 +23,7 @@ /** @file tree-mutator-gen-node-binding.hpp ** Special binding implementation for TreeMutator, allowing to map - ** tree diff operations onto an »External Tree Description«. Such is is a + ** tree diff operations onto an »External Tree Description«. This term denotes a ** DOM like representation of tree like structures, comprised of GenNode elements. ** TreeMutator is a customisable intermediary, which enables otherwise opaque ** implementation data structures to receive and respond to generic structural diff --git a/src/lib/diff/tree-mutator-noop-binding.hpp b/src/lib/diff/tree-mutator-noop-binding.hpp new file mode 100644 index 000000000..a07c26fa3 --- /dev/null +++ b/src/lib/diff/tree-mutator-noop-binding.hpp @@ -0,0 +1,102 @@ +/* + TREE-MUTATOR-NOOP-BINDING.hpp - diff::TreeMutator implementation building block + + Copyright (C) Lumiera.org + 2018, 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 tree-mutator-noop-binding.hpp + ** Special binding implementation for TreeMutator, allowing to accept + ** and ignore any tree diff without tangible effect. TreeMutator is a + ** customisable intermediary, which enables otherwise opaque implementation + ** data structures to receive and respond to generic structural change messages + ** ("tree diff"). + ** + ** Each concrete TreeMutator instance will be configured differently, and this + ** adaptation is done by combining various building blocks. This header defines + ** a special `/dev/null` building block, which behaves as if successfully consuming + ** the given diff without actually doing anything. Obviously, such a "black hole layer" + ** need to be below any other diff binding, and may be used to absorb any diff verbs + ** not matched and consumed by a more specific binding. Contrast this to the TreeMutator + ** default implementation, which likewise absorbs diff verbs, but in a way to trigger + ** a lumiera::error::LUMIERA_ERROR_DIFF_CONFLICT. + ** + ** @note the header tree-mutator-attribute-binding.hpp was split off for sake of readability + ** and is included automatically from bottom of tree-mutator.hpp + ** + ** @see tree-mutator-test.cpp + ** @see TreeMutator::build() + ** + */ + + +#ifndef LIB_DIFF_TREE_MUTATOR_NOOP_BINDING_H +#define LIB_DIFF_TREE_MUTATOR_NOOP_BINDING_H + + +#include "lib/error.hpp" +#include "lib/symbol.hpp" +#include "lib/diff/gen-node.hpp" +#include "lib/diff/tree-mutator.hpp" +#include "lib/format-string.hpp" +#include "lib/idi/entry-id.hpp" + +#include + + +namespace lib { +namespace diff{ + + namespace { // Mutator-Builder decorator components... + + + /** + * Diff binding for black holes, happily accepting anything. + * @note absorbs and silently ignores any diff verb. + */ + template + class BlackHoleMutation + : public PAR + { + + + public: + BlackHoleMutation (PAR&& chain) + : PAR{std::forward(chain)} + { } + + + }; + + + + /** Entry point for DSL builder */ + template + inline auto + Builder::ignoreAllChanges() + { + return chainedBuilder>(); + } + + + + }//(END)Mutator-Builder decorator components... + +}} // namespace lib::diff +#endif /*LIB_DIFF_TREE_MUTATOR_NOOP_BINDING_H*/ diff --git a/src/lib/diff/tree-mutator.hpp b/src/lib/diff/tree-mutator.hpp index 4a5c0df61..4e11d98c2 100644 --- a/src/lib/diff/tree-mutator.hpp +++ b/src/lib/diff/tree-mutator.hpp @@ -156,7 +156,7 @@ namespace diff{ /** initialisation immediately before start of diff application * @remark allows for setup of state which is dependent on memory location, - * like e.g. iterators. Due to the invokation via Builder DSL, the + * like e.g. iterators. Due to the invocation via Builder DSL, the * implementation object may be moved after construction, but prior * to invoking this hook */ @@ -439,6 +439,9 @@ namespace diff{ */ auto attachDummy (TestMutationTarget& dummy); + + /** set up a catch-all and ignore-everything layer */ + auto ignoreAllChanges(); }; }//(END) Mutator-Builder... @@ -460,4 +463,5 @@ namespace diff{ #include "lib/diff/tree-mutator-gen-node-binding.hpp" #include "lib/diff/tree-mutator-attribute-binding.hpp" #include "lib/diff/tree-mutator-collection-binding.hpp" +#include "lib/diff/tree-mutator-noop-binding.hpp" diff --git a/tests/15library.tests b/tests/15library.tests index c2a94f0cb..03944a017 100644 --- a/tests/15library.tests +++ b/tests/15library.tests @@ -122,6 +122,11 @@ return: 0 END +TEST "Diff: accept and ignore arbitrary diff" DiffIgnoreChanges_test < + + 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-ignore-changes-test.cpp + ** unit test \ref DiffIgnoreChanges_test. + ** Covers the special case of a TreeMutator configured to accept + ** any diff without actually doing anything. + */ + + +#include "lib/test/run.hpp" +#include "lib/test/test-helper.hpp" +#include "lib/format-util.hpp" +#include "lib/diff/tree-diff-application.hpp" +#include "lib/diff/test-mutation-target.hpp" +#include "lib/format-string.hpp" +#include "lib/format-cout.hpp" +#include "lib/util.hpp" + +#include + +using lib::iter_stl::snapshot; +using lib::time::Time; +using std::string; + + +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", "ξ"), // a "magic" type attribute "Xi" + TYPE_Z("type", "ζ"), // + 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 δ + GAMMA_PI("γ", 3.14159265); // happens to have the same identity (ID) as ATTRIB3 + + }//(End)Test fixture + + + + + + + + /**************************************************************************//** + * @test Special case: build a TreeMutator to accept any change and do nothing. + * + * @note for sake of symmetry, this test uses the same verb sequence used in + * all the other tree diff tests, assuming this sequence covers pretty + * much all features supported by the tree diff language. + * + * @see DiffComplexApplication_test test case which _indeed does a lot..._ + * @see TreeMutator_test base operations of the adapter + * @see diff-tree-application.hpp + * @see tree-diff.hpp + */ + class DiffIgnoreChanges_test + : public Test + , TreeDiffLanguage + { + using DiffSeq = iter_stl::IterSnapshot; + + DiffSeq + populationDiff() + { + return snapshot({ins(ATTRIB1) + , ins(ATTRIB3) + , ins(ATTRIB3) + , ins(CHILD_B) + , ins(CHILD_B) + , ins(CHILD_T) + }); + } // ==> ATTRIB1, ATTRIB3, (ATTRIB3), CHILD_B, CHILD_B, CHILD_T + + DiffSeq + reorderingDiff() + { + return snapshot({after(Ref::ATTRIBS) + , ins(ATTRIB2) + , del(CHILD_B) + , ins(SUB_NODE) + , find(CHILD_T) + , pick(CHILD_B) + , skip(CHILD_T) + }); + } // ==> ATTRIB1, ATTRIB3, (ATTRIB3), ATTRIB2, SUB_NODE, CHILD_T, CHILD_B + + DiffSeq + mutationDiff() + { + return snapshot({after(CHILD_B) + , after(Ref::END) + , set(GAMMA_PI) + , mut(SUB_NODE) + , ins(TYPE_X) + , ins(ATTRIB2) + , ins(CHILD_B) + , ins(CHILD_A) + , emu(SUB_NODE) + , ins(ATTRIB_NODE) + , mut(ATTRIB_NODE) + , ins(TYPE_Z) + , ins(CHILD_A) + , ins(CHILD_A) + , ins(CHILD_A) + , emu(ATTRIB_NODE) + }); + } // ==> ATTRIB1, ATTRIB3 := π, (ATTRIB3), ATTRIB2, + // ATTRIB_NODE{ type ζ, CHILD_A, CHILD_A, CHILD_A } + // SUB_NODE{ type ξ, ATTRIB2, CHILD_B, CHILD_A }, + // CHILD_T, CHILD_B + + + + + virtual void + run (Arg) + { + struct HappyBlackHole + { + bool grumpy = true; + + void + buildMutator (TreeMutator::Handle buff) + { + if (grumpy) + buff.create( + TreeMutator()); + else + buff.create( + TreeMutator::build() + .ignoreAllChanges()); + } + }; + + HappyBlackHole subject; + DiffApplicator application(subject); + + VERIFY_ERROR(DIFF_CONFLICT, application.consume(populationDiff()) ); + VERIFY_ERROR(DIFF_CONFLICT, application.consume(reorderingDiff()) ); + VERIFY_ERROR(DIFF_CONFLICT, application.consume(mutationDiff()) ); + + subject.grumpy = false; + + application.consume(populationDiff()); + application.consume(reorderingDiff()); + application.consume(mutationDiff()); + } + }; + + + /** Register this test class... */ + LAUNCHER (DiffIgnoreChanges_test, "unit common"); + + + +}}} // namespace lib::diff::test diff --git a/wiki/thinkPad.ichthyo.mm b/wiki/thinkPad.ichthyo.mm index d1b27e54d..8873e718f 100644 --- a/wiki/thinkPad.ichthyo.mm +++ b/wiki/thinkPad.ichthyo.mm @@ -16549,6 +16549,66 @@ + + + + + + + + + + + + + +

+ ...welches in eine Kind-Timeline absteigt, +

+

+ welche gegenwärtig im GUI nicht existiert +

+

+ und daher auf "inaktiv" geschaltet ist. +

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