From e00d6c2a4c136bde0bfe7216e6e8828c20f144f6 Mon Sep 17 00:00:00 2001 From: Ichthyostega Date: Fri, 2 Sep 2016 01:29:32 +0200 Subject: [PATCH] reorganise inclusion of TreeMutator-DSL builders previously they where included in the middle of tree-mutator.hpp This was straight forward, since the builder relies on the classes defined in the detail headers. However, the GenNode-binding needs to use a specifically configured collection binding, and this in turn requires writing a recursive lambda to deal with nested scopes. This gets us into trouble with circular definition dependencies. As a workaround we now only *declare* the DSL builder functions in the tree-mutator-builder object, and additionally use auto on all return types. This allows us to spell out the complete builder definition, without mentioning any of the implementation classes. Obviously, the detail headers have then to be included *after* the builder definition, at bottom of tree-mutator.hpp This also allows us to turn these implementation headers into completely normal headers, with namespaces and transitive #includes In the end, the whole setup looks much more "innocent" now. But beware: the #include of the implementation headers at bottom of tree-mutator.hpp needs to be given in reverse dependency order, due to the circular inclusion (back to tree-mutator.hpp) in conjunction with the inclusion guards! --- src/lib/diff/test-mutation-target.hpp | 4 +- src/lib/diff/tree-diff-traits.hpp | 4 +- .../diff/tree-mutator-attribute-binding.hpp | 50 ++++++++++-- .../diff/tree-mutator-collection-binding.hpp | 37 +++++++-- .../diff/tree-mutator-gen-node-binding.hpp | 57 +++++++------ src/lib/diff/tree-mutator.hpp | 80 +++++++++---------- 6 files changed, 141 insertions(+), 91 deletions(-) diff --git a/src/lib/diff/test-mutation-target.hpp b/src/lib/diff/test-mutation-target.hpp index beee23d35..4f9f79d4d 100644 --- a/src/lib/diff/test-mutation-target.hpp +++ b/src/lib/diff/test-mutation-target.hpp @@ -528,10 +528,10 @@ namespace diff{ template - Builder> + auto Builder::attachDummy (TestMutationTarget& dummy) { - return WireTap (dummy, move(*this)); + return chainedBuilder> (dummy); } } diff --git a/src/lib/diff/tree-diff-traits.hpp b/src/lib/diff/tree-diff-traits.hpp index 4f942df3b..9914a5e2b 100644 --- a/src/lib/diff/tree-diff-traits.hpp +++ b/src/lib/diff/tree-diff-traits.hpp @@ -208,8 +208,8 @@ namespace diff{ * the return value in local scope as long as necessary */ template - auto - mutatorBinding (TAR& subject) -> typename TreeDiffTraits::Ret + typename TreeDiffTraits::Ret + mutatorBinding (TAR& subject) { using Wrapper = typename TreeDiffTraits::Ret; return Wrapper{subject}; diff --git a/src/lib/diff/tree-mutator-attribute-binding.hpp b/src/lib/diff/tree-mutator-attribute-binding.hpp index 1167e6dfb..588a7a10d 100644 --- a/src/lib/diff/tree-mutator-attribute-binding.hpp +++ b/src/lib/diff/tree-mutator-attribute-binding.hpp @@ -84,9 +84,8 @@ ** constructing the concrete TreeMutator needs to have adequate understanding ** regarding mode of operation and "mechanics" of such a binding. ** - ** @note the header tree-mutator-attribute-binding.hpp with specific builder templates - ** is included way down, after the class definitions. This is done so for sake - ** of readability. + ** @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() @@ -96,13 +95,22 @@ #ifndef LIB_DIFF_TREE_MUTATOR_ATTRIBUTE_BINDING_H #define LIB_DIFF_TREE_MUTATOR_ATTRIBUTE_BINDING_H -#ifndef LIB_DIFF_TREE_MUTATOR_H - #error "this header shall not be used standalone (see tree-mutator.hpp)" -#endif - -//== anonymous namespace... +#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... /** @@ -333,4 +341,30 @@ }; + + /** Entry point for DSL builder */ + template + template + inline auto + Builder::change (Symbol attributeID, CLO setterClosure) + { + return chainedBuilder> (attributeID, setterClosure); + } + + + /** Entry point for DSL builder */ + template + template + inline auto + Builder::mutateAttrib (Symbol attributeID, CLO mutatorBuilderClosure) + { + idi::EntryID key{attributeID}; + return chainedBuilder> (key, mutatorBuilderClosure); + } + + + + }//(END)Mutator-Builder decorator components... + +}} // namespace lib::diff #endif /*LIB_DIFF_TREE_MUTATOR_ATTRIBUTE_BINDING_H*/ diff --git a/src/lib/diff/tree-mutator-collection-binding.hpp b/src/lib/diff/tree-mutator-collection-binding.hpp index a8041e169..8f98e8eb1 100644 --- a/src/lib/diff/tree-mutator-collection-binding.hpp +++ b/src/lib/diff/tree-mutator-collection-binding.hpp @@ -35,9 +35,8 @@ ** a building block for one such layer, especially for binding to a representation ** of "child objects" managed within a typical STL container. ** - ** @note the header tree-mutator-collection-binding.hpp with specific builder templates - ** is included way down, after the class definitions. This is done so for sake - ** of readability. + ** @note the header tree-mutator-collection-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() @@ -47,13 +46,21 @@ #ifndef LIB_DIFF_TREE_MUTATOR_COLLECTION_BINDING_H #define LIB_DIFF_TREE_MUTATOR_COLLECTION_BINDING_H -#ifndef LIB_DIFF_TREE_MUTATOR_H - #error "this header shall not be used standalone (see tree-mutator.hpp)" -#endif +#include "lib/error.hpp" +#include "lib/meta/trait.hpp" +#include "lib/diff/gen-node.hpp" +#include "lib/diff/tree-mutator.hpp" +#include "lib/iter-adapter-stl.hpp" -//== anonymous namespace... +#include + + +namespace lib { +namespace diff{ + + namespace { // Mutator-Builder decorator components... @@ -447,6 +454,7 @@ } + template struct _EmptyBinding { @@ -589,7 +597,7 @@ * using lambdas as callback into the otherwise opaque implementation code. */ template - auto + inline auto collection (COLL& coll) { using Elm = typename COLL::value_type; @@ -599,4 +607,17 @@ + /** Entry point for DSL builder */ + template + template + inline auto + Builder::attach (BIN&& collectionBindingSetup) + { + return chainedBuilder> (forward(collectionBindingSetup)); + } + + + }//(END)Mutator-Builder decorator components... + +}} // namespace lib::diff #endif /*LIB_DIFF_TREE_MUTATOR_COLLECTION_BINDING_H*/ diff --git a/src/lib/diff/tree-mutator-gen-node-binding.hpp b/src/lib/diff/tree-mutator-gen-node-binding.hpp index 0fa172cb6..e55c3ca5b 100644 --- a/src/lib/diff/tree-mutator-gen-node-binding.hpp +++ b/src/lib/diff/tree-mutator-gen-node-binding.hpp @@ -32,8 +32,8 @@ ** Each concrete TreeMutator instance will be configured differently, and this ** adaptation is done by implementing binding templates, in the way of building ** blocks, layered on top of each other. This header defines a special setup, based - ** on the two layered bindings for STL collections. The reason is that our »External - ** Tree Description« of object-like structures is comprised of recursively nested + ** on two layered bindings for STL collections. The reason is that our »External + ** Tree Description« of object-like structures is comprised of recursively nested ** Record to represent "objects", and this representation is actually implemented ** internally based on two collections -- one to hold the _attributes_ and one to hold the ** _children._ So this special setup relies on implementation inside knowledge to apply @@ -44,9 +44,8 @@ ** structure of our _diff language_ -- thus it is sufficient just to layer two collection ** bindings, together with suitable closures (lambdas) for layer selection, matching, etc. ** - ** @note the header tree-mutator-collection-binding.hpp with specific builder templates - ** is included way down, after the class definitions. This is done so for sake - ** of readability. + ** @note the header tree-mutator-collection-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() @@ -56,16 +55,19 @@ #ifndef LIB_DIFF_TREE_MUTATOR_GEN_NODE_BINDING_H #define LIB_DIFF_TREE_MUTATOR_GEN_NODE_BINDING_H -#ifndef LIB_DIFF_TREE_MUTATOR_H - #error "this header shall not be used standalone (see tree-mutator.hpp)" -#endif +#include "lib/diff/gen-node.hpp" +#include "lib/diff/tree-mutator-collection-binding.hpp" +#include "lib/diff/tree-mutator.hpp" -//== anonymous namespace... - - - +#include + + +namespace lib { +namespace diff{ + + namespace { // Mutator-Builder decorator components... using Storage = RecordSetup::Storage; @@ -83,26 +85,23 @@ return std::get<1> (targetTree.exposeToDiff()); } - /** - * Attach to GenNode tree: Special setup to build a concrete `TreeMutator`. - * This decorator is already outfitted with the necessary closures to work on - * a diff::Record -- which is typically used as "meta representation" - * of object-like structures. Thus this binding allows to apply a diff message - * onto such a given »External Tree Description«, mutating it into new shape. - */ + + + /** Entry point for DSL builder */ template inline auto - twoLayeredGenNodeTreeMutator (Rec::Mutator& targetTree, PAR&& builderBase) + Builder::attach (Rec::Mutator& targetTree) { - return builderBase - .attach (collection (accessChildren(targetTree))) - .attach (collection (accessAttribs(targetTree))) - .isApplicableIf ([&](GenNode const& spec) - { - return spec.isNamed(); // »Selector« : treat key-value elements here - }); + return this-> attach (collection (accessChildren(targetTree))) + .attach (collection (accessAttribs(targetTree))) + .isApplicableIf ([&](GenNode const& spec) + { + return spec.isNamed(); // »Selector« : treat key-value elements here + }); } - - + }//(END)Mutator-Builder decorator components... + + +}} // namespace lib::diff #endif /*LIB_DIFF_TREE_MUTATOR_GEN_NODE_BINDING_H*/ diff --git a/src/lib/diff/tree-mutator.hpp b/src/lib/diff/tree-mutator.hpp index 7b8cf3824..6884f8548 100644 --- a/src/lib/diff/tree-mutator.hpp +++ b/src/lib/diff/tree-mutator.hpp @@ -324,6 +324,9 @@ namespace diff{ }; + + + namespace { // Mutator-Builder decorator components... using lib::meta::Strip; @@ -374,16 +377,7 @@ namespace diff{ - /* == implementation detail headers == */ -#include "lib/diff/tree-mutator-attribute-binding.hpp" -#include "lib/diff/tree-mutator-collection-binding.hpp" -#include "lib/diff/tree-mutator-gen-node-binding.hpp" - - - - template - struct TestWireTap; /** @@ -402,16 +396,13 @@ namespace diff{ : PAR{forward (par)} { } - template - using Change = ChangeOperation; + template + Builder + chainedBuilder (ARGS&&...args) + { + return Builder (BIN{forward(args)..., move(*this)}); + } - template - using MutateAttrib = MutationOperation; - - template - using Collection = ChildCollectionMutator; - - using WireTap = TestWireTap; /* ==== binding API ==== */ @@ -434,13 +425,12 @@ namespace diff{ * "applicable" to this attribute and binding. Similar to * GenNode, the provided attributeID is used as-is, * without further sanitising. + * @return a _chained builder,_ which establishes this building and + * can then be used to define additional binding layers on top */ template - Builder> - change (Symbol attributeID, CLO setterClosure) - { - return Change (attributeID, setterClosure, move(*this)); - } + auto change (Symbol attributeID, CLO setterClosure); + /** set up a binding for an object valued "attribute" or _named scope_. * This covers the rather special case, where some relevant sub object is @@ -458,12 +448,7 @@ namespace diff{ * @see CollectionBindingBuilder::buildChildMutator */ template - Builder> - mutateAttrib (Symbol attributeID, CLO mutatorBuilderClosure) - { - idi::EntryID key{attributeID}; - return MutateAttrib (key, mutatorBuilderClosure, move(*this)); - } + auto mutateAttrib (Symbol attributeID, CLO mutatorBuilderClosure); ///////////////////////////////////////TODO define variant taking a GenNode::ID ?? @@ -498,30 +483,33 @@ namespace diff{ * this nested mutator until encountering the corresponding `EMU` bracket verb. */ template - Builder> - attach (BIN&& collectionBindingSetup) - { - return Collection {forward(collectionBindingSetup), move(*this)}; - } + auto attach (BIN&& collectionBindingSetup); + + + /** set up binding to a GenNode tree: Special setup to build a concrete `TreeMutator`. + * This decorator is already outfitted with the necessary closures to work on a + * diff::Record -- which is typically used as "meta representation" of + * object-like structures. Thus this binding allows to apply a diff message onto + * such a given »External Tree Description«, mutating it into new shape. + * @remarks our meta representation of "objects" is based on Record, which + * is implemented through two STL collections, one for the attributes and + * one for the child elements. Thus we'll using two binding layers, based + * on the ChildCollectionMutator, configured with the necessary lambdas. + */ + auto attach (Rec::Mutator& targetTree); - auto - attach (Rec::Mutator& targetTree) - { - return twoLayeredGenNodeTreeSetup (targetTree, move(*this)); - } /** set up a diagnostic layer, binding to TestMutationTarget. * This can be used to monitor the behaviour of the resulting TreeMutator for tests. */ - Builder - attachDummy (TestMutationTarget& dummy); + auto attachDummy (TestMutationTarget& dummy); }; }//(END) Mutator-Builder... - Builder + inline Builder TreeMutator::build () { return TreeMutator(); @@ -530,3 +518,11 @@ namespace diff{ }} // namespace lib::diff #endif /*LIB_DIFF_TREE_MUTATOR_H*/ + + + /* == implementation detail headers == */ + +#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" +