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...
|
//== anonymous namespace...
|
||||||
|
|
||||||
|
|
||||||
template<class PAR, class CLO>
|
template<class PAR, class IDI>
|
||||||
class ChangeOperation
|
class AttributeBindingBase
|
||||||
: public PAR
|
: 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.
|
/** hard wired "selector predicate" for this binding layer.
|
||||||
* We do only handle mutation operations pertaining attributes
|
* We do only handle mutation operations pertaining attributes
|
||||||
|
|
@ -83,17 +83,9 @@
|
||||||
and attribID_ == spec.idi;
|
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 ==== */
|
/* ==== re-Implementation of the operation API ==== */
|
||||||
|
public:
|
||||||
/** this binding to an object field can not support any reordering,
|
/** this binding to an object field can not support any reordering,
|
||||||
* inserting or deletion of "Elements", since the structure of an object
|
* inserting or deletion of "Elements", since the structure of an object
|
||||||
* is fixed through the underlying class definition. For this reason,
|
* is fixed through the underlying class definition. For this reason,
|
||||||
|
|
@ -126,35 +118,6 @@
|
||||||
return isApplicable (spec);
|
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
|
/** any reordering or deletion of object fields is prohibited
|
||||||
* @throw error::Logic when this binding layer becomes responsible for
|
* @throw error::Logic when this binding layer becomes responsible for
|
||||||
* handling the given diff spec, because a proper diff must be arranged
|
* handling the given diff spec, because a proper diff must be arranged
|
||||||
|
|
@ -175,37 +138,93 @@
|
||||||
|
|
||||||
/** repeatedly accept, until after the designated location */
|
/** repeatedly accept, until after the designated location */
|
||||||
virtual bool
|
virtual bool
|
||||||
accept_until (GenNode const& spec)
|
accept_until (GenNode const& spec) override
|
||||||
{
|
{
|
||||||
UNIMPLEMENTED("only support UNTIL END");
|
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
|
virtual bool
|
||||||
assignElm (GenNode const& spec)
|
injectNew (GenNode const& spec) override
|
||||||
{
|
{
|
||||||
if (not isApplicable(spec))
|
if (not this->isApplicable(spec))
|
||||||
return PAR::assignElm(spec);
|
return PAR::injectNew(spec);
|
||||||
|
|
||||||
change_(spec.data.get<ValueType>());
|
change_(spec.data.get<ValueType>());
|
||||||
return true;
|
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
|
/** locate the designated target element and build a suitable
|
||||||
* sub-mutator for this element into the provided target buffer */
|
* sub-mutator for this element into the provided target buffer */
|
||||||
virtual bool
|
virtual bool
|
||||||
mutateChild (GenNode const& spec, TreeMutator::MutatorBuffer targetBuff)
|
mutateChild (GenNode const& spec, TreeMutator::MutatorBuffer targetBuff) override
|
||||||
{
|
{
|
||||||
UNIMPLEMENTED("invoke mutator builder");
|
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>
|
||||||
</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="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="1464386878983" ID="ID_19052291" MODIFIED="1464386887354" TEXT="Code selber muß es implizit wissen"/>
|
||||||
<node CREATED="1464386904676" ID="ID_1844234642" MODIFIED="1464386908705" TEXT="entweder-oder">
|
<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="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 CREATED="1464386929745" ID="ID_1833671444" MODIFIED="1464386936708" TEXT="es greift der Layer, der es kann"/>
|
||||||
</node>
|
</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>
|
</node>
|
||||||
</node>
|
</node>
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue