mirror of
https://github.com/swift-project/pilotclient.git
synced 2026-03-22 14:55:36 +08:00
using hashes to perform comparisons between blackmisc value objects stored inside of QVariant
refs #81
This commit is contained in:
committed by
Mathew Sutcliffe
parent
67a5dbfe48
commit
a280d239e6
@@ -58,6 +58,28 @@ namespace BlackMisc
|
||||
return !((*this) == other);
|
||||
}
|
||||
|
||||
/*
|
||||
* Compare
|
||||
*/
|
||||
int CAltitude::compare(const QVariant &qv) const
|
||||
{
|
||||
Q_ASSERT(qv.canConvert<CAltitude>() || qv.canConvert<CLength>());
|
||||
Q_ASSERT(qv.isValid() && !qv.isNull());
|
||||
if (qv.canConvert<CAltitude>())
|
||||
{
|
||||
CAltitude other = qv.value<CAltitude>();
|
||||
if (this->isMeanSeaLevel() && other.isAboveGroundLevel()) return 1;
|
||||
if (this->isAboveGroundLevel() && other.isMeanSeaLevel()) return -1;
|
||||
return this->compare(other);
|
||||
}
|
||||
else if (qv.canConvert<CLength>())
|
||||
{
|
||||
return this->compare(qv.value<CLength>());
|
||||
}
|
||||
qFatal("Invalid comparison");
|
||||
return 0; // just for compiler
|
||||
}
|
||||
|
||||
/*
|
||||
* Register metadata
|
||||
*/
|
||||
|
||||
@@ -122,6 +122,17 @@ namespace BlackMisc
|
||||
return m_datum;
|
||||
}
|
||||
|
||||
/*!
|
||||
* \copydoc BlackObject::compare
|
||||
*/
|
||||
virtual int compare(const QVariant &qv) const;
|
||||
|
||||
/*!
|
||||
* \todo this is a hack, to avoid hiding inherited names in CPhysicalQuantity
|
||||
* (see Effective C++ item 33) CPhysicalQuantity::compare is the real culprit
|
||||
*/
|
||||
int compare(const CLength &other) const { return static_cast<const CLength *>(this)->compare(other); }
|
||||
|
||||
/*!
|
||||
* \brief Register metadata
|
||||
*/
|
||||
|
||||
@@ -87,6 +87,15 @@ namespace BlackMisc
|
||||
return QVariant::fromValue(*this);
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Value hash
|
||||
* \return
|
||||
*/
|
||||
virtual uint getValueHash() const
|
||||
{
|
||||
return CModulator::getValueHash();
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Constructor
|
||||
* \param name
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
#include "blackmisc/aviocomsystem.h"
|
||||
#include "blackmisc/avionavsystem.h"
|
||||
#include "blackmisc/avioadfsystem.h"
|
||||
#include "blackmisc/blackmiscfreefunctions.h"
|
||||
|
||||
using BlackMisc::PhysicalQuantities::CFrequency;
|
||||
using BlackMisc::PhysicalQuantities::CFrequencyUnit;
|
||||
@@ -76,6 +77,18 @@ namespace BlackMisc
|
||||
argument >> this->m_digits;
|
||||
}
|
||||
|
||||
/*
|
||||
* Value hash
|
||||
*/
|
||||
template <class AVIO> uint CModulator<AVIO>::getValueHash() const
|
||||
{
|
||||
QList<uint> hashs;
|
||||
hashs << this->m_frequencyActive.getValueHash();
|
||||
hashs << this->m_frequencyStandby.getValueHash();
|
||||
hashs << qHash(this->m_digits);
|
||||
return BlackMisc::calculateHash(hashs, "CModulator");
|
||||
}
|
||||
|
||||
// see here for the reason of thess forward instantiations
|
||||
// http://www.parashift.com/c++-faq/separate-template-class-defn-from-decl.html
|
||||
template class CModulator<CComSystem>;
|
||||
|
||||
@@ -214,6 +214,12 @@ namespace BlackMisc
|
||||
*/
|
||||
virtual void unmarshallFromDbus(const QDBusArgument &argument);
|
||||
|
||||
/*!
|
||||
* \brief Value hash
|
||||
* \return
|
||||
*/
|
||||
virtual uint getValueHash() const;
|
||||
|
||||
public:
|
||||
/*!
|
||||
* \brief Virtual destructor
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "blackmisc/aviotransponder.h"
|
||||
#include "blackmisc/blackmiscfreefunctions.h"
|
||||
|
||||
namespace BlackMisc
|
||||
{
|
||||
@@ -136,6 +137,18 @@ namespace BlackMisc
|
||||
this->m_transponderMode = static_cast<TransponderMode>(tm);
|
||||
}
|
||||
|
||||
/*
|
||||
* Value hash
|
||||
*/
|
||||
uint CTransponder::getValueHash() const
|
||||
{
|
||||
QList<uint> hashs;
|
||||
hashs << qHash(this->m_name);
|
||||
hashs << qHash(this->m_transponderCode);
|
||||
hashs << qHash(this->m_transponderMode);
|
||||
return BlackMisc::calculateHash(hashs, "CTransponder");
|
||||
}
|
||||
|
||||
/*
|
||||
* Register metadata of unit and quantity
|
||||
*/
|
||||
|
||||
@@ -331,6 +331,12 @@ namespace BlackMisc
|
||||
return CTransponder::tryGetTransponder(o_transponder, "Transponder", transponderCode, mode);
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Value hash
|
||||
* \return
|
||||
*/
|
||||
virtual uint getValueHash() const;
|
||||
|
||||
/*!
|
||||
* \brief Register metadata of unit and quantity
|
||||
*/
|
||||
|
||||
@@ -81,6 +81,98 @@ void BlackMisc::initResources()
|
||||
{
|
||||
initBlackMiscResources();
|
||||
}
|
||||
|
||||
/*
|
||||
* Stupid extension bo be able to compare 2 QVariants
|
||||
*/
|
||||
bool BlackMisc::equalQVariants(const QVariant &v1, const QVariant &v2)
|
||||
{
|
||||
// prephase, shortcuts
|
||||
if (v1 == v2) return true; // compares on primitives or on address
|
||||
if (!v1.isValid() || !v2.isValid()) return false;
|
||||
if (v1.type() != v2.type()) return false;
|
||||
if (v1.userType() != v2.userType()) return false;
|
||||
|
||||
// I have same types now
|
||||
const CValueObject *cs1 = CValueObject::fromQVariant(v1);
|
||||
const CValueObject *cs2 = CValueObject::fromQVariant(v2);
|
||||
if (cs1 && cs2)
|
||||
{
|
||||
uint h1 = cs1->getValueHash();
|
||||
uint h2 = cs2->getValueHash();
|
||||
return h1 == h2;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/*
|
||||
* Compare values
|
||||
*/
|
||||
int BlackMisc:: compareQVariants(const QVariant &v1, const QVariant &v2)
|
||||
{
|
||||
if (v1 == v2) return 0; // compares on primitives or on address
|
||||
|
||||
if (!v1.isValid() || !v2.isValid()) qFatal("Invalid variants");
|
||||
if (v1.type() != v2.type()) qFatal("Mismatching types");
|
||||
if (v1.userType() != v2.userType()) qFatal("Mismatching user types");
|
||||
|
||||
switch (v1.type())
|
||||
{
|
||||
case QMetaType::QString:
|
||||
{
|
||||
QString s1 = v1.value<QString>();
|
||||
QString s2 = v2.value<QString>();
|
||||
return s1.compare(s2);
|
||||
}
|
||||
case QMetaType::QDateTime:
|
||||
{
|
||||
QDateTime dt1 = v1.value<QDateTime>();
|
||||
QDateTime dt2 = v2.value<QDateTime>();
|
||||
if (dt1 == dt2) return 0;
|
||||
return dt1 < dt2 ? -1 : 1;
|
||||
}
|
||||
case QMetaType::QDate:
|
||||
{
|
||||
QDate d1 = v1.value<QDate>();
|
||||
QDate d2 = v2.value<QDate>();
|
||||
if (d1 == d2) return 0;
|
||||
return d1 < d2 ? -1 : 1;
|
||||
}
|
||||
case QMetaType::QTime:
|
||||
{
|
||||
QTime t1 = v1.value<QTime>();
|
||||
QTime t2 = v2.value<QTime>();
|
||||
if (t1 == t2) return 0;
|
||||
return t1 < t2 ? -1 : 1;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
// BlackObject
|
||||
if (v1.type() == QVariant::UserType)
|
||||
{
|
||||
const CValueObject *cs1 = CValueObject::fromQVariant(v1);
|
||||
const CValueObject *cs2 = CValueObject::fromQVariant(v2);
|
||||
if (cs1 && cs2)
|
||||
{
|
||||
return cs1->compare(v2); // Note, that I have to compare against QVariant
|
||||
}
|
||||
}
|
||||
|
||||
// all kind of numeric values
|
||||
if (v1.canConvert<double>())
|
||||
{
|
||||
double d1 = v1.value<double>();
|
||||
double d2 = v2.value<double>();
|
||||
if (d1 == d2) return 0;
|
||||
return d1 < d2 ? -1 : 1;
|
||||
}
|
||||
|
||||
qFatal("Unknown type for compare");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/*
|
||||
* To string
|
||||
*/
|
||||
@@ -98,6 +190,27 @@ QString BlackMisc::qVariantToString(const QVariant &qv, bool i18n)
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Add hash values
|
||||
*/
|
||||
uint BlackMisc::calculateHash(const QList<uint> &values, const char *className)
|
||||
{
|
||||
// http://stackoverflow.com/questions/113511/hash-code-implementation/113600#113600
|
||||
if (values.isEmpty()) return 0;
|
||||
uint hash = values.first();
|
||||
for (int i = 1; i < values.size(); i++)
|
||||
{
|
||||
hash = 37 * hash + values.at(i);
|
||||
}
|
||||
|
||||
// same values, but different class?
|
||||
if (className)
|
||||
{
|
||||
hash = 37 * hash + qHash(QString(className));
|
||||
}
|
||||
return hash;
|
||||
}
|
||||
|
||||
/*
|
||||
* Fix QVariant if it comes from DBus and contains QDBusArgument
|
||||
*/
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
#define BLACKMISC_FREEFUNCTIONS_H
|
||||
|
||||
#include <QDir> // for Q_INIT_RESOURCE
|
||||
#include <QList>
|
||||
#include <QVariant>
|
||||
#include <QDBusArgument>
|
||||
|
||||
@@ -81,6 +82,21 @@ namespace BlackMisc
|
||||
*/
|
||||
void initResources();
|
||||
|
||||
/*!
|
||||
* \brief Compare 2 QVariants
|
||||
* \param v1
|
||||
* \param v2
|
||||
*/
|
||||
bool equalQVariants(const QVariant &v1, const QVariant &v2);
|
||||
|
||||
/*!
|
||||
* \brief Compare QVariants
|
||||
* \param v1
|
||||
* \param v2
|
||||
* \return
|
||||
*/
|
||||
int compareQVariants(const QVariant &v1, const QVariant &v2);
|
||||
|
||||
/*!
|
||||
* \brief QVariant to string, allows to stringify CValueObject
|
||||
* \param qv
|
||||
@@ -109,6 +125,14 @@ namespace BlackMisc
|
||||
// TODO: To be removed if a better solution is found
|
||||
QVariant complexQtTypeFromDbusArgument(const QDBusArgument &argument, int type);
|
||||
|
||||
/*!
|
||||
* \brief Add several hash values
|
||||
* \param values
|
||||
* \param classTypeId
|
||||
* \return
|
||||
*/
|
||||
uint calculateHash(const QList<uint> &values, const char *className);
|
||||
|
||||
} // BlackMisc
|
||||
|
||||
#endif // guard
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "blackmisc/coordinategeodetic.h"
|
||||
#include "blackmisc/blackmiscfreefunctions.h"
|
||||
|
||||
namespace BlackMisc
|
||||
{
|
||||
@@ -67,6 +68,18 @@ namespace BlackMisc
|
||||
qDBusRegisterMetaType<CCoordinateGeodetic>();
|
||||
}
|
||||
|
||||
/*
|
||||
* Hash
|
||||
*/
|
||||
uint CCoordinateGeodetic::getValueHash() const
|
||||
{
|
||||
QList<uint> hashs;
|
||||
hashs << this->m_latitude.getValueHash();
|
||||
hashs << this->m_longitude.getValueHash();
|
||||
hashs << this->m_height.getValueHash();
|
||||
return BlackMisc::calculateHash(hashs, "CCoordinateGeodetic");
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Great circle distance
|
||||
|
||||
@@ -217,6 +217,11 @@ namespace BlackMisc
|
||||
*/
|
||||
bool operator !=(const CCoordinateGeodetic &other) const;
|
||||
|
||||
/*!
|
||||
* \brief value Hash
|
||||
*/
|
||||
virtual uint getValueHash() const;
|
||||
|
||||
/*!
|
||||
* Register metadata
|
||||
*/
|
||||
|
||||
@@ -71,6 +71,18 @@ namespace BlackMisc
|
||||
return LATorLON(a);
|
||||
}
|
||||
|
||||
/*
|
||||
* Compare
|
||||
*/
|
||||
template <class LATorLON> int CEarthAngle<LATorLON>::compare(const QVariant &qv) const
|
||||
{
|
||||
Q_ASSERT(qv.canConvert<LATorLON>() || qv.canConvert<CAngle>());
|
||||
Q_ASSERT(qv.isValid() && !qv.isNull());
|
||||
if (qv.canConvert<LATorLON>())
|
||||
return this->toAngle().compare(qv.value<LATorLON>().toAngle());
|
||||
else
|
||||
return this->toAngle().compare(qv.value<CAngle>());
|
||||
}
|
||||
|
||||
// see here for the reason of thess forward instantiations
|
||||
// http://www.parashift.com/c++-faq/separate-template-class-defn-from-decl.html
|
||||
|
||||
@@ -184,6 +184,11 @@ namespace BlackMisc
|
||||
return BlackMisc::PhysicalQuantities::CAngle(static_cast<BlackMisc::PhysicalQuantities::CAngle>(*this));
|
||||
}
|
||||
|
||||
/*!
|
||||
* Compare
|
||||
*/
|
||||
int compare(const QVariant &qv) const;
|
||||
|
||||
/*!
|
||||
* Register metadata
|
||||
*/
|
||||
|
||||
@@ -138,6 +138,23 @@ namespace BlackMisc
|
||||
return s;
|
||||
}
|
||||
|
||||
/*
|
||||
* Hash
|
||||
*/
|
||||
template <class ImplMatrix, int Rows, int Columns> uint CMatrixBase<ImplMatrix, Rows, Columns>::getValueHash() const
|
||||
{
|
||||
const QList<double> l = this->toList();
|
||||
QList<uint> hashs;
|
||||
|
||||
// there is an issue with the signature of QList, so I use
|
||||
// individual values
|
||||
foreach(double v, l)
|
||||
{
|
||||
hashs << qHash(static_cast<long>(v));
|
||||
}
|
||||
return BlackMisc::calculateHash(hashs, "CMatrixBase");
|
||||
}
|
||||
|
||||
/*
|
||||
* To DBus
|
||||
*/
|
||||
|
||||
@@ -89,6 +89,12 @@ namespace BlackMisc
|
||||
*/
|
||||
QList<double> toList() const;
|
||||
|
||||
/*!
|
||||
* \brief Value hash
|
||||
* \return
|
||||
*/
|
||||
virtual uint getValueHash() const;
|
||||
|
||||
/*!
|
||||
* \brief List of values
|
||||
* \return
|
||||
|
||||
@@ -144,6 +144,18 @@ namespace BlackMisc
|
||||
argument >> this->m_k;
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Stream to DBus
|
||||
* \param argument
|
||||
*/
|
||||
template <class ImplVector> uint CVector3DBase<ImplVector>::getValueHash() const
|
||||
{
|
||||
QList<uint> hashs;
|
||||
hashs << qHash(static_cast<long>(this->m_i));
|
||||
hashs << qHash(static_cast<long>(this->m_j));
|
||||
hashs << qHash(static_cast<long>(this->m_k));
|
||||
return BlackMisc::calculateHash(hashs, "CVector3DBase");
|
||||
}
|
||||
|
||||
/*
|
||||
* Register metadata
|
||||
|
||||
@@ -323,6 +323,12 @@ namespace BlackMisc
|
||||
*/
|
||||
CMatrix3x1 toMatrix3x1() const;
|
||||
|
||||
/*!
|
||||
* \brief Value hash
|
||||
* \return
|
||||
*/
|
||||
virtual uint getValueHash() const;
|
||||
|
||||
/*!
|
||||
* \brief length / magnitude
|
||||
* \return
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
#include <QDebug>
|
||||
#include <QSharedData>
|
||||
#include <QSharedDataPointer>
|
||||
#include <QHash>
|
||||
|
||||
namespace BlackMisc
|
||||
{
|
||||
@@ -301,6 +302,14 @@ namespace BlackMisc
|
||||
return i18n ? QCoreApplication::translate("CMeasurementUnit", this->m_symbol.toStdString().c_str()) : this->m_symbol;
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Value hash
|
||||
* \return
|
||||
*/
|
||||
virtual uint getValueHash() const
|
||||
{
|
||||
return qHash(this->getName());
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Rounded value
|
||||
|
||||
@@ -254,6 +254,36 @@ namespace BlackMisc
|
||||
return this->valueRoundedWithUnit(this->getUnit(), -1, i18n);
|
||||
}
|
||||
|
||||
/*
|
||||
* Hash
|
||||
*/
|
||||
template <class MU, class PQ> uint CPhysicalQuantity<MU, PQ>::getValueHash() const
|
||||
{
|
||||
QList<uint> hashs;
|
||||
hashs << this->m_unit.getValueHash();
|
||||
hashs << qHash(static_cast<long>(this->m_value));
|
||||
return BlackMisc::calculateHash(hashs, "PQ");
|
||||
}
|
||||
|
||||
/*
|
||||
* Compare
|
||||
*/
|
||||
template <class MU, class PQ> int CPhysicalQuantity<MU, PQ>::compare(const QVariant &qv) const
|
||||
{
|
||||
Q_ASSERT(qv.canConvert<PQ>());
|
||||
Q_ASSERT(!qv.isNull() && qv.isValid());
|
||||
return this->compare(qv.value<PQ>());
|
||||
}
|
||||
|
||||
/*
|
||||
* Compare
|
||||
*/
|
||||
template <class MU, class PQ> int CPhysicalQuantity<MU, PQ>::compare(const PQ &other) const
|
||||
{
|
||||
if (other == (*this)) return 0;
|
||||
return ((*this) < other) ? -1 : 1;
|
||||
}
|
||||
|
||||
// see here for the reason of thess forward instantiations
|
||||
// http://www.parashift.com/c++-faq/separate-template-class-defn-from-decl.html
|
||||
template class CPhysicalQuantity<CLengthUnit, CLength>;
|
||||
|
||||
@@ -347,11 +347,26 @@ namespace BlackMisc
|
||||
*/
|
||||
virtual void unmarshallFromDbus(const QDBusArgument &argument);
|
||||
|
||||
/*!
|
||||
* \brief Value hash
|
||||
* \return
|
||||
*/
|
||||
virtual uint getValueHash() const;
|
||||
|
||||
/*!
|
||||
* \brief Register metadata of unit and quantity
|
||||
*/
|
||||
static void registerMetadata();
|
||||
|
||||
/*!
|
||||
* \copydoc BlackObject::compare
|
||||
*/
|
||||
virtual int compare(const QVariant &qv) const;
|
||||
|
||||
/*!
|
||||
* \copydoc BlackObject::compare
|
||||
*/
|
||||
virtual int compare(const PQ &other) const;
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
||||
@@ -60,6 +60,16 @@ namespace BlackMisc
|
||||
return vo;
|
||||
}
|
||||
|
||||
/*
|
||||
* Compare
|
||||
*/
|
||||
int CValueObject::compare(const QVariant & /** qv **/) const
|
||||
{
|
||||
// not all classes have to implement this
|
||||
qFatal("Property by index as string not implemented");
|
||||
return -1; // avoid compiler warning
|
||||
}
|
||||
|
||||
/*
|
||||
* from DBus
|
||||
*/
|
||||
|
||||
@@ -12,6 +12,8 @@
|
||||
|
||||
namespace BlackMisc
|
||||
{
|
||||
// forward declaration
|
||||
class CValueMap;
|
||||
|
||||
/*!
|
||||
* \brief Base class for value objects.
|
||||
@@ -132,6 +134,21 @@ namespace BlackMisc
|
||||
*/
|
||||
std::string toStdString(bool i18n = false) const;
|
||||
|
||||
/*!
|
||||
* \brief Value hash, allows comparisons between QVariants
|
||||
* \return
|
||||
*/
|
||||
virtual uint getValueHash() const = 0;
|
||||
|
||||
/*!
|
||||
* Compares with QVariant with this object
|
||||
* and returns an integer less than, equal to, or greater than zero
|
||||
* if this is less than, equal to, or greater than QVariant.
|
||||
* \remarks allows sorting among QVariants, not all classes implement this
|
||||
* \return
|
||||
*/
|
||||
virtual int compare(const QVariant &qv) const;
|
||||
|
||||
/*!
|
||||
* \brief Virtual method to return QVariant, used with DBUS QVariant lists
|
||||
* \return
|
||||
@@ -216,6 +233,48 @@ namespace BlackMisc
|
||||
return argument << static_cast<CValueObject const &>(uc);
|
||||
}
|
||||
|
||||
/*!
|
||||
* Allow comparison with QVariant, e.g.
|
||||
* QVariant == CFrequency ?
|
||||
*/
|
||||
template <class T> typename std::enable_if<std::is_base_of<CValueObject, T>::value, bool>::type
|
||||
operator==(const QVariant &variant, const T &uc)
|
||||
{
|
||||
if (!variant.canConvert<T>()) return false;
|
||||
T vuc = variant.value<T>();
|
||||
return vuc == uc;
|
||||
}
|
||||
|
||||
/*!
|
||||
* Allow comparison with QVariant, e.g.
|
||||
* QVariant != CFrequency ?
|
||||
*/
|
||||
template <class T> typename std::enable_if<std::is_base_of<CValueObject, T>::value, bool>::type
|
||||
operator!=(const QVariant &variant, const T &uc)
|
||||
{
|
||||
return !(variant == uc);
|
||||
}
|
||||
|
||||
/*!
|
||||
* Allow comparison with QVariant, e.g.
|
||||
* QVariant == CFrequency ?
|
||||
*/
|
||||
template <class T> typename std::enable_if<std::is_base_of<CValueObject, T>::value, bool>::type
|
||||
operator==(const T &uc, const QVariant &variant)
|
||||
{
|
||||
return variant == uc;
|
||||
}
|
||||
|
||||
/*!
|
||||
* Allow comparison with QVariant, e.g.
|
||||
* QVariant != CFrequency ?
|
||||
*/
|
||||
template <class T> typename std::enable_if<std::is_base_of<CValueObject, T>::value, bool>::type
|
||||
operator!=(const T &uc, const QVariant &variant)
|
||||
{
|
||||
return variant != uc;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
#endif // guard
|
||||
|
||||
Reference in New Issue
Block a user