after sleeping one night over the problem, this seems to be the most natural solution, since the possibility of assignment naturally arises from the fact that, for tree diff, we have to distinguish between the *identity* of an element node and its payload (which could be recursive). Thus, IFF the payoad is an assignable value, why not allow to assign it. Doing so elegnatly solves the problem with assignment of attributes Signed-off-by: Ichthyostega <prg@ichthyostega.de>
293 lines
7.3 KiB
C++
293 lines
7.3 KiB
C++
/*
|
|
GenNode - generic node element for tree like data representation
|
|
|
|
Copyright (C) Lumiera.org
|
|
2015, Hermann Vosseler <Ichthyostega@web.de>
|
|
|
|
This program is free software; you can redistribute it and/or
|
|
modify it under the terms of the GNU General Public License as
|
|
published by the Free Software Foundation; either version 2 of
|
|
the License, or (at your option) any later version.
|
|
|
|
This program is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
GNU General Public License for more details.
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
along with this program; if not, write to the Free Software
|
|
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
|
|
|
* *****************************************************/
|
|
|
|
|
|
/** @file gen-node.cpp
|
|
** Generic node element (implementation parts).
|
|
** Some of the more technical details regarding value access and
|
|
** comparisons has been moved down within this compilation unit,
|
|
** to cut down compilation time.
|
|
**
|
|
** \par comparison and match
|
|
**
|
|
** The DataCap element provides a set of functions to check for \em equivalence
|
|
** or match. These are used to build a recursive containment check. To implement
|
|
** such predicates, we need to build a one-way off visitor for use with lib::Variant.
|
|
** These specifically tailored functors only define \c handle(TY) functions for the
|
|
** cases actually of interest. All other cases invoke the default handling, which
|
|
** returns \c false.
|
|
**
|
|
** @see gen-node-basic-test.cpp
|
|
**
|
|
*/
|
|
|
|
|
|
#include "lib/error.hpp"
|
|
#include "lib/diff/diff-language.hpp"
|
|
#include "lib/diff/gen-node.hpp"
|
|
#include "lib/util-quant.hpp"
|
|
#include "lib/variant.hpp"
|
|
|
|
#include <boost/lexical_cast.hpp>
|
|
|
|
|
|
using boost::lexical_cast;
|
|
using lib::time::TimeValue;
|
|
using util::almostEqual;
|
|
using lib::hash::LuidH;
|
|
|
|
|
|
namespace lib {
|
|
namespace diff{
|
|
|
|
/* symbolic marker ID references
|
|
* used within the tree diff language
|
|
* to mark specific scopes and situations
|
|
*/
|
|
const Ref Ref::I ("_I_");
|
|
const Ref Ref::NO ("_NO_");
|
|
const Ref Ref::END ("_END_");
|
|
const Ref Ref::THIS ("_THIS_");
|
|
const Ref Ref::CHILD ("_CHILD_");
|
|
const Ref Ref::ATTRIBS("_ATTRIBS_");
|
|
|
|
|
|
|
|
|
|
/** Implementation of content equality test, delgating to content
|
|
* @throws error::Logic when the given other DataCap
|
|
* does not hold a value of the same type than
|
|
* this DataCap.
|
|
* @remarks since the GenNode::ID is generated including a type hash,
|
|
* the equality operator of GenNode ensures this content test
|
|
* is only called on a compatible DataCap.
|
|
*/
|
|
bool
|
|
DataCap::matchData (DataCap const& o) const
|
|
{
|
|
class EqualityTest
|
|
: public Variant<DataValues>::Predicate
|
|
{
|
|
DataCap const& o_;
|
|
|
|
#define DERIVE_EQUALITY(_TY_) \
|
|
virtual bool handle (_TY_ const& val) override { return (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 (Rec)
|
|
|
|
/** special treatment to allow matching a RecRef
|
|
* with an Record or RecRef on the other side */
|
|
virtual bool
|
|
handle (RecRef const& val) override
|
|
{
|
|
return o_.matchRec(val);
|
|
}
|
|
|
|
public:
|
|
EqualityTest(DataCap const& o)
|
|
: o_(o)
|
|
{ }
|
|
};
|
|
|
|
EqualityTest visitor(o);
|
|
return accept(visitor);
|
|
}
|
|
|
|
|
|
bool
|
|
DataCap::matchNum (int64_t num) const
|
|
{
|
|
class MatchNumber
|
|
: public Variant<DataValues>::Predicate
|
|
{
|
|
int64_t num_;
|
|
|
|
#define MATCH_NUMBER(_TY_) \
|
|
virtual bool handle (_TY_ const& val) override { return val == num_; }
|
|
|
|
MATCH_NUMBER (int)
|
|
MATCH_NUMBER (int64_t)
|
|
MATCH_NUMBER (short)
|
|
MATCH_NUMBER (char)
|
|
MATCH_NUMBER (double)
|
|
|
|
public:
|
|
MatchNumber(int64_t num)
|
|
: num_(num)
|
|
{ }
|
|
};
|
|
|
|
MatchNumber visitor(num);
|
|
return accept(visitor);
|
|
}
|
|
|
|
|
|
bool
|
|
DataCap::matchDbl (double d) const
|
|
{
|
|
class MatchDouble
|
|
: public Variant<DataValues>::Predicate
|
|
{
|
|
double num_;
|
|
|
|
#define MATCH_DOUBLE(_TY_) \
|
|
virtual bool handle (_TY_ const& val) override { return almostEqual (double(val), num_); }
|
|
|
|
MATCH_DOUBLE (int)
|
|
MATCH_DOUBLE (int64_t)
|
|
MATCH_DOUBLE (short)
|
|
MATCH_DOUBLE (char)
|
|
MATCH_DOUBLE (double)
|
|
|
|
public:
|
|
MatchDouble(double d)
|
|
: num_(d)
|
|
{ }
|
|
};
|
|
|
|
MatchDouble visitor(d);
|
|
return accept(visitor);
|
|
}
|
|
|
|
|
|
bool
|
|
DataCap::matchTxt (string const& text) const
|
|
{
|
|
class MatchString
|
|
: public Variant<DataValues>::Predicate
|
|
{
|
|
string const& txt_;
|
|
|
|
#define MATCH_STRING(_TY_) \
|
|
virtual bool handle (_TY_ const& val) override { return lexical_cast<string>(val) == txt_; }
|
|
|
|
MATCH_STRING (int)
|
|
MATCH_STRING (int64_t)
|
|
MATCH_STRING (short)
|
|
MATCH_STRING (double)
|
|
MATCH_STRING (bool)
|
|
|
|
virtual bool handle (string const& str) override { return str == txt_; }
|
|
virtual bool handle (char const& c ) override { return 1 == txt_.length() && txt_.front() == c; }
|
|
|
|
public:
|
|
MatchString(string const& text)
|
|
: txt_(text)
|
|
{ }
|
|
};
|
|
|
|
MatchString visitor(text);
|
|
return accept(visitor);
|
|
}
|
|
|
|
|
|
bool
|
|
DataCap::matchTime (TimeValue time) const
|
|
{
|
|
class MatchTime
|
|
: public Variant<DataValues>::Predicate
|
|
{
|
|
TimeValue& t_;
|
|
|
|
#define MATCH_TIME(_TY_) \
|
|
virtual bool handle (_TY_ const& val) override { return val == t_; }
|
|
|
|
MATCH_TIME (time::Time)
|
|
MATCH_TIME (time::Offset)
|
|
MATCH_TIME (time::Duration)
|
|
MATCH_TIME (time::TimeSpan)
|
|
MATCH_TIME (hash::LuidH)
|
|
|
|
public:
|
|
MatchTime(TimeValue& t)
|
|
: t_(t)
|
|
{ }
|
|
};
|
|
|
|
MatchTime visitor(time);
|
|
return accept(visitor);
|
|
}
|
|
|
|
|
|
bool
|
|
DataCap::matchBool (bool b) const
|
|
{
|
|
bool* val = unConst(this)->maybeGet<bool>();
|
|
return val && (b == *val);
|
|
}
|
|
|
|
|
|
bool
|
|
DataCap::matchLuid (LuidH hash) const
|
|
{
|
|
LuidH* val = unConst(this)->maybeGet<LuidH>();
|
|
return val && (hash == *val);
|
|
}
|
|
|
|
|
|
bool
|
|
DataCap::matchRec (RecRef const& ref) const
|
|
{
|
|
if (ref)
|
|
return matchRec (*ref.get());
|
|
else
|
|
{
|
|
RecRef* val = unConst(this)->maybeGet<RecRef>();
|
|
return val && val->empty();
|
|
}
|
|
}
|
|
|
|
|
|
bool
|
|
DataCap::matchRec (Rec const& rec) const
|
|
{
|
|
Rec* val = unConst(this)->maybeGet<Rec>();
|
|
if (!val)
|
|
{
|
|
RecRef* r = unConst(this)->maybeGet<RecRef>();
|
|
if (r) val = r->get();
|
|
}
|
|
return val && (rec == *val);
|
|
}
|
|
|
|
|
|
|
|
|
|
DataCap::operator string() const
|
|
{
|
|
return "DataCap|"+string(this->buffer());
|
|
}
|
|
|
|
|
|
}} // namespace lib::diff
|