TreeMutator binding: extend collection binding to support std::map

actually this is a pragmatic extension for some special use cases,
and in general rather discurraged, since it contradicts the
established diff semantics. Yet with some precaution, it should
be possible to transport information via an intermediary ETD

Map -> ETD -> Map
This commit is contained in:
Fischlurch 2016-10-03 19:31:59 +02:00
parent 15ac0d6310
commit d58f8c853a
3 changed files with 157 additions and 41 deletions

View file

@ -35,6 +35,9 @@
** a building block for one such layer, especially for binding to a representation
** of "child objects" managed within a typical STL container.
**
** As a _special case_, binding to a STL map is supported, while this usage is rather
** discurraged, since it contradicts the diff semantics due to intrinsic ordering.
**
** @note the header tree-mutator-collection-binding.hpp was split off for sake of readability
** and is included automatically from bottom of tree-mutator.hpp
**
@ -55,6 +58,8 @@
#include "lib/iter-adapter-stl.hpp"
#include <utility>
#include <vector>
#include <map>
namespace lib {
@ -63,7 +68,7 @@ namespace diff{
namespace { // Mutator-Builder decorator components...
using std::forward;
using lib::meta::Strip;
using lib::diff::GenNode;
using lib::iter_stl::eachElm;
@ -139,7 +144,7 @@ namespace diff{
void
inject (Elm&& elm)
{
collection.emplace_back (forward<Elm>(elm));
emplace (collection, forward<Elm>(elm));
}
iterator
@ -154,23 +159,82 @@ namespace diff{
locate (GenNode const& targetSpec)
{
if (not collection.empty()
and matches (targetSpec, collection.back()))
return lastElm();
and matches (targetSpec, recentElm(collection)))
return recentElmIter();
else
return search (targetSpec, eachElm(collection));
}
private:
private: /* === technicallities of container access === */
/** @internal technicality
* Our iterator is actually a Lumiera RangeIter, and thus we need
* to construct a raw collection iterator pointing to the aftmost element
* and then create a range from this iterator and the `end()` iterator.
*/
iterator
lastElm()
recentElmIter()
{
using raw_iter = typename CollectionBinding::Coll::iterator;
return iterator (raw_iter(&collection.back()), collection.end());
return iterator (recentElmRawIter(collection), collection.end());
}
template<class C>
static auto
recentElmRawIter (C& coll) ///< fallback: use first element of container
{
return coll.begin();
}
template<typename E>
using Map = std::map<typename E::key_type, typename E::second_type>;
template<typename E>
static auto
recentElmRawIter (Map<E>& map) ///< workaround for `std::Map`: lookup via reverse iterator
{
return map.find (recentElm(map).first);
}
static auto
recentElmRawIter (std::vector<Elm>& vec)
{
return typename std::vector<Elm>::iterator (&vec.back());
}
template<class C>
static Elm&
recentElm (C& coll)
{
return *coll.begin();
}
template<typename E>
static E&
recentElm (Map<E>& map)
{
return *++map.rend();
}
static Elm&
recentElm (std::vector<Elm>& vec)
{
return vec.back();
}
template<class C>
static void
emplace (C& coll, Elm&& elm)
{
coll.emplace (forward<Elm> (elm));
}
static void
emplace (std::vector<Elm>& coll, Elm&& elm)
{
coll.emplace_back (forward<Elm> (elm));
}
};

View file

@ -8231,7 +8231,7 @@ On receiving a stream of tokens of this &quot;diff language&quot;, it is possibl
i.e. a ''unified diff'' or the ''predicate notation'' used above to describe the list diffing algorithm, just by accumulating changes.
</pre>
</div>
<div title="TreeMutator" creator="Ichthyostega" modifier="Ichthyostega" created="201503292115" modified="201609021520" tags="Model Concepts GuiPattern design draft" changecount="94">
<div title="TreeMutator" creator="Ichthyostega" modifier="Ichthyostega" created="201503292115" modified="201610031515" tags="Model Concepts GuiPattern design draft" changecount="95">
<pre>The TreeMutator is an intermediary to translate a generic structure pattern into heterogeneous local invocation sequences.
within the [[diff framework|TreeDiffModel]], this is a crucial joint, since here the abstract, generic, ~DOM-like ExternalTreeDescription meeds opaque, local and undisclosed data structures.
@ -8354,6 +8354,10 @@ attached to a clip, or the mixture of clips, effects and labels found within a [
:** fabricate a recursive sub-TreeMutator to deal with the (implementation data) element passed as reference
:** the ID, as taken from the (diff) spec, is also passed, for orientation
:** the lambda is expected to //place// the generated mutator into the given buffer smart handle, which takes ownership of this object
;STL map binding
:...can be supported, as an extension to the ''collection binding'' --
:* elements are (key, value) pairs
:* //use is discurraged,// since it contradicts and breaks diff semantics (due to the inherent ordering of maps)
;object field binding
:this maps the concept of &quot;Attribute&quot; onto concrete, mutable data fields
:any re-ordering and deletion of fields is ''prohibited'', while defaultable optional fields may be tolerated
@ -8377,7 +8381,7 @@ attached to a clip, or the mixture of clips, effects and labels found within a [
You should note that this entire design is recursive: only after understanding the part, where, for handling a sub-structure, a nested mutator is fabricated and placed into a given buffer, it becomes clear to what effect we're creating a customised mutator: we always need some (relative) parent scope, which happens to know more about the actual data to be treated with a TreeMutator. This scope assists with creating a suitable binding. Obviously, from within that binding, it is known what the sub-structures and children of that local data are all about and what semantics to give to the fundamental operations.
</pre>
</div>
<div title="TreeMutatorEvolution" creator="Ichthyostega" modifier="Ichthyostega" created="201603160255" modified="201609021605" tags="Model Concepts design draft" changecount="25">
<div title="TreeMutatorEvolution" creator="Ichthyostega" modifier="Ichthyostega" created="201603160255" modified="201610031511" tags="Model Concepts design draft" changecount="26">
<pre>The TreeMutator is an intermediary to translate a generic structure pattern into heterogeneous local invocation sequences.
!Motivation
@ -8492,7 +8496,7 @@ So we get to choose between
Since our goal is to represent changes to structured objects in the form of a diff message sequence, the ability to capture the essence of objects is crucial. We are not concerned with behaviour and state, yet we have to deal with the //object's visible properties.// This gets us into a design dilemma; the notion underlying our diff language is that of //structured data,// which indeed offers the concept of an //attribute// -- but visible properties are based on //object fields,// and thus have more limited capabilities, as being rooted in the class definition underlying each object. Consequently our diff language may express changes beyond the abilities of any ordinary object.
* attributes may be reordered
* attributes may be added and deleted
-- none of which has any tangible meaning for a regular (language) object. Contrast this with ExternalTreeDescription, which we crafted specifically to support diff language and diff messages, resulting in the ability to represent those changes explicitly. So, in theory, a given diff, when applied both to a GenNode and via TreeMutator to a native data structure, might lead to states not semantically equivalent. We can not reliably protect ourselves against that possibility, but, on the other hand, it is not clear if such poses an actual threat.
-- none of which has any tangible meaning for a regular (language) object. Contrast this with ExternalTreeDescription, which we crafted specifically to support diff language and diff messages, resulting in the ability to represent those changes explicitly. So, in theory, a given diff, when applied both to a GenNode and via TreeMutator to a native data structure, might lead to states not semantically equivalent. We can not reliably protect ourselves against that possibility, but, on the other hand, it is not clear if such poses an actual threat. Thus we'll tolerate extensions to the diff binding, to acknowledge usefulness in specific situations
''A possible path to reconcile'' these inner contradictions is to support the mutation primitives ''as far as is sensible''.
Through analysis of the semantics, we could distinguish several flavours of &quot;attributes&quot;, especially...
@ -8505,7 +8509,7 @@ Through analysis of the semantics, we could distinguish several flavours of &quo
;attribute map
:an ordered collection of key-value associations, which can be enumerated, searched and extended
Thus we //could define a sensible handling for each of those cases, and deal with combinations// -- but --
it seems more adequate to limit ourselves just to object fields and to include the defaultable object fields through implementation leeway. Because, in the end we really do need object fields, and anything beyond is just a materialisation of special behaviour and can be kept out of the diff system altogether. Through diff messages, we want to express structured changes, not metadata, nor closures, nor strategies, nor prototypes. And the attribute map is really something different than an object, and should be implemented separately, when it comes to applying diff messages to GenNode elements; the latter are able to //emulate// or //represent// objects, but by their nature are rather key-value associations arranged in nested scopes.
it seems more adequate to limit ourselves just to object fields and to include the defaultable object fields through implementation leeway. Because, in the end we really do need object fields, and anything beyond is just a materialisation of special behaviour and can be kept out of the diff system altogether. Through diff messages, we want to express structured changes, not metadata, nor closures, nor strategies, nor prototypes. And the attribute map is really something different than an object, and should be implemented separately, based on binding ot a //attribute collection,// when it comes to applying diff messages to GenNode elements; the latter are able to //emulate// or //represent// objects, but by their nature are rather key-value associations arranged in nested scopes.
!!!mapping rules to handle object fields
So we basically ''disallow'' anything related to ''order'', ''re-ordering'' and ''deletion'' of object fields.

View file

@ -1883,7 +1883,7 @@
<node CREATED="1456430363599" ID="ID_1608232847" MODIFIED="1456505525321" TEXT="erlaube typ-gefilterte Kinder"/>
</node>
</node>
<node COLOR="#338800" CREATED="1456506101544" FOLDED="true" HGAP="4" ID="ID_133511037" MODIFIED="1473352361466" TEXT="Implementierung" VSHIFT="16">
<node COLOR="#338800" CREATED="1456506101544" FOLDED="true" HGAP="4" ID="ID_133511037" MODIFIED="1475507065141" TEXT="Implementierung" VSHIFT="16">
<icon BUILTIN="button_ok"/>
<node CREATED="1456506128581" HGAP="-12" ID="ID_322289358" MODIFIED="1473014961683" TEXT="Abw&#xe4;gungen" VSHIFT="184">
<node CREATED="1456506135028" FOLDED="true" HGAP="29" ID="ID_470489868" MODIFIED="1472830010078" TEXT="Indirektionen" VSHIFT="-5">
@ -2833,7 +2833,7 @@
</node>
</node>
</node>
<node CREATED="1457232752458" FOLDED="true" ID="ID_1490646673" MODIFIED="1472219587187" TEXT="Attribute">
<node CREATED="1457232752458" FOLDED="true" ID="ID_1490646673" MODIFIED="1475507061988" TEXT="Attribute">
<icon BUILTIN="full-3"/>
<node CREATED="1458175823858" ID="ID_1785794072" MODIFIED="1458175828956" TEXT="Design-Grundlagen">
<node CREATED="1461882686190" ID="ID_233456976" MODIFIED="1472219338718" TEXT="von praktischer Notwendigkeit getrieben">
@ -2892,7 +2892,7 @@
<icon BUILTIN="idea"/>
</node>
</node>
<node CREATED="1458175861176" FOLDED="true" HGAP="39" ID="ID_887227300" MODIFIED="1465428527547" TEXT="Design-Anforderungen" VSHIFT="7">
<node CREATED="1458175861176" FOLDED="true" HGAP="39" ID="ID_887227300" MODIFIED="1475507055901" TEXT="Design-Anforderungen" VSHIFT="7">
<node CREATED="1458175880034" ID="ID_163174135" MODIFIED="1461888634670" TEXT="...ein Objekt hat schon ein bestimmtes Feld">
<node CREATED="1458175892400" ID="ID_640596624" MODIFIED="1461888660658" TEXT="Typ"/>
<node CREATED="1461888661462" ID="ID_1138175982" MODIFIED="1461888668033" TEXT="default-Wert"/>
@ -3007,7 +3007,7 @@
</body>
</html></richcontent>
</node>
<node CREATED="1461890009355" ID="ID_1808149320" MODIFIED="1461890064730" TEXT="aber ETD als Zwischenstufe ist m&#xf6;glich">
<node CREATED="1461890009355" ID="ID_1808149320" MODIFIED="1475506883423" TEXT="aber ETD als Zwischenstufe ist m&#xf6;glich">
<richcontent TYPE="NOTE"><html>
<head>
@ -3030,6 +3030,7 @@
</p>
</body>
</html></richcontent>
<linktarget COLOR="#807bce" DESTINATION="ID_1808149320" ENDARROW="Default" ENDINCLINATION="671;0;" ID="Arrow_ID_1677374853" SOURCE="ID_1767038604" STARTARROW="Default" STARTINCLINATION="994;0;"/>
</node>
<node CREATED="1461890240148" ID="ID_1409253452" MODIFIED="1461890244887" TEXT="Schutzmechanismen">
<node CREATED="1461890266377" ID="ID_513997188" MODIFIED="1461890283701">
@ -3129,7 +3130,7 @@
<node CREATED="1461967051095" ID="ID_328050724" MODIFIED="1461967056946" TEXT="wendet an, was anwendbar ist"/>
<node CREATED="1461967057462" ID="ID_437076290" MODIFIED="1461967068248" TEXT="alles andere &quot;durchwinken&quot;"/>
</node>
<node COLOR="#990000" CREATED="1461967003141" HGAP="29" ID="ID_1805886948" MODIFIED="1461967337361" TEXT="Design-Entscheidung" VSHIFT="19">
<node COLOR="#990000" CREATED="1461967003141" HGAP="29" ID="ID_1805886948" MODIFIED="1475506674214" TEXT="Design-Entscheidung" VSHIFT="19">
<font NAME="SansSerif" SIZE="14"/>
<icon BUILTIN="messagebox_warning"/>
<node CREATED="1461967143851" ID="ID_1596604972" MODIFIED="1461967245047">
@ -3205,6 +3206,17 @@
</node>
</node>
</node>
<node CREATED="1475506680125" HGAP="58" ID="ID_1865970661" MODIFIED="1475506689657" TEXT="Variante" VSHIFT="13">
<node CREATED="1475506691595" ID="ID_69735021" MODIFIED="1475506704861" TEXT="emptySrc -&gt; hasSrc"/>
<node CREATED="1475506705641" ID="ID_409132685" MODIFIED="1475506735169" TEXT="und den nicht implementierbaren Fall tolerieren"/>
<node CREATED="1475506735949" ID="ID_1814707193" MODIFIED="1475506746633" TEXT="im &#xdc;brigen: stets pr&#xfc;fen und scheitern">
<icon BUILTIN="yes"/>
</node>
<node COLOR="#338800" CREATED="1475506753523" HGAP="34" ID="ID_845946083" MODIFIED="1475506765947" TEXT="so umgesetzt" VSHIFT="10">
<font NAME="SansSerif" SIZE="10"/>
<icon BUILTIN="button_ok"/>
</node>
</node>
</node>
</node>
<node CREATED="1455927276314" HGAP="100" ID="ID_98863612" MODIFIED="1461946110630" TEXT="Spezifikation" VSHIFT="18">
@ -3516,8 +3528,8 @@
</node>
</node>
</node>
<node CREATED="1458178113697" FOLDED="true" HGAP="61" ID="ID_38103760" MODIFIED="1465428590343" TEXT="Design-Schlu&#xdf;folgerungen" VSHIFT="48">
<node CREATED="1463687362843" FOLDED="true" HGAP="116" ID="ID_775516687" MODIFIED="1465428540991" TEXT="Eingrenzung" VSHIFT="-28">
<node CREATED="1458178113697" FOLDED="true" HGAP="61" ID="ID_38103760" MODIFIED="1475507059437" TEXT="Design-Schlu&#xdf;folgerungen" VSHIFT="48">
<node CREATED="1463687362843" HGAP="116" ID="ID_775516687" MODIFIED="1475506631325" TEXT="Eingrenzung" VSHIFT="-28">
<node CREATED="1463687373889" ID="ID_155516876" MODIFIED="1463687400026" TEXT="Art von Attributen">
<node CREATED="1463687402462" ID="ID_1119981147" MODIFIED="1464114029013" TEXT="Objekt-Feld">
<icon BUILTIN="forward"/>
@ -3591,7 +3603,9 @@
<node CREATED="1463687461925" ID="ID_39763189" MODIFIED="1463687496231" TEXT="hier ausgeschlossen">
<icon BUILTIN="yes"/>
</node>
<node CREATED="1463687466573" ID="ID_1853473792" MODIFIED="1463687482279" TEXT="implementierbar auf Basis des Collection-Binding"/>
<node CREATED="1463687466573" ID="ID_1853473792" MODIFIED="1475507021278" TEXT="implementierbar auf Basis des Collection-Binding">
<linktarget COLOR="#9f96d9" DESTINATION="ID_1853473792" ENDARROW="Default" ENDINCLINATION="41;-121;" ID="Arrow_ID_503281678" SOURCE="ID_1112268061" STARTARROW="Default" STARTINCLINATION="1873;0;"/>
</node>
<node CREATED="1463687484338" ID="ID_1009085517" MODIFIED="1463687491613" TEXT="k&#xf6;nnte f&#xfc;r GenNode relevant sein"/>
</node>
</node>
@ -5525,8 +5539,7 @@
</li>
</ul>
</body>
</html>
</richcontent>
</html></richcontent>
</node>
</node>
<node CREATED="1475250930756" ID="ID_509435943" MODIFIED="1475250975686" TEXT="wo steckt der Diff selber">
@ -5547,8 +5560,7 @@
Marker-Typ <b>MutationMessage</b>
</p>
</body>
</html>
</richcontent>
</html></richcontent>
</node>
</node>
<node CREATED="1475250947858" ID="ID_1438298132" MODIFIED="1475250973257" TEXT="wer ist der Kommunikationspartner">
@ -5618,8 +5630,7 @@
Und f&#252;r eine reine Ref erzeugt C++ niemals eine anonyme Instanz!
</p>
</body>
</html>
</richcontent>
</html></richcontent>
</node>
<node CREATED="1475439429055" ID="ID_1383518557" MODIFIED="1475444176904" TEXT="also: embeded Buffer">
<richcontent TYPE="NOTE"><html>
@ -5643,8 +5654,7 @@
MutationMessage(blaBlubb())
</p>
</body>
</html>
</richcontent>
</html></richcontent>
<icon BUILTIN="ksmiletris"/>
</node>
<node CREATED="1475439436134" ID="ID_583247605" MODIFIED="1475444176904" TEXT="verwende InPlaceBuffer"/>
@ -5676,8 +5686,7 @@
Der Nexus speichert n&#228;mlich eine direkte Referenz in der Routingtabelle
</p>
</body>
</html>
</richcontent>
</html></richcontent>
<icon BUILTIN="messagebox_warning"/>
</node>
<node CREATED="1475449544379" ID="ID_1132064603" MODIFIED="1475449583284" TEXT="also nur per shared_ptr">
@ -5715,10 +5724,13 @@
Und es gibt nicht sowas wie das &quot;zuletzt behandelte&quot; Element
</p>
</body>
</html>
</richcontent>
</html></richcontent>
<icon BUILTIN="messagebox_warning"/>
</node>
<node CREATED="1475506967550" HGAP="42" ID="ID_1112268061" MODIFIED="1475507021278" TEXT="ist aber implementierbar" VSHIFT="8">
<arrowlink COLOR="#9f96d9" DESTINATION="ID_1853473792" ENDARROW="Default" ENDINCLINATION="41;-121;" ID="Arrow_ID_503281678" STARTARROW="Default" STARTINCLINATION="1873;0;"/>
<font ITALIC="true" NAME="SansSerif" SIZE="12"/>
</node>
<node CREATED="1475449719180" ID="ID_6178930" MODIFIED="1475449724993" TEXT="Sinnvoll das zu erweitern">
<icon BUILTIN="help"/>
<node CREATED="1475450034810" ID="ID_445949466" MODIFIED="1475450443961" TEXT="pro">
@ -5741,8 +5753,7 @@
erhalten!
</p>
</body>
</html>
</richcontent>
</html></richcontent>
<node CREATED="1475450179591" ID="ID_793985703" MODIFIED="1475450197936" TEXT="dann sogar del"/>
<node CREATED="1475450053927" ID="ID_1110207658" MODIFIED="1475450055018" TEXT="pick"/>
</node>
@ -5764,8 +5775,7 @@
Das bricht mit unserem grunds&#228;tzlichen Konzept der <b>kongruenten</b>&#160; Daten-Strukturen
</p>
</body>
</html>
</richcontent>
</html></richcontent>
<icon BUILTIN="messagebox_warning"/>
</node>
<node CREATED="1475450272442" ID="ID_567969130" MODIFIED="1475450429317" TEXT="inkompatibel mit GenNode">
@ -5781,25 +5791,63 @@
l&#228;&#223;t sich nicht auf eine Map-Implementierung aufspielen
</p>
</body>
</html>
</richcontent>
</html></richcontent>
<icon BUILTIN="messagebox_warning"/>
</node>
</node>
</node>
<node CREATED="1475450448290" ID="ID_1738216720" MODIFIED="1475450466683">
<node CREATED="1475506346525" ID="ID_574367406" MODIFIED="1475506428740" VSHIFT="6">
<richcontent TYPE="NODE"><html>
<head>
</head>
<body>
<p>
Entscheidung: <i>abgelehnt</i>
Entscheidung
</p>
</body>
</html></richcontent>
<icon BUILTIN="yes"/>
<node CREATED="1475506358863" ID="ID_120379432" MODIFIED="1475506391795" TEXT="wird nicht empfohlen">
<font ITALIC="true" NAME="SansSerif" SIZE="13"/>
</node>
<node CREATED="1475506368078" ID="ID_1568414977" MODIFIED="1475506381941" TEXT="vollst&#xe4;ndigkeitshalber unterst&#xfc;tzt">
<font NAME="SansSerif" SIZE="11"/>
</node>
<node CREATED="1475506411768" ID="ID_583086851" MODIFIED="1475506507414" TEXT="kann sinnvoll sein...">
<richcontent TYPE="NOTE"><html>
<head>
</head>
<body>
<p>
...zum Beispiel wie grade hier, beim MockElm
</p>
<p>
das wird vermutlich niemals wirklich in einem vollen Diff-Zusammenhang gebraucht.
</p>
<p>
</p>
<p>
Und dann ist unbestreitbar eine Map eine sehr einfache Implementierung
</p>
<p>
und auch im Diff-Applikator nicht wirklich schwierig zu unterst&#252;tzen
</p>
</body>
</html>
</richcontent>
<icon BUILTIN="yes"/>
<font NAME="SansSerif" SIZE="10"/>
</node>
<node COLOR="#338800" CREATED="1475506514203" HGAP="45" ID="ID_1183193114" MODIFIED="1475506577093" TEXT="Begr&#xfc;ndung" VSHIFT="23">
<node CREATED="1475506528937" ID="ID_1971084550" MODIFIED="1475506538324" TEXT="es verletzt die Prinzipien"/>
<node CREATED="1475506538983" ID="ID_1555995664" MODIFIED="1475506547491" TEXT="insofern aber wie Feld-Attribute auch"/>
<node CREATED="1475506549886" ID="ID_275560362" MODIFIED="1475506558609" TEXT="eingeschr&#xe4;nkt unterst&#xfc;tzbar"/>
<node CREATED="1475506559309" ID="ID_1767038604" MODIFIED="1475506896798" TEXT="Objekt -&gt; ETD -&gt; Objekt">
<arrowlink COLOR="#807bce" DESTINATION="ID_1808149320" ENDARROW="Default" ENDINCLINATION="671;0;" ID="Arrow_ID_1677374853" STARTARROW="Default" STARTINCLINATION="994;0;"/>
</node>
</node>
</node>
</node>
</node>