From ef93477a82970f0bb29b0103346caa7374086a7c Mon Sep 17 00:00:00 2001 From: Mathew Sutcliffe Date: Tue, 1 Jul 2014 21:04:40 +0100 Subject: [PATCH] CDictionary: fixed, enabled, and tested automatic selection of appropriate default implementation container. refs #281 --- src/blackmisc/dictionary.h | 57 +++++++++++++++++++++++++++++-- tests/blackmisc/testvalueobject.h | 31 ++++++++++++++++- 2 files changed, 85 insertions(+), 3 deletions(-) diff --git a/src/blackmisc/dictionary.h b/src/blackmisc/dictionary.h index 27e8c4519..15ec1ce29 100644 --- a/src/blackmisc/dictionary.h +++ b/src/blackmisc/dictionary.h @@ -13,14 +13,67 @@ namespace BlackMisc { + namespace Private + { + //! \cond PRIVATE + + namespace ADL + { + struct NotFound {}; + struct FromAny { template FromAny(const T &); }; + NotFound operator <(const FromAny &, const FromAny &); + NotFound operator ==(const FromAny &, const FromAny &); + NotFound qHash(...); + + template + struct SupportsQHash : std::integral_constant() == std::declval()), NotFound>::value && + ! std::is_same())), NotFound>::value + > {}; + template + struct SupportsQMap : std::integral_constant() < std::declval()), NotFound>::value + > {}; + } + + template + struct AssociativityTraits + { + template + using DefaultType = QHash; + }; + template <> + struct AssociativityTraits + { + template + using DefaultType = QMap; + }; + template <> + struct AssociativityTraits + { + template + struct DefaultType { static_assert((std::is_void::value, false), "Key does not support either QHash or QMap"); }; + }; + + //! \endcond + } // namespace Private + + + //! Trait to select the appropriate default associative container type depending on what the key type supports + template + struct AssociativityTraits : public Private::AssociativityTraits::value, Private::ADL::SupportsQMap::value> + {}; + //! Associative container with value semantics, chooses a sensible default implementation container type - template class Impl> + template class Impl = AssociativityTraits::template DefaultType> class CDictionary : public CValueObject { public: + //! The implementation container + typedef Impl impl_type; - //! \brief STL compatibility + //! STL compatibility //! @{ typedef Key key_type; typedef Value value_type; diff --git a/tests/blackmisc/testvalueobject.h b/tests/blackmisc/testvalueobject.h index 8849e7edf..362bd58c3 100644 --- a/tests/blackmisc/testvalueobject.h +++ b/tests/blackmisc/testvalueobject.h @@ -106,6 +106,19 @@ namespace BlackMisc QString m_description; }; + //! \cond NO_DOXYGEN + struct CNotHashable + { + int n; + bool operator <(const CNotHashable &other) const { return n < other.n; } + QString toQString(bool = false) const { return {}; } + }; + inline QJsonArray &operator <<(QJsonArray &a, const CNotHashable &) { return a; } + inline const QJsonValueRef &operator >>(const QJsonValueRef &v, CNotHashable &) { return v; } + inline QDBusArgument &operator <<(QDBusArgument &a, const CNotHashable &) { return a; } + inline const QDBusArgument &operator >>(const QDBusArgument &a, const CNotHashable &) { return a; } + //! \endcond + } // namespace BLACK_DECLARE_TUPLE_CONVERSION(BlackMisc::CTestValueObject, (o.m_name, o.m_description)) @@ -113,9 +126,25 @@ Q_DECLARE_METATYPE(BlackMisc::CTestValueObject) Q_DECLARE_METATYPE(BlackMisc::CCollection) Q_DECLARE_METATYPE(BlackMisc::CSequence) +Q_DECLARE_METATYPE(BlackMisc::CNotHashable) + // We need to typedef because 'commas' confuse the Q_DECLARE_METATYPE macro // https://bugreports.qt-project.org/browse/QTBUG-11485 -typedef BlackMisc::CDictionary CValueObjectDictionary; +typedef BlackMisc::CDictionary CValueObjectDictionary; +typedef BlackMisc::CDictionary CValueObjectHashDictionary; +typedef BlackMisc::CDictionary CNotHashableDictionary; +typedef BlackMisc::CDictionary CNotHashableMapDictionary; Q_DECLARE_METATYPE(CValueObjectDictionary) +Q_DECLARE_METATYPE(CValueObjectHashDictionary) +Q_DECLARE_METATYPE(CNotHashableDictionary) +Q_DECLARE_METATYPE(CNotHashableMapDictionary) + +// MSVC has trouble with these checks +#if !defined(Q_CC_MSVC) +static_assert(std::is_same::value, + "Expected CValueObjectDictionary to use QHash"); +static_assert(std::is_same::value, + "Expected CDictionary to use QMap"); +#endif // ! Q_CC_MSVC #endif // guard