Diff-Listener: fill in implementation

...basically just need to intercept three TreeMutator-operations
This commit is contained in:
Fischlurch 2019-12-15 00:03:50 +01:00
parent a33e236630
commit d8b20ae497
4 changed files with 130 additions and 9 deletions

View file

@ -0,0 +1,119 @@
/*
TREE-MUTATOR-LISTENER-BINDING.hpp - decorator for TreeMutator to attach change listeners
Copyright (C) Lumiera.org
2019, 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-listener-binding.hpp
** Special supplement for TreeMutator, to attach listeners for notification
** on specific changes, especially structural ones. 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 combining various building blocks. This header defines
** a special decorator to be layered on top of such a TreeMutator binding; it will
** not interfere with the received diff, but detect relevant changes and invoke the
** bound functor after the triggering diff has been applied completely.
**
** @note the header tree-mutator-listener-binding.hpp was split off for sake of readability
** and is included automatically from bottom of tree-mutator.hpp -- no need to
** include it explicitly
**
** @see tree-mutator-test.cpp
** @see TreeMutator::build()
**
*/
#ifndef LIB_DIFF_TREE_MUTATOR_LISTENER_BINDING_H
#define LIB_DIFF_TREE_MUTATOR_LISTENER_BINDING_H
#include "lib/error.hpp"
#include "lib/diff/gen-node.hpp"
#include "lib/diff/tree-mutator.hpp"
namespace lib {
namespace diff{
namespace { // Mutator-Builder decorator components...
/**
* Decorator for TreeMutator bindings, to fire a listener function
* when the applied diff describes a structural change. By convention,
* all changes pertaining the sequence of children count as structural.
* Thus, effectively a structural change incurs usage of the `INS`, `DEL`
* `SKIP` or `FIND` verbs, which in turn are translated into the three
* API operation intercepted here.
* @note TreeMutator is a disposable one-way object;
* the triggering mechanism directly relies on that.
*/
template<class PAR, typename LIS>
class Detector4StructuralChanges
: public PAR
{
LIS changeListener_;
bool triggered_ = false;
public:
Detector4StructuralChanges (LIS functor, PAR&& chain)
: PAR(std::forward<PAR>(chain))
, changeListener_{functor}
{ }
/** once the diff is for this level is completely applied,
* the TreeMutator will be discarded, and we can fire our
* change listener at that point. */
~Detector4StructuralChanges()
{
if (triggered_)
changeListener_();
}
/* ==== TreeMutator API ==== */
using Elm = GenNode const&;
bool injectNew (Elm elm) override { triggered_ = true; return PAR::injectNew (elm); }
bool findSrc (Elm elm) override { triggered_ = true; return PAR::findSrc (elm); }
void skipSrc (Elm elm) override { triggered_ = true; PAR::skipSrc (elm); }
};
/** Entry point for DSL builder: attach a functor as listener to be notified after structural changes.
*/
template<class PAR>
template<typename LIS>
inline auto
Builder<PAR>::onStructuralChange (LIS changeListener)
{
ASSERT_VALID_SIGNATURE (LIS, void(void))
return chainedBuilder<Detector4StructuralChanges<PAR,LIS>> (changeListener);
}
}//(END)Mutator-Builder decorator components...
}} // namespace lib::diff
#endif /*LIB_DIFF_TREE_MUTATOR_LISTENER_BINDING_H*/

View file

@ -37,7 +37,7 @@
** default implementation, which likewise absorbs diff verbs, but in a way to trigger
** a lumiera::error::LUMIERA_ERROR_DIFF_CONFLICT.
**
** @note the header tree-mutator-attribute-binding.hpp was split off for sake of readability
** @note the header tree-mutator-noop-binding.hpp was split off for sake of readability
** and is included automatically from bottom of tree-mutator.hpp
**
** @see tree-mutator-test.cpp

View file

@ -453,12 +453,14 @@ namespace diff{
/** attach a listener function, to be invoked on _structural changes._
* Here, we define any change as "structural", which alters the _sequence_ of
* child elements, as opposed to their content. In practice, this listener will
* be invoked _after_ applying a diff with any `INS`, `DEL`, `FIND`, `SKIP` verb,
* or a specific `AFTER` verb (i.e. _not_ `AFTER(Ref::END)`)
* be invoked _after_ applying a diff with any `INS`, `DEL`, `FIND`, `SKIP` verb.
* @remark in theory, one could also drop contents indirectly, by sending only
* part of the necessary PICK verbs (or using AFTER(...)). However,
* such a diff is formally not prohibited, and will indeed be detected as
* error in many but not all cases, in ChildCollectionMutator::completeScope()
*/
template<typename LIS>
Builder<TreeMutator>///////////////////////TODO
onStructuralChange (LIS changeListener);
auto onStructuralChange (LIS changeListener);
};
}//(END) Mutator-Builder...
@ -480,5 +482,6 @@ namespace diff{
#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"
#include "lib/diff/tree-mutator-listener-binding.hpp"
#include "lib/diff/tree-mutator-noop-binding.hpp"

View file

@ -104,10 +104,9 @@ namespace test{
{
buff.create (
TreeMutator::build()
.attach (collection (subject_)
)
.onStructuralChange ([&](){ ++structChanges_; }
));
.attach (collection (subject_))
.onStructuralChange ([&](){ ++structChanges_; })
);
}