Issue #15 Added CVariant::matches()

If the contained object type has a matches() method, CVariant::matches()
will call that method and return its result.
(This is a utility to allow using CVariant to represent an event subscription.)
This commit is contained in:
Mat Sutcliffe
2019-02-26 01:51:21 +00:00
parent 8de217fbab
commit 073f1549a2
7 changed files with 75 additions and 1 deletions

View File

@@ -193,7 +193,8 @@ namespace BlackMisc
bool matchesVariant(const CVariant &value) const; bool matchesVariant(const CVariant &value) const;
//! True if this map matches the value //! True if this map matches the value
template <typename T> bool matches(const T &value) const { return matchesVariant(CVariant::from(value)); } template <typename T, typename = std::enable_if_t<!std::is_same<T, CVariant>::value>>
bool matches(const T &value) const { return matchesVariant(CVariant::from(value)); }
//! Map //! Map
const QMap<CPropertyIndex, CVariant> &map() const { return m_values; } const QMap<CPropertyIndex, CVariant> &map() const { return m_values; }

View File

@@ -533,6 +533,26 @@ namespace BlackMisc
return toIcon().toPixmap(); return toIcon().toPixmap();
} }
bool CVariant::matches(const CVariant &value) const
{
if (! isValid()) { return false; }
auto *meta = getValueObjectMetaInfo();
if (! meta)
{
CLogMessage(this).warning(u"Invalid type for CVariant::matches: %1") << typeName();
return false;
}
try
{
return meta->matches(data(), value);
}
catch (const Private::CVariantException &ex)
{
CLogMessage(this).debug() << ex.what();
return false;
}
}
QVariant fixQVariantFromDbusArgument(const QVariant &variant, int localUserType, const QString &typeName) QVariant fixQVariantFromDbusArgument(const QVariant &variant, int localUserType, const QString &typeName)
{ {
if (localUserType == static_cast<int>(QVariant::Invalid)) if (localUserType == static_cast<int>(QVariant::Invalid))

View File

@@ -343,6 +343,9 @@ namespace BlackMisc
//! \copydoc BlackMisc::Mixin::Icon::toIcon //! \copydoc BlackMisc::Mixin::Icon::toIcon
CIcon toIcon() const; CIcon toIcon() const;
//! If this is an event subscription, return true if it matches the given event.
bool matches(const CVariant &event) const;
private: private:
QVariant m_v; QVariant m_v;

View File

@@ -36,4 +36,9 @@ namespace BlackMisc
QMetaType::registerConverter<CVariantList, QVector<CVariant>>([](const CVariantList &list) { return list.toVector(); }); QMetaType::registerConverter<CVariantList, QVector<CVariant>>([](const CVariantList &list) { return list.toVector(); });
QMetaType::registerConverter<QVector<CVariant>, CVariantList>([](const QVector<CVariant> &list) { return CSequence(list); }); QMetaType::registerConverter<QVector<CVariant>, CVariantList>([](const QVector<CVariant> &list) { return CSequence(list); });
} }
bool CVariantList::matches(const CVariant &event) const
{
return containsBy([ & ](const CVariant &pattern) { return pattern.matches(event); });
}
} // ns } // ns

View File

@@ -59,6 +59,9 @@ namespace BlackMisc
//! \copydoc BlackMisc::CValueObject::registerMetadata //! \copydoc BlackMisc::CValueObject::registerMetadata
static void registerMetadata(); static void registerMetadata();
//! True if any element of the list matches the given event.
bool matches(const CVariant &event) const;
}; };
} }

View File

