complete dummy/proof-of-concept implementation of TreeMutator primitives

the first part of the unit test (now passing)
is able to demonstrate the full set of diff operations
just by binding to a TestMutationTarget.

Now, after verifying the design of those primmitive operations,
we can now proceed with bindings to "real" data structures
This commit is contained in:
Fischlurch 2016-03-11 21:30:25 +01:00
parent b0c6ba0777
commit 9ef32e0d62
3 changed files with 59 additions and 23 deletions

View file

@ -51,17 +51,15 @@
#include "lib/diff/record.hpp"
#include "lib/diff/tree-mutator.hpp"
#include "lib/idi/genfunc.hpp"
#include "lib/format-string.hpp"
#include "lib/format-util.hpp"
#include "lib/test/event-log.hpp"
#include "lib/util.hpp"
//#include "lib/format-string.hpp"
#include <boost/noncopyable.hpp>
//#include <functional>
#include <utility>
#include <string>
#include <vector>
//#include <map>
namespace lib {
@ -69,15 +67,15 @@ namespace diff{
namespace error = lumiera::error;
//using util::_Fmt;
using lib::Literal;
using lib::test::EventLog;
using lib::test::EventMatch;
using lib::Literal;
using iter_stl::eachElm;
using util::unConst;
using util::isnil;
using util::join;
// using std::function;
using util::_Fmt;
using std::string;
using std::forward;
using std::move;
@ -194,7 +192,11 @@ namespace diff{
/**
* Test adapter to watch and verify how the
* TreeMutator binds to custom tree data structures.
* @todo WIP 2/2016
* As a data structure, the TestMutationTarget builds an
* »External Tree Description« reflecting the actual data structure,
* as can be inferred through listening to all handled diff mutation primitives.
* Besides, each of these primitives is recorded in the embedded \ref EventLog.
* @see TreeManipulationBinding_test::mutateDummy()
*/
class TestMutationTarget
: boost::noncopyable
@ -263,6 +265,23 @@ namespace diff{
log_.event ("skipSrc", isnil(content.idi.getSym())? util::BOTTOM_INDICATOR : renderNode(content));
}
void
logAssignment (GenNode const& target, string oldPayload)
{
log_.event ("assignElm", _Fmt{"%s: %s ⤅ %s"}
% target.idi.getSym()
% oldPayload
% render(target.data));
}
void
logMutation (GenNode const& target)
{
log_.event ("mutateChild", _Fmt{"%s: start mutation...%s"}
% target.idi.getSym()
% render(target.data));
}
/* === Diagnostic / Verification === */
@ -327,9 +346,6 @@ namespace diff{
{
return log_;
}
private:
};
@ -443,13 +459,15 @@ namespace diff{
}
/** locate element already accepted into the taget sequence
* and assigne the designated payload value to it. */
* and assign the designated payload value to it. */
virtual bool
assignElm (GenNode const& spec)
{
Iter targetElm = target_.locate (spec.idi);
if (not targetElm) return false;
string logOldPayload{render(targetElm->data)};
*targetElm = spec;
target_.logAssignment (*targetElm, logOldPayload);
return true;
}
@ -458,8 +476,13 @@ namespace diff{
virtual bool
mutateChild (GenNode const& spec, TreeMutator::MutatorBuffer targetBuff)
{
UNIMPLEMENTED("locate and open sub mutator");
return false;
Iter targetElm = target_.locate (spec.idi);
if (not targetElm) return false;
bool otherSuccessfulMutation = PAR::mutateChild (spec, targetBuff);
if (not otherSuccessfulMutation) // Test mode only --
targetBuff.create (TreeMutator::build()); // no other layer was able to provide a mutator
target_.logMutation (*targetElm);
return true;
}

View file

@ -110,9 +110,9 @@ namespace lib {
{ }
template<class SUB, typename...ARGS>
template<class SUB>
BA&
create (ARGS&& ...args)
create (SUB&& subMutator)
{
if (sizeof(SUB) > maxSiz_)
throw error::Fatal("Unable to implant implementation object of size "
@ -122,7 +122,7 @@ namespace lib {
using Holder = InPlaceBuffer<BA, sizeof(SUB)>;
Holder& holder = *static_cast<Holder*> (buffer_);
return holder.create<SUB> (std::forward<ARGS> (args)...);
return holder.create<SUB> (std::forward<SUB> (subMutator));
}
template<class SUB>

View file

@ -226,16 +226,18 @@ namespace test{
CHECK (mutator3.acceptSrc (ATTRIB3)); // and accept the second copy of attribute γ
CHECK (mutator3.matchSrc (SUB_NODE)); // this /would/ be the next source element, but...
CHECK (not contains(target.showContent(), "γ = 3.14159265"));
CHECK (not contains(target.showContent(), "γ = 3.1415927"));
CHECK (mutator3.assignElm(GAMMA_PI)); // ...we assign a new payload to the current element first
CHECK ( contains(target.showContent(), "γ = 3.14159265"));
CHECK ( contains(target.showContent(), "γ = 3.1415927"));
CHECK (mutator3.accept_until (Ref::END)); // fast forward, since we do not want to re-order anything
cout << "Content after assignment; "
<< target.showContent() <<endl;
// for mutation of an enclosed scope, in real usage the managing TreeDiffInterpreter
// would maintain a stack of "mutation frames", where each one provides an OpaqueHolder
// to place a suitable sub-mutator for this nested scope. At this point, we can't get any further
// with this TestWireTap / TestMutationTarget approach, since the latter just records strings and
// thus will never be able to simulate mutation of a nested scope. In case there is no /real/ mutator
// with this TestWireTap / TestMutationTarget approach, since the latter just records actions and
// otherwise forwards operation to the rest of the TreeMutator. In case there is no /real/ mutator
// in any "onion layer" below the TestWireTap within this TreeMutator, we'll just get a default (NOP)
// implementation of TreeMutator without any further functionality.
@ -251,9 +253,20 @@ namespace test{
GenNode differentTime{CHILD_T.idi.getSym(), Time(11,22)};
VERIFY_ERROR (LOGIC, mutator3.assignElm (differentTime));
cout << "Content after mutation; "
<< target.showContent() <<endl;
CHECK (target.showContent() == "γ = 3.45, α = 1, β = 2, γ = 3.1415927, Rec(), b, 78:56:34.012");
CHECK (target.verifyEvent("acceptSrc","78:56:34.012")
.before("attachMutator TestWireTap")
.beforeEvent("accept_until β","γ = 3.45")
.beforeEvent("accept_until β","α = 1")
.beforeEvent("accept_until β","β = 2")
.beforeEvent("acceptSrc","γ = 3.45")
.beforeEvent("assignElm","γ: 3.45 ⤅ 3.1415927")
.beforeEvent("accept_until END","Rec()")
.beforeEvent("accept_until END","b")
.beforeEvent("accept_until END","78:56:34.012")
.beforeEvent("mutateChild","_CHILD_Record.001: start mutation...Rec()")
);
cout << "____Mutation-Log______________\n"
<< join(target.getLog(), "\n")
<< "\n───╼━━━━━━━━━╾────────────────"<<endl;