2016-08-31 17:09:32 +02:00
|
|
|
/*
|
|
|
|
|
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
|
2018-10-11 23:56:33 +02:00
|
|
|
** tree diff operations onto an »External Tree Description«. This term denotes a
|
2016-08-31 17:09:32 +02:00
|
|
|
** 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
|
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!
2016-09-02 01:29:32 +02:00
|
|
|
** on two layered bindings for STL collections. The reason is that our »External
|
|
|
|
|
** Tree Description« of object-like structures is comprised of recursively nested
|
2016-08-31 17:09:32 +02:00
|
|
|
** 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
|
2016-09-04 20:55:21 +02:00
|
|
|
** bindings, together with suitable closures (lambdas) for layer selection, matching, most
|
|
|
|
|
** of which is already defined for collections of GenNode elements in general
|
2016-08-31 17:09:32 +02:00
|
|
|
**
|
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!
2016-09-02 01:29:32 +02:00
|
|
|
** @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
|
2016-08-31 17:09:32 +02:00
|
|
|
**
|
2016-09-04 20:55:21 +02:00
|
|
|
** @see _DefaultBinding<GenNode>
|
|
|
|
|
** @see tree-mutator-collection-binding.hpp
|
2016-08-31 17:09:32 +02:00
|
|
|
** @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
|
|
|
|
|
|
|
|
|
|
|
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!
2016-09-02 01:29:32 +02:00
|
|
|
#include "lib/diff/gen-node.hpp"
|
|
|
|
|
#include "lib/diff/tree-mutator-collection-binding.hpp"
|
|
|
|
|
#include "lib/diff/tree-mutator.hpp"
|
2016-08-31 17:09:32 +02:00
|
|
|
|
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!
2016-09-02 01:29:32 +02:00
|
|
|
#include <tuple>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
namespace lib {
|
|
|
|
|
namespace diff{
|
|
|
|
|
|
|
|
|
|
namespace { // Mutator-Builder decorator components...
|
2016-09-01 22:58:08 +02:00
|
|
|
|
2016-09-04 20:55:21 +02:00
|
|
|
/**
|
|
|
|
|
* Helper to deal with the magic "object type" attribute.
|
|
|
|
|
* Our _meta representation_ for "objects" as Record<GenNode>
|
|
|
|
|
* currently does not support metadata as a dedicated scope (as it should).
|
|
|
|
|
* Rather, the only relevant piece of metadata, an object type ID field, is
|
|
|
|
|
* treated with hard wired code and passed as a _magic attribute_ with key "type".
|
|
|
|
|
* Unfortunately this means for our task here that a plain flat standard binding
|
|
|
|
|
* for the collection of attributes does not suffice -- we need to intercept and
|
|
|
|
|
* grab assignments to this magic attribute to forward them to the dedicated
|
|
|
|
|
* type field found on diff::Record.
|
|
|
|
|
*
|
|
|
|
|
* Since we build two layers of bindings, with the attributes necessarily on top,
|
|
|
|
|
* this special treatment can be layered as a decorator on top, just overriding
|
|
|
|
|
* the two operations which get to handle assignment to attribute values.
|
|
|
|
|
*/
|
2016-09-03 22:34:36 +02:00
|
|
|
template<class PAR>
|
|
|
|
|
class ObjectTypeHandler
|
|
|
|
|
: public PAR
|
|
|
|
|
{
|
|
|
|
|
Rec::Mutator& targetObj_;
|
|
|
|
|
|
|
|
|
|
public:
|
|
|
|
|
ObjectTypeHandler(Rec::Mutator& targetObj, PAR&& chain)
|
|
|
|
|
: PAR(std::forward<PAR>(chain))
|
|
|
|
|
, targetObj_(targetObj)
|
|
|
|
|
{ }
|
|
|
|
|
|
|
|
|
|
virtual bool
|
2016-09-04 20:55:21 +02:00
|
|
|
injectNew (GenNode const& spec) override
|
2016-09-03 22:34:36 +02:00
|
|
|
{
|
2016-09-04 20:55:21 +02:00
|
|
|
if (spec.isNamed() and spec.isTypeID())
|
2016-09-03 22:34:36 +02:00
|
|
|
{
|
2016-09-04 20:55:21 +02:00
|
|
|
targetObj_.setType(spec.data.get<string>());
|
2016-09-03 22:34:36 +02:00
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
else
|
2016-09-04 20:55:21 +02:00
|
|
|
return PAR::injectNew (spec);
|
2016-09-03 22:34:36 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
virtual bool
|
2016-09-04 20:55:21 +02:00
|
|
|
assignElm (GenNode const& spec) override
|
2016-09-03 22:34:36 +02:00
|
|
|
{
|
2016-09-04 20:55:21 +02:00
|
|
|
if (spec.isNamed() and spec.isTypeID())
|
2016-09-03 22:34:36 +02:00
|
|
|
{
|
2016-09-04 20:55:21 +02:00
|
|
|
targetObj_.setType(spec.data.get<string>());
|
2016-09-03 22:34:36 +02:00
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
else
|
2016-09-04 20:55:21 +02:00
|
|
|
return PAR::assignElm (spec);
|
2016-09-03 22:34:36 +02:00
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
template<class MUT>
|
|
|
|
|
inline Builder<ObjectTypeHandler<MUT>>
|
2016-09-04 20:55:21 +02:00
|
|
|
filterObjectTypeAttribute (Rec::Mutator& targetTree, Builder<MUT>&& chain)
|
|
|
|
|
{
|
|
|
|
|
return ObjectTypeHandler<MUT> {targetTree, move(chain)};
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
using Storage = RecordSetup<GenNode>::Storage;
|
|
|
|
|
|
|
|
|
|
inline Storage&
|
|
|
|
|
accessAttribs (Rec::Mutator& targetTree)
|
2016-09-03 22:34:36 +02:00
|
|
|
{
|
2016-09-04 20:55:21 +02:00
|
|
|
return std::get<0> (targetTree.exposeToDiff());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
inline Storage&
|
|
|
|
|
accessChildren (Rec::Mutator& targetTree)
|
|
|
|
|
{
|
|
|
|
|
return std::get<1> (targetTree.exposeToDiff());
|
2016-09-03 22:34:36 +02:00
|
|
|
}
|
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!
2016-09-02 01:29:32 +02:00
|
|
|
|
|
|
|
|
|
|
|
|
|
/** Entry point for DSL builder */
|
2016-08-31 18:40:09 +02:00
|
|
|
template<class PAR>
|
|
|
|
|
inline auto
|
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!
2016-09-02 01:29:32 +02:00
|
|
|
Builder<PAR>::attach (Rec::Mutator& targetTree)
|
2016-08-31 17:09:32 +02:00
|
|
|
{
|
2016-09-04 20:55:21 +02:00
|
|
|
auto rawBinding = this->attach (collection (accessChildren(targetTree)))
|
|
|
|
|
.attach (collection (accessAttribs(targetTree))
|
|
|
|
|
.isApplicableIf ([](GenNode const& spec) -> bool
|
|
|
|
|
{ // »Selector« : treat key-value elements here
|
|
|
|
|
return spec.isNamed();
|
|
|
|
|
}));
|
|
|
|
|
|
|
|
|
|
return filterObjectTypeAttribute(targetTree, move(rawBinding));
|
2016-08-31 17:09:32 +02:00
|
|
|
}
|
|
|
|
|
|
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!
2016-09-02 01:29:32 +02:00
|
|
|
}//(END)Mutator-Builder decorator components...
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
}} // namespace lib::diff
|
2016-08-31 17:09:32 +02:00
|
|
|
#endif /*LIB_DIFF_TREE_MUTATOR_GEN_NODE_BINDING_H*/
|