2016-07-28 01:17:50 +02:00
|
|
|
/*
|
|
|
|
|
TREE-DIFF-TRAITS.hpp - definitions to control tree mutator binding
|
|
|
|
|
|
|
|
|
|
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-traits.hpp
|
|
|
|
|
** Definitions and Properties to guide automated tree mutator binding.
|
|
|
|
|
** Decision how to access the target structure and how to construct
|
|
|
|
|
** a suitable TreeMutator as attached to this opaque target data.
|
|
|
|
|
**
|
2016-08-29 22:14:03 +02:00
|
|
|
** In a nutshell, if some private data structure wants to receive
|
|
|
|
|
** mutation diff messages...
|
|
|
|
|
** - it must either implement the interface DiffMutable
|
2019-12-12 23:41:26 +01:00
|
|
|
** - or provide the extension point `void buildMutator(TreeMutator::Handle)`
|
2016-08-29 22:14:03 +02:00
|
|
|
** Additionally, when the size of the custom TreeMutator object exceeds some
|
|
|
|
|
** hard wired limit (200 bytes), then the target type also needs to define
|
|
|
|
|
** the extension point `size_t treeMutatorSize(TargetType)`
|
|
|
|
|
**
|
|
|
|
|
** All of this boils down to somewhere / somehow using the TreeMutator::Builder
|
|
|
|
|
** (a DSL API) to construct a custom binding, which allows to talk to our
|
|
|
|
|
** private data structure through the TreeMutator interface.
|
2016-07-28 01:17:50 +02:00
|
|
|
**
|
2016-08-29 17:52:35 +02:00
|
|
|
** @see DiffComplexApplication_test
|
2016-07-28 01:17:50 +02:00
|
|
|
** @see DiffTreeApplication_test
|
|
|
|
|
** @see DiffListApplication_test
|
2019-12-12 23:41:26 +01:00
|
|
|
** @see GenNode_test
|
2016-07-28 01:17:50 +02:00
|
|
|
** @see tree-diff.hpp
|
|
|
|
|
**
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#ifndef LIB_DIFF_TREE_DIFF_TRAITS_H
|
|
|
|
|
#define LIB_DIFF_TREE_DIFF_TRAITS_H
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#include "lib/diff/tree-mutator.hpp"
|
|
|
|
|
#include "lib/diff/diff-mutable.hpp"
|
2016-07-30 23:22:46 +02:00
|
|
|
#include "lib/null-value.hpp"
|
2016-07-28 01:17:50 +02:00
|
|
|
#include "lib/util.hpp"
|
|
|
|
|
|
|
|
|
|
#include <utility>
|
|
|
|
|
#include <stack>
|
|
|
|
|
|
|
|
|
|
namespace lib {
|
|
|
|
|
namespace diff{
|
|
|
|
|
|
2016-07-30 16:47:57 +02:00
|
|
|
|
|
|
|
|
/* ======= Hints / Heuristics for the required TreeMutator buffer size ======= */
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Heuristics to guide the allocation for nested TreeMutator.
|
|
|
|
|
* When applying a structural (tree) diff, the (otherwise undisclosed)
|
|
|
|
|
* target data structure needs to supply a TreeMutator implementation
|
|
|
|
|
* properly wired to the internal opaque data elements. Typically, this
|
|
|
|
|
* custom TreeMutator relies on several lambdas and closures, which
|
|
|
|
|
* require a variable and hard to guess amount of storage for back pointers
|
|
|
|
|
* and embedded parametrisation. More so, when the diff application opens
|
|
|
|
|
* nested scopes within the target data. The TreeDiffMutatorBinding relies
|
|
|
|
|
* on a (likewise opaque) ScopeManager implementation to maintain a stack
|
|
|
|
|
* of heap allocated buffers, where the mentioned nested TreeMutator
|
|
|
|
|
* implementations can be built and operated during the mutation process.
|
|
|
|
|
*
|
|
|
|
|
* The default for buffer dimensions includes a safety margin and is thus
|
|
|
|
|
* quite expensive -- even though this is just a temporary working buffer.
|
|
|
|
|
* Thus we offer a hook for explicit or partial specialisations to control
|
|
|
|
|
* the very common cases known to work with smaller buffer sizes.
|
|
|
|
|
*
|
|
|
|
|
* \par future extensions
|
|
|
|
|
* We might consider to make this system dynamic, in case buffer allocation
|
|
|
|
|
* for tree diff application becomes an issue in general. We might then guard
|
|
|
|
|
* the whole diff application location with try-catch blocks and allow thus
|
|
|
|
|
* for learning the right setting at runtime; obviously we'd then also have to
|
|
|
|
|
* memorise our findings somehow within the dynamic application configuration.
|
|
|
|
|
*
|
|
|
|
|
* @see tree-diff-application.hpp
|
2016-08-29 17:52:35 +02:00
|
|
|
* @see DiffComplexApplication_test
|
2016-07-30 16:47:57 +02:00
|
|
|
*/
|
2016-07-30 23:22:46 +02:00
|
|
|
template<class TAR, typename SEL =void>
|
2016-07-30 16:47:57 +02:00
|
|
|
struct TreeMutatorSizeTraits
|
|
|
|
|
{
|
|
|
|
|
enum { siz = 200 };
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
2016-07-30 23:22:46 +02:00
|
|
|
constexpr size_t
|
2016-08-29 22:14:03 +02:00
|
|
|
treeMutatorSize (...) ///< fallback to detect absence of a custom definition
|
2016-07-30 23:22:46 +02:00
|
|
|
{
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
template<typename T>
|
|
|
|
|
constexpr T*
|
|
|
|
|
getSelector()
|
|
|
|
|
{
|
|
|
|
|
return static_cast<T*> (nullptr);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
template<typename T>
|
|
|
|
|
struct defines_custom_BufferSize
|
|
|
|
|
{
|
|
|
|
|
enum { value = 0 < treeMutatorSize (getSelector<T>()) };
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
template<class TAR>
|
|
|
|
|
struct TreeMutatorSizeTraits<TAR, enable_if<defines_custom_BufferSize<TAR>> >
|
|
|
|
|
{
|
|
|
|
|
enum { siz = treeMutatorSize (getSelector<TAR>()) };
|
|
|
|
|
};
|
|
|
|
|
|
2016-07-30 16:47:57 +02:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2016-08-29 22:14:03 +02:00
|
|
|
/* ======= derive TreeMutator binding for a given opaque data structure ======= */
|
2016-07-28 01:17:50 +02:00
|
|
|
|
|
|
|
|
|
|
|
|
|
using meta::enable_if;
|
|
|
|
|
using meta::Yes_t;
|
|
|
|
|
using meta::No_t;
|
2019-12-14 23:35:16 +01:00
|
|
|
using std::is_base_of;
|
2016-07-28 01:17:50 +02:00
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* helper to detect presence of a
|
|
|
|
|
* TreeMutator builder function
|
|
|
|
|
*/
|
|
|
|
|
template<typename T>
|
|
|
|
|
class exposes_MutatorBuilder
|
|
|
|
|
{
|
|
|
|
|
|
|
|
|
|
META_DETECT_FUNCTION (void, buildMutator, (TreeMutator::Handle));
|
|
|
|
|
|
|
|
|
|
public:
|
2016-10-02 23:34:07 +02:00
|
|
|
enum{ value = HasFunSig_buildMutator<T>::value
|
2019-12-14 23:35:16 +01:00
|
|
|
and not is_base_of<DiffMutable, T>::value};
|
2016-07-28 01:17:50 +02:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
template<class TAR, typename SEL =void>
|
|
|
|
|
struct TreeDiffTraits
|
2016-07-28 22:58:21 +02:00
|
|
|
: std::false_type
|
2016-07-28 01:17:50 +02:00
|
|
|
{
|
|
|
|
|
static_assert (!sizeof(TAR), "TreeDiffTraits: Unable to access or build a TreeMutator for this target data.");
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
template<class TAR>
|
2019-12-14 23:35:16 +01:00
|
|
|
struct TreeDiffTraits<TAR, enable_if<is_base_of<DiffMutable, TAR>>>
|
2016-07-28 22:58:21 +02:00
|
|
|
: std::true_type
|
2016-07-28 01:17:50 +02:00
|
|
|
{
|
|
|
|
|
using Ret = DiffMutable&;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
template<class TAR>
|
|
|
|
|
struct TreeDiffTraits<TAR, enable_if<exposes_MutatorBuilder<TAR>>>
|
2016-07-28 22:58:21 +02:00
|
|
|
: std::true_type
|
2016-07-28 01:17:50 +02:00
|
|
|
{
|
|
|
|
|
class Wrapper
|
|
|
|
|
: public DiffMutable
|
|
|
|
|
{
|
|
|
|
|
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-08-29 22:14:03 +02:00
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* public access point to this configuration machinery
|
|
|
|
|
* @return depending on the circumstances, either a direct reference
|
|
|
|
|
* to DiffMutable, or a transient functor object implementing
|
|
|
|
|
* the DiffMutable interface
|
|
|
|
|
* @warning beware of dangling references! either use this call immediately
|
|
|
|
|
* inline, or (preferably) use an `auto` typed variable to hold
|
|
|
|
|
* the return value in local scope as long as necessary
|
|
|
|
|
*/
|
2016-07-28 01:17:50 +02:00
|
|
|
template<class TAR>
|
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
|
|
|
typename TreeDiffTraits<TAR>::Ret
|
|
|
|
|
mutatorBinding (TAR& subject)
|
2016-07-28 01:17:50 +02:00
|
|
|
{
|
|
|
|
|
using Wrapper = typename TreeDiffTraits<TAR>::Ret;
|
2016-10-02 23:34:07 +02:00
|
|
|
return Wrapper(subject);
|
2016-07-28 01:17:50 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
}} // namespace lib::diff
|
|
|
|
|
#endif /*LIB_DIFF_TREE_DIFF_TRAITS_H*/
|