From aa96cb6dd1ea7c9c12072a433f3404eb4c629418 Mon Sep 17 00:00:00 2001 From: Ichthyostega Date: Fri, 28 Aug 2015 16:12:04 +0200 Subject: [PATCH] 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. --- src/lib/diff/diff.cpp | 42 +++++++++++++++++++++++++++++++++++++++ src/lib/diff/gen-node.hpp | 7 +++++-- wiki/renderengine.html | 4 ++-- 3 files changed, 49 insertions(+), 4 deletions(-) diff --git a/src/lib/diff/diff.cpp b/src/lib/diff/diff.cpp index 6cedeeeb2..af7be6ee3 100644 --- a/src/lib/diff/diff.cpp +++ b/src/lib/diff/diff.cpp @@ -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::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 diff --git a/src/lib/diff/gen-node.hpp b/src/lib/diff/gen-node.hpp index 58c2d32fd..7edc88433 100644 --- a/src/lib/diff/gen-node.hpp +++ b/src/lib/diff/gen-node.hpp @@ -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); } diff --git a/wiki/renderengine.html b/wiki/renderengine.html index 65a3b8f0f..e12057bbf 100644 --- a/wiki/renderengine.html +++ b/wiki/renderengine.html @@ -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 -
+
//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.