Reorganise implementation into base class + overlay

...as preparation for implementing the two flavours of
binding attributes either via  a setter lambda or via
creation of a nested mutator.
This commit is contained in:
Fischlurch 2016-05-29 03:01:27 +02:00
parent e5bbcb27d8
commit ee99c405fd
2 changed files with 113 additions and 61 deletions

View file

@ -56,18 +56,18 @@
//== anonymous namespace...
template<class PAR, class CLO>
class ChangeOperation
template<class PAR, class IDI>
class AttributeBindingBase
: public PAR
{
using CloArgs = typename _ClosureType<CLO>::Args;
using ValueType = typename lib::meta::Pick<CloArgs, 0>::Type;
using ID = idi::EntryID<ValueType>;
ID attribID_;
CLO change_;
IDI attribID_;
protected:
AttributeBindingBase (IDI attribID, PAR&& chain)
: PAR(std::forward<PAR>(chain))
, attribID_(attribID)
{ }
/** hard wired "selector predicate" for this binding layer.
* We do only handle mutation operations pertaining attributes
@ -83,17 +83,9 @@
and attribID_ == spec.idi;
}
public:
ChangeOperation (Symbol attribKey, CLO clo, PAR&& chain)
: PAR(std::forward<PAR>(chain))
, attribID_(attribKey)
, change_(clo)
{ }
/* ==== re-Implementation of the operation API ==== */
public:
/** this binding to an object field can not support any reordering,
* inserting or deletion of "Elements", since the structure of an object
* is fixed through the underlying class definition. For this reason,
@ -126,35 +118,6 @@
return isApplicable (spec);
}
/** while, strictly speaking, one can not "insert" fields into a
* given class definition, this binding can tolerate an `INS` verb
* whenever this means to touch a field which is actually known and
* present in the class definition underlying this binding. In such
* a case, we just assign the given value. This implementation leeway
* is deliberate to support classes with optional / defaultable properties.
*/
virtual bool
injectNew (GenNode const& spec) override
{
if (not isApplicable(spec))
return PAR::injectNew(spec);
change_(spec.data.get<ValueType>());
return true;
}
/** has no meaning, since object fields have no notion of "order".
* @note it would be desirable to throw, but due to other restrictions
* in the "diff protocol" this operation does not get any arguments.
* Thus we're not able to determine, if this layer is in charge, so
* we need just to pass on the invocation.
*/
virtual void
skipSrc () override
{
PAR::skipSrc();
}
/** any reordering or deletion of object fields is prohibited
* @throw error::Logic when this binding layer becomes responsible for
* handling the given diff spec, because a proper diff must be arranged
@ -175,37 +138,93 @@
/** repeatedly accept, until after the designated location */
virtual bool
accept_until (GenNode const& spec)
accept_until (GenNode const& spec) override
{
UNIMPLEMENTED("only support UNTIL END");
}
};
template<typename CLO>
struct AttribType
{
using CloArgs = typename _ClosureType<CLO>::Args;
using ValueType = typename lib::meta::Pick<CloArgs, 0>::Type;
using ID = idi::EntryID<ValueType>;
};
template<class PAR, class CLO>
class ChangeOperation
: public AttributeBindingBase<PAR, typename AttribType<CLO>::ID>
{
using ID = typename AttribType<CLO>::ID;
using ValueType = typename AttribType<CLO>::ValueType;
/** invoke the setter lambda, in case this binding layer is in charge */
CLO change_;
public:
ChangeOperation (Symbol attribKey, CLO clo, PAR&& chain)
: AttributeBindingBase<PAR, ID>(ID{attribKey}, std::forward<PAR>(chain))
, change_(clo)
{ }
/* ==== Implementation of value assignment operation ==== */
/** while, strictly speaking, one can not "insert" fields into a
* given class definition, this binding can tolerate an `INS` verb
* whenever this means to touch a field which is actually known and
* present in the class definition underlying this binding. In such
* a case, we just assign the given value. This implementation leeway
* is deliberate to support classes with optional / defaultable properties.
*/
virtual bool
assignElm (GenNode const& spec)
injectNew (GenNode const& spec) override
{
if (not isApplicable(spec))
return PAR::assignElm(spec);
if (not this->isApplicable(spec))
return PAR::injectNew(spec);
change_(spec.data.get<ValueType>());
return true;
}
/** invoke the setter lambda, in case this binding layer is in charge */
virtual bool
assignElm (GenNode const& spec) override
{
if (not this->isApplicable(spec))
return PAR::assignElm(spec);
change_(spec.data.get<ValueType>());
return true;
}
};
template<class PAR, class IDI, class MUT>
class MutationOperation
: public AttributeBindingBase<PAR, IDI>
{
MUT mutatorBuilder_;
public:
MutationOperation (IDI attribID, MUT clo, PAR&& chain)
: AttributeBindingBase<PAR, IDI>(attribID, std::forward<PAR>(chain))
, mutatorBuilder_(clo)
{ }
/** locate the designated target element and build a suitable
* sub-mutator for this element into the provided target buffer */
virtual bool
mutateChild (GenNode const& spec, TreeMutator::MutatorBuffer targetBuff)
mutateChild (GenNode const& spec, TreeMutator::MutatorBuffer targetBuff) override
{
UNIMPLEMENTED("invoke mutator builder");
}
/** verify all our pending (old) source elements where mentioned.
* @note allows chained "onion-layers" to clean-up and verify.*/
virtual bool
completeScope()
{
return PAR::completeScope();
}
};

