define a TreeMutator binding for our test::Opaque type

OMG, this is intricate stuff....
Questionable if anyone (other than myself) will be able
to get those bindings right???

Probably we'll need yet another abstraction layer to handle
the most common binding situations automatically, so that people
can use the diff framework without intricate knowledge of
TreeMutator construction.
This commit is contained in:
Fischlurch 2016-07-30 23:22:46 +02:00
parent 2b424be57c
commit cbdc53e2d8
2 changed files with 143 additions and 6 deletions

View file

@ -43,6 +43,7 @@
#include "lib/diff/tree-mutator.hpp"
#include "lib/diff/diff-mutable.hpp"
#include "lib/null-value.hpp"
#include "lib/util.hpp"
#include <utility>
@ -82,13 +83,40 @@ namespace diff{
* @see tree-diff-application.hpp
* @see DiffVirtualisedApplication_test
*/
template<class TAR>
template<class TAR, typename SEL =void>
struct TreeMutatorSizeTraits
{
enum { siz = 200 };
};
constexpr size_t
treeMutatorSize (...)
{
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>()) };
};

View file

@ -24,6 +24,7 @@
#include "lib/test/run.hpp"
#include "lib/format-util.hpp"
#include "lib/diff/tree-diff-application.hpp"
#include "lib/diff/test-mutation-target.hpp"
#include "lib/iter-adapter-stl.hpp"
#include "lib/time/timevalue.hpp"
#include "lib/format-cout.hpp" //////////TODO necessary?
@ -41,6 +42,7 @@ using util::join;
using util::_Fmt;
using util::join;
using std::unique_ptr;
using std::make_unique;
using std::string;
using std::vector;
using lib::time::Time;
@ -76,6 +78,9 @@ namespace test{
*/
class Opaque
{
idi::EntryID<Opaque> key_;
string type_ = Rec::TYPE_NIL;
int alpha_ = -1;
string beta_ = "NIL";
double gamma_ = -1;
@ -88,10 +93,46 @@ namespace test{
public:
Opaque() { }
explicit
Opaque (string keyID)
: key_(keyID)
{ }
explicit
Opaque (idi::BareEntryID id)
: key_(id)
{ }
Opaque (Opaque const& o)
: key_(o.key_)
, type_(o.type_)
, alpha_(o.alpha_)
, beta_(o.beta_)
, gamma_(o.gamma_)
, delta_()
, nestedObj_(o.nestedObj_)
, nestedData_(o.nestedData_)
{
if (o.delta_)
delta_.reset(new Opaque(*o.delta_));
}
Opaque&
operator= (Opaque const& o)
{
if (&o != this)
{
Opaque tmp(o);
swap (*this, tmp);
}
return *this;
}
operator string() const
{
return _Fmt{"%s (α:%d β:%s γ:%7.5f δ:%s\n......|nested:%s\n......|data:%s\n )"}
% idi::instanceTypeID (this)
% identity()
% alpha_
% beta_
% gamma_
@ -101,15 +142,85 @@ namespace test{
;
}
string
identity() const
{
string symbol = key_.getSym() + (isTyped()? "≺"+type_+"≻" : "");
return lib::idi::format::instance_hex_format(symbol, key_.getHash());
}
bool
isTyped() const
{
return Rec::TYPE_NIL != type_;
}
void
buildMutator (TreeMutator::Handle buff)
{
UNIMPLEMENTED("construct the concrete Binding, using the TreeMutator::Builder DSL");
buff.create (
TreeMutator::build()
.attach (collection(nestedData_)
));
.isApplicableIf ([&](GenNode const& spec) -> bool
{
return not spec.isNamed(); // »Selector« : accept anything unnamed value-like
})
.assignElement ([&](string& target, GenNode const& spec) -> bool
{
target = render(spec.data);
return true;
}))
.attach (collection(nestedObj_)
.isApplicableIf ([&](GenNode const& spec) -> bool
{
return type_ == spec.data.recordType(); // »Selector« : require object-like sub scope with matching typeID
})
.constructFrom ([&](GenNode const& spec) -> Opaque
{
return Opaque{spec.idi};
})
.matchElement ([&](GenNode const& spec, Opaque const& elm) -> bool
{
return spec.idi == elm.key_;
})
.buildChildMutator ([&](Opaque& target, GenNode::ID const& subID, TreeMutator::Handle buff) -> bool
{
if (target.key_ != subID) return false; // require match on already existing child object
target.buildMutator (buff); // delegate to child to build nested TreeMutator
return true;
}))
.change("type", [&](string typeID)
{
type_ = typeID;
})
.change("α", [&](int val)
{
alpha_ = val;
})
.change("β", [&](string val)
{
beta_ = val;
})
.change("γ", [&](double val)
{
gamma_ = val;
})
.mutateAttrib("δ", [&](TreeMutator::Handle buff)
{
if (not delta_)
delta_.reset (new Opaque("δ"));
REQUIRE (delta_);
delta_->buildMutator(buff);
}));
}
friend constexpr size_t
treeMutatorSize (const Opaque*)
{
return 350;
}
};
}//(End)Test fixture
@ -120,8 +231,6 @@ namespace test{
/***********************************************************************//**
* @test Demonstration: apply a structural change to unspecified private
* data structures, with the help of an [dynamic adapter](\ref TreeMutator)