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!
107 lines
4.1 KiB
C++
107 lines
4.1 KiB
C++
/*
|
|
TREE-MUTATOR-GEN-NODE-BINDING.hpp - diff::TreeMutator implementation building block
|
|
|
|
Copyright (C) Lumiera.org
|
|
2016, Hermann Vosseler <Ichthyostega@web.de>
|
|
|
|
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-gen-node-binding.hpp
|
|
** Special binding implementation for TreeMutator, allowing to map
|
|
** tree diff operations onto an »External Tree Description«. Such is is 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
|
|
** change messages ("tree diff").
|
|
**
|
|
** 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 two layered bindings for STL collections. The reason is that our »External
|
|
** Tree Description« of object-like structures is comprised of recursively nested
|
|
** Record<GenNode> 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
|
|
** structural changes to such a representation. There is an implicit convention that
|
|
** "objects" are to be spelled out by first giving the metadata, then enumerating the
|
|
** attributes (key-value properties) and finally the child elements located within the
|
|
** scope of this "object" node. This implicit convention is in accordance with the
|
|
** 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 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_GEN_NODE_BINDING_H
|
|
#define LIB_DIFF_TREE_MUTATOR_GEN_NODE_BINDING_H
|
|
|
|
|
|
#include "lib/diff/gen-node.hpp"
|
|
#include "lib/diff/tree-mutator-collection-binding.hpp"
|
|
#include "lib/diff/tree-mutator.hpp"
|
|
|
|
#include <tuple>
|
|
|
|
|
|
namespace lib {
|
|
namespace diff{
|
|
|
|
namespace { // Mutator-Builder decorator components...
|
|
|
|
|
|
using Storage = RecordSetup<GenNode>::Storage;
|
|
|
|
|
|
inline Storage&
|
|
accessAttribs (Rec::Mutator& targetTree)
|
|
{
|
|
return std::get<0> (targetTree.exposeToDiff());
|
|
}
|
|
|
|
inline Storage&
|
|
accessChildren (Rec::Mutator& targetTree)
|
|
{
|
|
return std::get<1> (targetTree.exposeToDiff());
|
|
}
|
|
|
|
|
|
|
|
/** Entry point for DSL builder */
|
|
template<class PAR>
|
|
inline auto
|
|
Builder<PAR>::attach (Rec::Mutator& targetTree)
|
|
{
|
|
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*/
|