View file

@ -4050,7 +4050,8 @@
</node>
</node>
</node>
<node CREATED="1464386771270" ID="ID_1279882649" MODIFIED="1464386811412" TEXT="setter vs mutator">
<node CREATED="1464386771270" ID="ID_1279882649" MODIFIED="1464483680342" TEXT="setter vs mutator">
<icon BUILTIN="pencil"/>
<node CREATED="1464386870265" ID="ID_1326576761" MODIFIED="1464387168773" TEXT="Metaprogrammierung"/>
<node CREATED="1464386878983" ID="ID_19052291" MODIFIED="1464386887354" TEXT="Code selber mu&#xdf; es implizit wissen"/>
<node CREATED="1464386904676" ID="ID_1844234642" MODIFIED="1464386908705" TEXT="entweder-oder">
@ -4058,6 +4059,38 @@
<node CREATED="1464386910099" ID="ID_127180278" MODIFIED="1464386913750" TEXT="nicht notwendig"/>
<node CREATED="1464386929745" ID="ID_1833671444" MODIFIED="1464386936708" TEXT="es greift der Layer, der es kann"/>
</node>
<node CREATED="1464483482949" HGAP="32" ID="ID_597384200" MODIFIED="1464483496618" TEXT="Code-Struktur" VSHIFT="15">
<icon BUILTIN="messagebox_warning"/>
<node CREATED="1464483497524" ID="ID_206433048" MODIFIED="1464483503639" TEXT="Basisklasse + Overlay"/>
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1464483504155" ID="ID_565058375" MODIFIED="1464483671480" TEXT="unsch&#xf6;n und verwirrend">
<node CREATED="1464483533863" ID="ID_1813082482" MODIFIED="1464483617082" TEXT="mehrfach geschachtelte Typdefinitionen">
<icon BUILTIN="smily_bad"/>
</node>
<node CREATED="1464483544429" ID="ID_467553331" MODIFIED="1464483659487" TEXT="Problem mit der EntryID">
<richcontent TYPE="NOTE"><html>
<head>
</head>
<body>
<p>
in einem Fall kann man sie aus der Closure abgreifen
</p>
<p>
im anderen Fall mu&#223; es doch der Client leisten.
</p>
<p>
Keine klare Linie
</p>
</body>
</html>
</richcontent>
<icon BUILTIN="smily_bad"/>
</node>
<node CREATED="1464483601318" ID="ID_1275035047" MODIFIED="1464483610226" TEXT="gibt es &#xfc;berhaupt eine Alternative">
<icon BUILTIN="help"/>
</node>
</node>
</node>
</node>
</node>
</node>