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:
parent
b0c6ba0777
commit
9ef32e0d62
3 changed files with 59 additions and 23 deletions
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
Loading…
Reference in a new issue