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:
parent
e5bbcb27d8
commit
ee99c405fd
2 changed files with 113 additions and 61 deletions
|
|
@ -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();
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -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ß 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ö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ß 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 überhaupt eine Alternative">
|
||||
<icon BUILTIN="help"/>
|
||||
</node>
|
||||
</node>
|
||||
</node>
|
||||
</node>
|
||||
</node>
|
||||
</node>
|
||||
|
|
|
|||
Loading…
Reference in a new issue