@@ -59,6 +59,7 @@ namespace BlackMisc
virtual void propertyByIndex(const void *object, CVariant &o_variant, const BlackMisc::CPropertyIndex &index) const = 0; virtual void propertyByIndex(const void *object, CVariant &o_variant, const BlackMisc::CPropertyIndex &index) const = 0;
virtual QString propertyByIndexAsString(const void *object, const CPropertyIndex &index, bool i18n) const = 0; virtual QString propertyByIndexAsString(const void *object, const CPropertyIndex &index, bool i18n) const = 0;
virtual bool equalsPropertyByIndex(const void *object, const CVariant &compareValue, const CPropertyIndex &index) const = 0; virtual bool equalsPropertyByIndex(const void *object, const CVariant &compareValue, const CPropertyIndex &index) const = 0;
virtual bool matches(const void *object, const CVariant &value) const = 0;
virtual void toIcon(const void *object, CIcon &o_icon) const = 0; virtual void toIcon(const void *object, CIcon &o_icon) const = 0;
}; };
@@ -141,6 +142,11 @@ namespace BlackMisc
static void toIcon(const T &object, CIcon &o_icon, std::enable_if_t < ! std::is_same<T, CVariant>::value, decltype(static_cast<void>(object.toIcon()), 0) >) { assign(o_icon, object.toIcon()); } static void toIcon(const T &object, CIcon &o_icon, std::enable_if_t < ! std::is_same<T, CVariant>::value, decltype(static_cast<void>(object.toIcon()), 0) >) { assign(o_icon, object.toIcon()); }
template <typename T> template <typename T>
static void toIcon(const T &object, CIcon &, ...) { throw CVariantException(object, "toIcon"); } static void toIcon(const T &object, CIcon &, ...) { throw CVariantException(object, "toIcon"); }
template <typename T>
static bool matches(const T &object, const CVariant &value, decltype(static_cast<void>(object.matches(value)), 0)) { return object.matches(value); }
template <typename T>
static bool matches(const T &object, const CVariant &, ...) { throw CVariantException(object, "matches"); }
}; };
//! \private Implementation of IValueObjectMetaInfo representing the set of operations supported by T. //! \private Implementation of IValueObjectMetaInfo representing the set of operations supported by T.
@@ -208,6 +214,10 @@ namespace BlackMisc
{ {
CValueObjectMetaInfoHelper::toIcon(cast(object), o_icon, 0); CValueObjectMetaInfoHelper::toIcon(cast(object), o_icon, 0);
} }
virtual bool matches(const void *object, const CVariant &value) const override
{
return CValueObjectMetaInfoHelper::matches(cast(object), value, 0);
}
static const T &cast(const void *object) { return *static_cast<const T *>(object); } static const T &cast(const void *object) { return *static_cast<const T *>(object); }
static T &cast(void *object) { return *static_cast<T *>(object); } static T &cast(void *object) { return *static_cast<T *>(object); }

View File

@@ -29,6 +29,8 @@
#include "blackmisc/variant.h" #include "blackmisc/variant.h"
#include "test.h" #include "test.h"
#include <QDBusArgument>
#include <QObject>
#include <QDateTime> #include <QDateTime>
#include <QTest> #include <QTest>
@@ -55,10 +57,32 @@ namespace BlackMiscTest
//! Unit tests for variant lists //! Unit tests for variant lists
void variantList(); void variantList();
//! Unit tests for matches feature
void matches();
//! Unit tests for value maps and value objects //! Unit tests for value maps and value objects
void valueMap(); void valueMap();
}; };
//! \private
class CTestMatcher : public BlackMisc::Mixin::MetaType<CTestMatcher>
{
public:
bool matches(const BlackMisc::CVariant &) const { return true; }
// methods needed for metatype registration
QString toQString(bool) const { return {}; }
friend QDBusArgument &operator <<(QDBusArgument &arg, const CTestMatcher &) { return arg; }
friend const QDBusArgument &operator >>(const QDBusArgument &arg, CTestMatcher &) { return arg; }
friend QDataStream &operator <<(QDataStream &ds, const CTestMatcher &) { return ds; }
friend QDataStream &operator >>(QDataStream &ds, CTestMatcher &) { return ds; }
};
} // namespace
Q_DECLARE_METATYPE(BlackMiscTest::CTestMatcher)
namespace BlackMiscTest
{
void CTestVariantAndMap::initTestCase() void CTestVariantAndMap::initTestCase()
{ {
BlackMisc::registerMetadata(); BlackMisc::registerMetadata();
@@ -134,6 +158,14 @@ namespace BlackMiscTest
QVERIFY2(list == variant.to<CAirlineIcaoCodeList>(), "Variant list converted back compares equal"); QVERIFY2(list == variant.to<CAirlineIcaoCodeList>(), "Variant list converted back compares equal");
} }
void CTestVariantAndMap::matches()
{
CTestMatcher::registerMetadata();
const CTestMatcher matcher {};
const CVariant variant = CVariant::from(matcher);
QVERIFY2(variant.matches(CVariant()), "Variant provides access to stored object's matches() method");
}
void CTestVariantAndMap::valueMap() void CTestVariantAndMap::valueMap()
{ {
// ATC station // ATC station