implement full data-based equality for GenNode

initially my intention was to use the ID for equality test.
But on a second thought, this seemed like a bad idea, since
it confuses the concepts of equality and identity.

Note: at the moment, I do not know if we even need an equality test,
so it is provided here rather for sake of completeness. And this
means even more that we want an 'equality' implementation that
does what one would naively expect: compare the object identity
*and* compare the contents.
This commit is contained in:
Fischlurch 2015-08-28 16:12:04 +02:00
parent 1024cea2c8
commit aa96cb6dd1
3 changed files with 49 additions and 4 deletions

View file

@ -51,4 +51,46 @@ namespace diff{
Ref Ref::ATTRIBS("_ATTRIBS_");
/** Implementation of content equality test */
bool
DataCap::operator== (DataCap const& o) const
{
class EqualityTest
: public Variant<DataValues>::Visitor
{
DataCap const& o_;
bool isEqual_;
#define DERIVE_EQUALITY(_TY_) \
virtual void handle (_TY_& val) override { isEqual_ = (o_.get<_TY_>() == val); }
DERIVE_EQUALITY (int)
DERIVE_EQUALITY (int64_t)
DERIVE_EQUALITY (short)
DERIVE_EQUALITY (char)
DERIVE_EQUALITY (bool)
DERIVE_EQUALITY (double)
DERIVE_EQUALITY (string)
DERIVE_EQUALITY (time::Time)
DERIVE_EQUALITY (time::Offset)
DERIVE_EQUALITY (time::Duration)
DERIVE_EQUALITY (time::TimeSpan)
DERIVE_EQUALITY (hash::LuidH)
DERIVE_EQUALITY (RecRef)
DERIVE_EQUALITY (Rec)
public:
EqualityTest(DataCap const& o)
: o_(o)
, isEqual_(false)
{ }
operator bool() { return isEqual_; }
};
EqualityTest visitor(o);
unConst(this)->accept(visitor);
return visitor;
}
}} // namespace lib::diff

View file

@ -176,6 +176,8 @@ namespace diff{
DataCap& operator= (DataCap const&) =default;
DataCap& operator= (DataCap&&) =default;
bool operator== (DataCap const&) const;
};
@ -273,13 +275,14 @@ namespace diff{
friend bool
operator== (GenNode const& n1, GenNode const& n2)
{
return n1.idi == n2.idi;
return n1.idi == n2.idi
&& n1.data == n2.data;
}
friend bool
operator!= (GenNode const& n1, GenNode const& n2)
{
return n1.idi != n2.idi;
return ! (n1 == n2);
}

View file

@ -7947,7 +7947,7 @@ Used this way, diff representation helps to separate structure and raw data in e
:Chunks of raw data are attached inline to the structural diff, assuming that each element implicitly knows the kind of data to expect
</pre>
</div>
<div title="TreeDiffImplementation" creator="Ichthyostega" modifier="Ichthyostega" created="201412210015" modified="201507041449" tags="Model GuiPattern design draft" changecount="38">
<div title="TreeDiffImplementation" creator="Ichthyostega" modifier="Ichthyostega" created="201412210015" modified="201508281207" tags="Model GuiPattern design draft" changecount="39">
<pre>//This page details decisions taken for implementation of Lumiera's diff handling framework//
This topic is rather abstract, since diff handling is multi purpose within Lumiera: Diff representation is seen as a meta language and abstraction mechanism; it enables tight collaboration without the need to tie and tangle the involved implementation data structures. Used this way, diff representation reduces coupling and helps to cut down overall complexity -- so to justify the considerable amount of complexity seen within the diff framework implementation.
@ -7987,7 +7987,7 @@ Our tree diff handling framework is conceived as a direct specialisation of and
* nodes representing //objects// may have attribute children, which are always mentioned before the sub node children.
* when a node is //opened for diffing,// we first spell out any structural alterations (added, deleted or re-ordered children)
* the recursive descent into children happens postfix depth-first, each enclosed into a bracketing construct.
Consequently, when an element appears in the diff description sequence, first of all, its type is immediately clear, so the receiver can use an appropriate handler for this kind of element. Moreover, if the element is of atomic type (an attribute), its value is part of the element itself and thus is known just by spelling out the element. Any structural changes can be dealt with on a completely generic level, without further knowledge about the object's nature. And finally, any internal alterations of the object and its children happen after the generic part and clearly delineated in the sequence of diff tokens -- a sub handler can be invoked recursively
Consequently, when an element appears in the diff description sequence, first of all, its type is assumed to be known implicitly, so the receiver can use an appropriate handler for this kind of element. Moreover, if the element is of atomic type (an attribute), its value is part of the element itself and thus is known just by spelling out the element. Any structural changes can be dealt with on a completely generic level, without further knowledge about the object's nature. And finally, any internal alterations of the object and its children happen after the generic part and clearly delineated in the sequence of diff tokens -- a sub handler can be invoked recursively
!!!problem of the typed context
This is a problem every introspective framework has to face. When individual elements in the data structure require specific type information for proper handling, this information must be readily available, once we start doing anything of significance with the generic data representation. A naive implementation would attach the type identification to a descriptor record exposed alongside with the data representation, thereby forcing the client back into the worst conceivable programming style, suffocating any beneficial effect the use of types and contracts might have on understandability and maintainability of the code: Either, you'll just assume everything goes well, or you end up being prepared for anything conceivable, or -- even worse -- a combination of both evils.