From ed18e1161c163fb75d5cbd5de7ebad937a749a76 Mon Sep 17 00:00:00 2001 From: Ichthyostega Date: Thu, 28 Jul 2016 01:17:50 +0200 Subject: [PATCH] WIP: code organisation - double layered architecture --- src/lib/diff/tree-diff-application.hpp | 25 ++ src/lib/diff/tree-diff-mutator-binding.cpp | 78 +++--- src/lib/diff/tree-diff-mutator-binding.hpp | 83 +----- src/lib/diff/tree-diff-traits.hpp | 131 +++++++++ .../diff-virtualised-application-test.cpp | 2 +- wiki/thinkPad.ichthyo.mm | 254 +++++++++++++++++- 6 files changed, 446 insertions(+), 127 deletions(-) create mode 100644 src/lib/diff/tree-diff-traits.hpp diff --git a/src/lib/diff/tree-diff-application.hpp b/src/lib/diff/tree-diff-application.hpp index 6a22146c5..387564742 100644 --- a/src/lib/diff/tree-diff-application.hpp +++ b/src/lib/diff/tree-diff-application.hpp @@ -103,6 +103,8 @@ #include "lib/diff/tree-diff.hpp" +#include "lib/diff/tree-diff-traits.hpp" +#include "lib/diff/tree-diff-mutator-binding.hpp" #include "lib/diff/gen-node.hpp" #include "lib/format-string.hpp" #include "lib/util.hpp" @@ -120,6 +122,29 @@ namespace diff{ using std::swap; + + /** + * Interpreter for the tree-diff-language to work on arbitrary + * opaque target data structures. A concrete strategy to apply a structural diff + * to otherwise undisclosed, recursive, tree-like target data. The only requirement + * is for this target structure to expose a hook for building a customised + * TreeMutator able to work on and transform the private target data. + * @throws lumiera::error::State when diff application fails due to the + * target sequence being different than assumed by the given diff. + * @see #TreeDiffInterpreter explanation of the verbs + */ + template<> + class DiffApplicationStrategy + : public TreeDiffMutatorBinding + { + public: + explicit + DiffApplicationStrategy(DiffMutable& targetBinding) + : TreeDiffMutatorBinding(targetBinding) + { } + }; + + /** * Interpreter for the tree-diff-language to work on GenNode elements * A concrete strategy to apply a structural diff to a target data structure diff --git a/src/lib/diff/tree-diff-mutator-binding.cpp b/src/lib/diff/tree-diff-mutator-binding.cpp index 33070735c..7bf13f4a8 100644 --- a/src/lib/diff/tree-diff-mutator-binding.cpp +++ b/src/lib/diff/tree-diff-mutator-binding.cpp @@ -64,7 +64,7 @@ namespace diff{ using Iter = Content::Iter; template<> - struct DiffApplicationStrategy::ScopeFrame + struct TreeDiffMutatorBinding::ScopeFrame { Mutator& target; Content content; @@ -94,7 +94,7 @@ namespace diff{ void - DiffApplicationStrategy::__expect_in_target (GenNode const& elm, Literal oper) + TreeDiffMutatorBinding::__expect_in_target (GenNode const& elm, Literal oper) { if (endOfData()) throw error::State(_Fmt("Unable to %s element %s from target as demanded; " @@ -112,7 +112,7 @@ namespace diff{ } void - DiffApplicationStrategy::__expect_further_elements (GenNode const& elm) + TreeDiffMutatorBinding::__expect_further_elements (GenNode const& elm) { if (endOfData()) throw error::State(_Fmt("Premature end of target sequence, still expecting element %s; " @@ -121,7 +121,7 @@ namespace diff{ } void - DiffApplicationStrategy::__expect_found (GenNode const& elm, Iter const& targetPos) + TreeDiffMutatorBinding::__expect_found (GenNode const& elm, Iter const& targetPos) { if (targetPos == src().end()) throw error::State(_Fmt("Premature end of sequence; unable to locate " @@ -130,7 +130,7 @@ namespace diff{ } void - DiffApplicationStrategy::__expect_successful_location (GenNode const& elm) + TreeDiffMutatorBinding::__expect_successful_location (GenNode const& elm) { if (endOfData() and not ( elm.matches(Ref::END) // after(_END_) -> its OK we hit the end @@ -140,7 +140,7 @@ namespace diff{ } void - DiffApplicationStrategy::__expect_valid_parent_scope (GenNode::ID const& idi) + TreeDiffMutatorBinding::__expect_valid_parent_scope (GenNode::ID const& idi) { if (scopes_.empty()) throw error::State(_Fmt("Unbalanced child scope bracketing tokens in diff; " @@ -154,7 +154,7 @@ namespace diff{ } void - DiffApplicationStrategy::__expect_end_of_scope (GenNode::ID const& idi) + TreeDiffMutatorBinding::__expect_end_of_scope (GenNode::ID const& idi) { if (not endOfData()) throw error::State(_Fmt("Incomplete diff: when about to leave scope %s, " @@ -165,7 +165,7 @@ namespace diff{ Iter - DiffApplicationStrategy::find_in_current_scope (GenNode const& elm) + TreeDiffMutatorBinding::find_in_current_scope (GenNode const& elm) { Iter end_of_scope = src().currIsAttrib()? src().attribs.end() : src().children.end(); @@ -178,7 +178,7 @@ namespace diff{ } GenNode const& - DiffApplicationStrategy::find_child (GenNode::ID const& idi) + TreeDiffMutatorBinding::find_child (GenNode::ID const& idi) { if (alteredRec().empty()) throw error::State(_Fmt("Attempt to mutate element %s, but current target data scope is empty. " @@ -204,7 +204,7 @@ namespace diff{ } void - DiffApplicationStrategy::move_into_new_sequence (Iter pos) + TreeDiffMutatorBinding::move_into_new_sequence (Iter pos) { if (src().currIsAttrib()) out().appendAttrib (move(*pos)); //////////////TICKET #969 was it a good idea to allow adding attributes "after the fact"? @@ -216,31 +216,31 @@ namespace diff{ /* == Forwarding: error handling == */ void - DiffApplicationStrategy::__expect_in_target (GenNode const& elm, Literal oper) + TreeDiffMutatorBinding::__expect_in_target (GenNode const& elm, Literal oper) { } void - DiffApplicationStrategy::__expect_further_elements (GenNode const& elm) + TreeDiffMutatorBinding::__expect_further_elements (GenNode const& elm) { } void - DiffApplicationStrategy::__fail_not_found (GenNode const& elm) + TreeDiffMutatorBinding::__fail_not_found (GenNode const& elm) { } void - DiffApplicationStrategy::__expect_end_of_scope (GenNode::ID const& idi) + TreeDiffMutatorBinding::__expect_end_of_scope (GenNode::ID const& idi) { } void - DiffApplicationStrategy::__expect_valid_parent_scope (GenNode::ID const& idi) + TreeDiffMutatorBinding::__expect_valid_parent_scope (GenNode::ID const& idi) { } @@ -249,55 +249,55 @@ namespace diff{ /* == Forwarding: mutation primitives == */ void - DiffApplicationStrategy::skipSrc() + TreeDiffMutatorBinding::skipSrc() { UNIMPLEMENTED("skip next src element and advance abstract source position"); } void - DiffApplicationStrategy::injectNew (GenNode const& n) + TreeDiffMutatorBinding::injectNew (GenNode const& n) { UNIMPLEMENTED("inject a new element at current abstract position"); } bool - DiffApplicationStrategy::matchSrc (GenNode const& n) + TreeDiffMutatorBinding::matchSrc (GenNode const& n) { UNIMPLEMENTED("ensure the next source element matches with given spec"); } bool - DiffApplicationStrategy::acceptSrc (GenNode const& n) + TreeDiffMutatorBinding::acceptSrc (GenNode const& n) { UNIMPLEMENTED("accept existing element, when matching the given spec"); } bool - DiffApplicationStrategy::findSrc (GenNode const& n) + TreeDiffMutatorBinding::findSrc (GenNode const& n) { UNIMPLEMENTED("locate designated element and accept it at current position"); } bool - DiffApplicationStrategy::accept_until (GenNode const& refMark) + TreeDiffMutatorBinding::accept_until (GenNode const& refMark) { UNIMPLEMENTED("repeatedly accept until encountering the mark"); } void - DiffApplicationStrategy::assignElm (GenNode const& n) + TreeDiffMutatorBinding::assignElm (GenNode const& n) { UNIMPLEMENTED("locate already accepted element and assign given new payload"); } void - DiffApplicationStrategy::open_subScope (GenNode const& n) + TreeDiffMutatorBinding::open_subScope (GenNode const& n) { UNIMPLEMENTED("locate already accepted element and open recursive sub-scope for mutation"); } void - DiffApplicationStrategy::close_subScope() + TreeDiffMutatorBinding::close_subScope() { UNIMPLEMENTED("finish and leave sub scope and return to invoking parent scope"); } @@ -307,38 +307,38 @@ namespace diff{ /* == Implementation of the list diff application primitives == */ void - DiffApplicationStrategy::ins (GenNode const& n) + TreeDiffMutatorBinding::ins (GenNode const& n) { injectNew (n); } void - DiffApplicationStrategy::del (GenNode const& n) + TreeDiffMutatorBinding::del (GenNode const& n) { __expect_in_target(n, "remove"); skipSrc(); } void - DiffApplicationStrategy::pick (GenNode const& n) + TreeDiffMutatorBinding::pick (GenNode const& n) { __expect_in_target(n, "pick"); acceptSrc (n); } void - DiffApplicationStrategy::skip (GenNode const& n) + TreeDiffMutatorBinding::skip (GenNode const& n) { __expect_further_elements (n); skipSrc(); } // assume the actual content has been moved away by a previous find() void - DiffApplicationStrategy::find (GenNode const& n) + TreeDiffMutatorBinding::find (GenNode const& n) { __expect_further_elements (n); // consume and leave waste, expected to be cleaned-up by skip() later - if (not findSrc(n)); + if (not this->findSrc(n)); __fail_not_found (n); } @@ -349,7 +349,7 @@ namespace diff{ * thereby picking (accepting) all traversed elements * into the reshaped new data structure as-is */ void - DiffApplicationStrategy::after (GenNode const& n) + TreeDiffMutatorBinding::after (GenNode const& n) { if (not accept_until(n)) __fail_not_found (n); @@ -357,14 +357,14 @@ namespace diff{ /** assignment of changed value in one step */ void - DiffApplicationStrategy::set (GenNode const& n) + TreeDiffMutatorBinding::set (GenNode const& n) { assignElm (n); } /** open nested scope to apply diff to child object */ void - DiffApplicationStrategy::mut (GenNode const& n) + TreeDiffMutatorBinding::mut (GenNode const& n) { open_subScope (n); @@ -376,7 +376,7 @@ namespace diff{ /** finish and leave child object scope, return to parent */ void - DiffApplicationStrategy::emu (GenNode const& n) + TreeDiffMutatorBinding::emu (GenNode const& n) { #if false /////////////////////////////////////////////////////////////////////////////////////////////////////////////UNIMPLEMENTED :: TICKET #992 TRACE (diff, "tree-diff: LEAVE scope %s", cStr(describeScope())); @@ -390,7 +390,7 @@ namespace diff{ void - DiffApplicationStrategy::initDiffApplication() + TreeDiffMutatorBinding::initDiffApplication() { TODO("(re)initialise the diff application machinery"); #if false /////////////////////////////////////////////////////////////////////////////////////////////////////////////UNIMPLEMENTED :: TICKET #992 @@ -401,14 +401,6 @@ namespace diff{ - /* ==== trigger code generation of the generic part ==== */ - - /************************************************************************/ - /* explicit template instantiation DiffApplicationStrategy */ - /************************************************************************/ - - template class DiffApplicationStrategy; - }} // namespace lib::diff diff --git a/src/lib/diff/tree-diff-mutator-binding.hpp b/src/lib/diff/tree-diff-mutator-binding.hpp index f27baf741..670f3f84f 100644 --- a/src/lib/diff/tree-diff-mutator-binding.hpp +++ b/src/lib/diff/tree-diff-mutator-binding.hpp @@ -94,80 +94,6 @@ namespace lib { namespace diff{ - /* ======= derive a TreeMutator binding for a given opaque data structure ======= */ - - - using meta::enable_if; - using meta::Yes_t; - using meta::No_t; - using std::is_same; - - /** - * helper to detect presence of a - * TreeMutator builder function - */ - template - class exposes_MutatorBuilder - { - - META_DETECT_FUNCTION (void, buildMutator, (TreeMutator::Handle)); - - public: - enum{ value = HasFunSig_buildMutator::value - }; - }; - - - - - - template - struct MutatorBinding - { - static_assert (!sizeof(TAR), "MutatorBinding: Unable to access or build a TreeMutator for this target data."); - }; - - template - struct MutatorBinding>> - { - using Ret = DiffMutable&; - }; - - template - struct MutatorBinding>> - { - class Wrapper - : public DiffMutable - { - TAR& subject_; - - /** implement the TreeMutator interface, - * by forwarding to a known implementation function - * on the wrapped target data type */ - virtual void - buildMutator (TreeMutator::Handle handle) - { - subject_.buildMutator (handle); - } - - public: - Wrapper(TAR& subj) - : subject_(subj) - { } - }; - - using Ret = Wrapper; - }; - - template - auto - mutatorBinding (TAR& subject) -> typename MutatorBinding::Ret - { - using Wrapper = typename MutatorBinding::Ret; - return Wrapper{subject}; - } - - /* ======= Implementation of Tree Diff Application via TreeMutator ======= */ @@ -190,8 +116,7 @@ namespace diff{ * @see TreeDiffInterpreter explanation of the verbs * @see DiffVirtualisedApplication_test demonstration of usage */ - template<> - class DiffApplicationStrategy + class TreeDiffMutatorBinding : public TreeDiffInterpreter { #if false /////////////////////////////////////////////////////////////////////////////////////////////////////////////UNIMPLEMENTED :: TICKET #992 @@ -286,7 +211,7 @@ namespace diff{ public: explicit - DiffApplicationStrategy(DiffMutable& targetBinding) + TreeDiffMutatorBinding(DiffMutable& targetBinding) { TODO("attach to the given Target"); #if false /////////////////////////////////////////////////////////////////////////////////////////////////////////////UNIMPLEMENTED :: TICKET #992 @@ -299,9 +224,5 @@ namespace diff{ - /** use the explicit instantiation provided in library module */ - extern template class DiffApplicationStrategy; - - }} // namespace lib::diff #endif /*LIB_DIFF_TREE_DIFF_MUTATOR_BINDING_H*/ diff --git a/src/lib/diff/tree-diff-traits.hpp b/src/lib/diff/tree-diff-traits.hpp new file mode 100644 index 000000000..3e8223f42 --- /dev/null +++ b/src/lib/diff/tree-diff-traits.hpp @@ -0,0 +1,131 @@ +/* + TREE-DIFF-TRAITS.hpp - definitions to control tree mutator binding + + Copyright (C) Lumiera.org + 2016, 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-diff-traits.hpp + ** Definitions and Properties to guide automated tree mutator binding. + ** Decision how to access the target structure and how to construct + ** a suitable TreeMutator as attached to this opaque target data. + ** + ** @todo this is WIP as of 8/2016 + ** + ** @see DiffVirtualisedApplication_test + ** @see DiffTreeApplication_test + ** @see DiffListApplication_test + ** @see GenNodeBasic_test + ** @see tree-diff.hpp + ** + */ + + +#ifndef LIB_DIFF_TREE_DIFF_TRAITS_H +#define LIB_DIFF_TREE_DIFF_TRAITS_H + + +#include "lib/diff/tree-mutator.hpp" +#include "lib/diff/diff-mutable.hpp" +#include "lib/util.hpp" + +#include +#include + +namespace lib { +namespace diff{ + + /* ======= derive a TreeMutator binding for a given opaque data structure ======= */ + + + using meta::enable_if; + using meta::Yes_t; + using meta::No_t; + using std::is_same; + + /** + * helper to detect presence of a + * TreeMutator builder function + */ + template + class exposes_MutatorBuilder + { + + META_DETECT_FUNCTION (void, buildMutator, (TreeMutator::Handle)); + + public: + enum{ value = HasFunSig_buildMutator::value + }; + }; + + + + + + template + struct TreeDiffTraits + { + static_assert (!sizeof(TAR), "TreeDiffTraits: Unable to access or build a TreeMutator for this target data."); + }; + + template + struct TreeDiffTraits>> + { + using Ret = DiffMutable&; + }; + + template + struct TreeDiffTraits>> + { + class Wrapper + : public DiffMutable + { + TAR& subject_; + + /** implement the TreeMutator interface, + * by forwarding to a known implementation function + * on the wrapped target data type */ + virtual void + buildMutator (TreeMutator::Handle handle) + { + subject_.buildMutator (handle); + } + + public: + Wrapper(TAR& subj) + : subject_(subj) + { } + }; + + using Ret = Wrapper; + }; + + template + auto + mutatorBinding (TAR& subject) -> typename TreeDiffTraits::Ret + { + using Wrapper = typename TreeDiffTraits::Ret; + return Wrapper{subject}; + } + + + + +}} // namespace lib::diff +#endif /*LIB_DIFF_TREE_DIFF_TRAITS_H*/ diff --git a/tests/library/diff/diff-virtualised-application-test.cpp b/tests/library/diff/diff-virtualised-application-test.cpp index bb99ee832..29b262a8c 100644 --- a/tests/library/diff/diff-virtualised-application-test.cpp +++ b/tests/library/diff/diff-virtualised-application-test.cpp @@ -23,7 +23,7 @@ #include "lib/test/run.hpp" #include "lib/format-util.hpp" -#include "lib/diff/tree-diff-mutator-binding.hpp" +#include "lib/diff/tree-diff-application.hpp" #include "lib/iter-adapter-stl.hpp" #include "lib/time/timevalue.hpp" #include "lib/format-cout.hpp" //////////TODO necessary? diff --git a/wiki/thinkPad.ichthyo.mm b/wiki/thinkPad.ichthyo.mm index c13c32bcd..2925f65ae 100644 --- a/wiki/thinkPad.ichthyo.mm +++ b/wiki/thinkPad.ichthyo.mm @@ -4378,8 +4378,8 @@ - - + + @@ -4442,6 +4442,252 @@ + + + + + + + + + + + + + + + + + +

