2016-02-19 20:25:30 +01:00
|
|
|
/*
|
|
|
|
|
TREE-DIFF-MUTATOR-BINDING.hpp - consume a tree diff, but target arbitrary private data
|
|
|
|
|
|
|
|
|
|
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-diff-mutator-binding.hpp
|
|
|
|
|
** Concrete implementation to apply structural changes to unspecific
|
2016-06-09 01:10:52 +02:00
|
|
|
** private data structures with hierarchical nature. This is a variation
|
2016-02-19 20:25:30 +01:00
|
|
|
** of the generic [tree diff applicator](\ref tree-diff-application.hpp),
|
|
|
|
|
** using the same implementation concept, while relying on an abstract
|
|
|
|
|
** adapter type, the \ref TreeMutator. Similar to the generic case, when
|
|
|
|
|
** combined with the generic #DiffApplicator, this allows to receive
|
|
|
|
|
** linearised structural diff descriptions and apply them to a given
|
|
|
|
|
** target data structure, which in this case is even a decoupled
|
|
|
|
|
** private data structure.
|
|
|
|
|
**
|
|
|
|
|
** ## Design considerations
|
2016-02-19 21:33:22 +01:00
|
|
|
** So this use case is implemented on the same conceptual framework used for
|
|
|
|
|
** the generic tree diff application, which in turn is -- conceptually -- an
|
|
|
|
|
** extension of applying a list diff. But, again, we follow the route _not_ to
|
|
|
|
|
** explicate those conceptual relations in the form of inheritance. This would
|
|
|
|
|
** be implementation re-use, as opposed to building a new viable abstraction.
|
|
|
|
|
** No one outside the implementation realm would benefit from such an abstraction,
|
|
|
|
|
** so we prefer to understand the tree diff language as the abstraction, which
|
|
|
|
|
** needs to embodied into two distinct contexts of implementation.
|
2016-02-19 20:25:30 +01:00
|
|
|
**
|
2016-02-19 21:33:22 +01:00
|
|
|
** ### Yet another indirection
|
|
|
|
|
** Unfortunately this leads to yet another indirection layer: Implementing a
|
|
|
|
|
** language in itself is necessarily a double dispatch (we have to abstract the
|
|
|
|
|
** verbs and we have to abstract the implementation side). And now we're decoupling
|
|
|
|
|
** the implementation side from a concrete data structure. Which means, that the
|
2016-06-09 01:10:52 +02:00
|
|
|
** use will have to provide a set of closures (which might even partially be generated
|
2016-02-19 21:33:22 +01:00
|
|
|
** functors) to translate the _implementation actions_ underlying the language into
|
2016-06-09 01:10:52 +02:00
|
|
|
** _concrete actions_ working on local data.
|
2016-02-19 20:25:30 +01:00
|
|
|
**
|
2016-07-24 15:16:06 +02:00
|
|
|
** ### Generic and variable parts
|
|
|
|
|
** So this is a link between generic [»tree diff language«](\ref tree-diff.hpp)
|
|
|
|
|
** interpretation and the concrete yet undisclosed private data structure, and
|
|
|
|
|
** most of this implementation is entirely generic, since the specifics are
|
|
|
|
|
** abstracted away behind the TreeMutator interface. For this reason, most of
|
|
|
|
|
** this explicit template specialisation code, especially. the virtual functions,
|
|
|
|
|
** can be emitted right here, within the library module. This helps to reduce
|
|
|
|
|
** "template bloat" and simplifies the dynamic linking. Thus, this header
|
|
|
|
|
** only contains the definition and the ctor code, which indeed needs to
|
|
|
|
|
** be adapted to each usage situation, while the main body of the
|
|
|
|
|
** functionality has been moved to the corresponding implementation
|
|
|
|
|
** file, where this template is explicitly instantiated, to force
|
|
|
|
|
** code generation into the library module.
|
|
|
|
|
**
|
2016-02-26 17:50:44 +01:00
|
|
|
** @todo this is WIP as of 2/2016 -- in the end it might be merged back or even
|
|
|
|
|
** replace the tree-diff-application.hpp
|
|
|
|
|
**
|
2016-02-19 21:33:22 +01:00
|
|
|
** @see DiffVirtualisedApplication_test
|
2016-02-19 20:25:30 +01:00
|
|
|
** @see DiffTreeApplication_test
|
|
|
|
|
** @see DiffListApplication_test
|
|
|
|
|
** @see GenNodeBasic_test
|
|
|
|
|
** @see tree-diff.hpp
|
|
|
|
|
**
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#ifndef LIB_DIFF_TREE_DIFF_MUTATOR_BINDING_H
|
|
|
|
|
#define LIB_DIFF_TREE_DIFF_MUTATOR_BINDING_H
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#include "lib/diff/tree-diff.hpp"
|
2016-02-21 00:49:13 +01:00
|
|
|
#include "lib/diff/tree-mutator.hpp"
|
2016-06-14 02:33:28 +02:00
|
|
|
#include "lib/diff/diff-mutable.hpp"
|
2016-02-19 20:25:30 +01:00
|
|
|
#include "lib/diff/gen-node.hpp"
|
|
|
|
|
#include "lib/format-string.hpp"
|
|
|
|
|
#include "lib/util.hpp"
|
|
|
|
|
|
|
|
|
|
#include <utility>
|
|
|
|
|
#include <stack>
|
|
|
|
|
|
|
|
|
|
namespace lib {
|
|
|
|
|
namespace diff{
|
|
|
|
|
|
2016-06-14 02:33:28 +02:00
|
|
|
/* ======= derive a TreeMutator binding for a given opaque data structure ======= */
|
|
|
|
|
|
2016-07-21 19:29:16 +02:00
|
|
|
|
|
|
|
|
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<typename T>
|
|
|
|
|
class exposes_MutatorBuilder
|
|
|
|
|
{
|
|
|
|
|
|
|
|
|
|
META_DETECT_FUNCTION (void, buildMutator, (TreeMutator::Handle));
|
|
|
|
|
|
|
|
|
|
public:
|
|
|
|
|
enum{ value = HasFunSig_buildMutator<T>::value
|
|
|
|
|
};
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2016-06-14 02:33:28 +02:00
|
|
|
template<class TAR, typename SEL =void>
|
|
|
|
|
struct MutatorBinding
|
|
|
|
|
{
|
2016-07-21 19:29:16 +02:00
|
|
|
static_assert (!sizeof(TAR), "MutatorBinding: Unable to access or build a TreeMutator for this target data.");
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
template<class TAR>
|
|
|
|
|
struct MutatorBinding<TAR, enable_if<is_same<TAR, DiffMutable>>>
|
|
|
|
|
{
|
|
|
|
|
using Ret = DiffMutable&;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
template<class TAR>
|
|
|
|
|
struct MutatorBinding<TAR, enable_if<exposes_MutatorBuilder<TAR>>>
|
|
|
|
|
{
|
|
|
|
|
class Wrapper
|
|
|
|
|
: public DiffMutable
|
2016-06-14 02:33:28 +02:00
|
|
|
{
|
2016-07-21 19:29:16 +02:00
|
|
|
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;
|
2016-06-14 02:33:28 +02:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
template<class TAR>
|
2016-07-21 19:29:16 +02:00
|
|
|
auto
|
|
|
|
|
mutatorBinding (TAR& subject) -> typename MutatorBinding<TAR>::Ret
|
2016-06-14 02:33:28 +02:00
|
|
|
{
|
2016-07-21 19:29:16 +02:00
|
|
|
using Wrapper = typename MutatorBinding<TAR>::Ret;
|
|
|
|
|
return Wrapper{subject};
|
2016-06-14 02:33:28 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* ======= Implementation of Tree Diff Application via TreeMutator ======= */
|
|
|
|
|
|
2016-02-19 20:25:30 +01:00
|
|
|
using util::unConst;
|
|
|
|
|
using util::cStr;
|
|
|
|
|
using util::_Fmt;
|
|
|
|
|
using std::move;
|
|
|
|
|
using std::swap;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
2016-06-09 01:10:52 +02:00
|
|
|
* Interpreter for the tree-diff-language to work on arbitrary, undisclosed
|
2016-02-19 21:33:22 +01:00
|
|
|
* local data structures. The key point to note is that this local data is
|
|
|
|
|
* not required to implement any specific interface. The only requirement is
|
|
|
|
|
* the ability somehow to support the basic operations of applying a structural
|
|
|
|
|
* diff. This is ensured with the help of a _customisable adapter_ the TreeMutator.
|
|
|
|
|
* @throws lumiera::error::State when diff application fails structurally.
|
|
|
|
|
* @throws _unspecified errors_ when delegated operations fail.
|
|
|
|
|
* @see TreeDiffInterpreter explanation of the verbs
|
|
|
|
|
* @see DiffVirtualisedApplication_test demonstration of usage
|
2016-02-19 20:25:30 +01:00
|
|
|
*/
|
|
|
|
|
template<>
|
2016-06-14 02:33:28 +02:00
|
|
|
class DiffApplicationStrategy<DiffMutable>
|
2016-02-19 20:25:30 +01:00
|
|
|
: public TreeDiffInterpreter
|
|
|
|
|
{
|
2016-02-21 00:49:13 +01:00
|
|
|
#if false /////////////////////////////////////////////////////////////////////////////////////////////////////////////UNIMPLEMENTED :: TICKET #992
|
2016-02-19 20:25:30 +01:00
|
|
|
using Mutator = Rec::Mutator;
|
|
|
|
|
using Content = Rec::ContentMutator;
|
|
|
|
|
using Iter = Content::Iter;
|
|
|
|
|
|
|
|
|
|
struct ScopeFrame
|
|
|
|
|
{
|
|
|
|
|
Mutator& target;
|
|
|
|
|
Content content;
|
|
|
|
|
|
|
|
|
|
ScopeFrame(Mutator& toModify)
|
|
|
|
|
: target(toModify)
|
|
|
|
|
, content()
|
|
|
|
|
{ }
|
|
|
|
|
|
|
|
|
|
void init()
|
|
|
|
|
{
|
|
|
|
|
target.swapContent (content);
|
|
|
|
|
content.resetPos();
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
/** Storage: a stack of workspaces
|
|
|
|
|
* used to handle nested child objects */
|
|
|
|
|
std::stack<ScopeFrame> scopes_;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Mutator& out() { return scopes_.top().target; }
|
|
|
|
|
Content& src() { return scopes_.top().content; }
|
|
|
|
|
Iter& srcPos() { return scopes_.top().content.pos; }
|
2016-05-24 21:34:08 +02:00
|
|
|
bool endOfData() { return srcPos() == src().end(); } /////TODO split into an actual scope end check and an non-null check
|
2016-02-19 20:25:30 +01:00
|
|
|
Rec& alteredRec() { return out(); }
|
|
|
|
|
|
|
|
|
|
|
2016-07-25 15:21:30 +02:00
|
|
|
void __expect_in_target (GenNode const& elm, Literal oper);
|
|
|
|
|
void __expect_further_elements (GenNode const& elm);
|
|
|
|
|
void __expect_found (GenNode const& elm, Iter const& targetPos);
|
|
|
|
|
void __expect_successful_location (GenNode const& elm);
|
|
|
|
|
void __expect_valid_parent_scope (GenNode::ID const& idi);
|
|
|
|
|
void __expect_end_of_scope (GenNode::ID const& idi);
|
2016-02-19 20:25:30 +01:00
|
|
|
|
|
|
|
|
|
2016-07-25 15:21:30 +02:00
|
|
|
Iter find_in_current_scope (GenNode const& elm);
|
2016-02-19 20:25:30 +01:00
|
|
|
|
2016-07-25 15:21:30 +02:00
|
|
|
GenNode const& find_child (GenNode::ID const& idi);
|
2016-02-19 20:25:30 +01:00
|
|
|
|
2016-07-25 15:21:30 +02:00
|
|
|
void move_into_new_sequence (Iter pos);
|
2016-02-26 17:50:44 +01:00
|
|
|
#endif /////////////////////////////////////////////////////////////////////////////////////////////////////////////UNIMPLEMENTED :: TICKET #992
|
2016-02-27 01:47:33 +01:00
|
|
|
|
|
|
|
|
/* == Forwarding: error handling == */
|
|
|
|
|
|
2016-07-25 15:21:30 +02:00
|
|
|
void __expect_in_target (GenNode const& elm, Literal oper);
|
|
|
|
|
void __expect_further_elements (GenNode const& elm);
|
|
|
|
|
void __fail_not_found (GenNode const& elm);
|
|
|
|
|
void __expect_end_of_scope (GenNode::ID const& idi);
|
|
|
|
|
void __expect_valid_parent_scope (GenNode::ID const& idi);
|
2016-02-27 01:47:33 +01:00
|
|
|
|
2016-02-26 17:50:44 +01:00
|
|
|
|
2016-02-19 20:25:30 +01:00
|
|
|
|
2016-02-27 01:47:33 +01:00
|
|
|
/* == Forwarding: mutation primitives == */
|
|
|
|
|
|
2016-07-25 15:21:30 +02:00
|
|
|
void skipSrc();
|
|
|
|
|
void injectNew (GenNode const& n);
|
|
|
|
|
bool matchSrc (GenNode const& n);
|
|
|
|
|
bool acceptSrc (GenNode const& n);
|
|
|
|
|
bool findSrc (GenNode const& n);
|
|
|
|
|
bool accept_until (GenNode const& refMark);
|
|
|
|
|
void assignElm (GenNode const& n);
|
|
|
|
|
void open_subScope (GenNode const& n);
|
|
|
|
|
void close_subScope();
|
2016-02-27 01:47:33 +01:00
|
|
|
|
|
|
|
|
|
2016-02-19 20:25:30 +01:00
|
|
|
|
|
|
|
|
/* == Implementation of the list diff application primitives == */
|
|
|
|
|
|
2016-07-25 15:21:30 +02:00
|
|
|
virtual void ins (GenNode const& n) override;
|
|
|
|
|
virtual void del (GenNode const& n) override;
|
|
|
|
|
virtual void pick (GenNode const& n) override;
|
|
|
|
|
virtual void skip (GenNode const& n) override;
|
|
|
|
|
virtual void find (GenNode const& n) override;
|
2016-02-19 20:25:30 +01:00
|
|
|
|
|
|
|
|
|
|
|
|
|
/* == Implementation of the tree diff application primitives == */
|
|
|
|
|
|
2016-07-25 15:21:30 +02:00
|
|
|
virtual void after(GenNode const& n) override;
|
|
|
|
|
virtual void set (GenNode const& n) override;
|
|
|
|
|
virtual void mut (GenNode const& n) override;
|
|
|
|
|
virtual void emu (GenNode const& n) override;
|
2016-02-19 20:25:30 +01:00
|
|
|
|
|
|
|
|
|
|
|
|
|
public:
|
|
|
|
|
explicit
|
2016-06-14 02:33:28 +02:00
|
|
|
DiffApplicationStrategy(DiffMutable& targetBinding)
|
2016-02-19 20:25:30 +01:00
|
|
|
{
|
2016-06-11 19:40:53 +02:00
|
|
|
TODO("attach to the given Target");
|
|
|
|
|
#if false /////////////////////////////////////////////////////////////////////////////////////////////////////////////UNIMPLEMENTED :: TICKET #992
|
2016-02-19 20:25:30 +01:00
|
|
|
scopes_.emplace(mutableTargetRecord);
|
2016-06-11 19:40:53 +02:00
|
|
|
#endif /////////////////////////////////////////////////////////////////////////////////////////////////////////////UNIMPLEMENTED :: TICKET #992
|
2016-02-19 20:25:30 +01:00
|
|
|
}
|
|
|
|
|
|
2016-07-25 15:21:30 +02:00
|
|
|
void initDiffApplication();
|
2016-02-21 00:49:13 +01:00
|
|
|
};
|
2016-02-19 20:25:30 +01:00
|
|
|
|
|
|
|
|
|
2016-07-25 15:21:30 +02:00
|
|
|
|
|
|
|
|
/** use the explicit instantiation provided in library module */
|
|
|
|
|
extern template class DiffApplicationStrategy<DiffMutable>;
|
|
|
|
|
|
|
|
|
|
|
2016-02-19 20:25:30 +01:00
|
|
|
}} // namespace lib::diff
|
|
|
|
|
#endif /*LIB_DIFF_TREE_DIFF_MUTATOR_BINDING_H*/
|