+ nicht generisch: mutatorBinding +

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

+ Lösungsversuch: extern template +

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

+ ...im Klartext: diesen Zugriff von der generischen Implementierung +

+

+ auf den eingebauten Stack-Mechanismus benötigen wir nur... +

+
    +
  • + einmal zu Beginn, bei der Konstruktion +
  • +
  • + wenn wir in einen geschachtelten Scope eintreten +
  • +
+

+ Zwar sind indirekte Calls aufwendiger, aber letzten Endes auch wieder nicht soooo aufwendig, +

+

+ daß sie uns im gegebenen Kontext umbringen +

+
    +
  • + wenn wir einen Solchen verlassen +
  • +
+ + +
+ +
+
+ + + + + + + + + + + + +

+ intern: eingebaute initDiffApplication() +

+ + +
+ + + + + +

+ ...wird automatisch vor Konsumieren eines Diff aufgerufen +

+ + +
+
+ + + + + + +

+ Widerspruch: TreeMutator ist Wegwerf-Objekt +

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

+ Lösungsversuch: doppelte Hülle +

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

+ kann daher TreeMutator konstruieren +

+ + +
+
+ + + + + + +

+ ...und zwar per mutatorBinding +

+ + +
+
+ + + + + + +

+ implementiert somit initDiffApplication() +

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

+ TODO: Namensgebung +

+ + +
+ + + + + + + + +
@@ -4604,6 +4850,10 @@
+ + + +