diff --git a/src/blackmisc/compare.h b/src/blackmisc/compare.h index 24c18cf0c..5bcc7a65a 100644 --- a/src/blackmisc/compare.h +++ b/src/blackmisc/compare.h @@ -12,13 +12,14 @@ #ifndef BLACKMISC_COMPARE_H #define BLACKMISC_COMPARE_H -#include "blackmisc/tuple.h" #include "blackmisc/metaclass.h" #include "blackmisc/inheritancetraits.h" #include "blackmisc/typetraits.h" namespace BlackMisc { + class CEmpty; + //! \cond PRIVATE namespace Private { @@ -61,10 +62,9 @@ namespace BlackMisc * Lexicographically compare two tuples and return negative, positive, or zero, * if a is less than, greater than, or equal to b. * Each element is compared with compare(a', b') if supported by the element type, operator less-than otherwise. - * \todo Rename to compare() after removing tuple.h, which contains a function with the same name and signature. */ template - int compareTuples(const std::tuple &a, const std::tuple &b) + int compare(const std::tuple &a, const std::tuple &b) { static_assert(sizeof...(Ts) == sizeof...(Us), "tuples must be same size"); return Private::CompareHelper::compareTuples(a, b); @@ -89,29 +89,6 @@ namespace BlackMisc friend bool operator !=(const Derived &a, const Derived &b) { return compare(a, b) != 0; } }; - /*! - * CRTP class template from which a derived class can inherit operator== implemented by metatuple. - */ - template - class EqualsByTuple : private Private::EncapsulationBreaker - { - public: - //! Equals - friend bool operator ==(const Derived &a, const Derived &b) { return equals(a, b); } - - //! Not equal - friend bool operator !=(const Derived &a, const Derived &b) { return ! equals(a, b); } - - private: - static bool equals(const Derived &a, const Derived &b) - { - return toMetaTuple(a) == toMetaTuple(b) && baseEquals(static_cast *>(&a), static_cast *>(&b)); - } - template static bool baseEquals(const T *a, const T *b) { return *a == *b; } - static bool baseEquals(const void *, const void *) { return true; } - static bool baseEquals(const CEmpty *, const CEmpty *) { return true; } - }; - /*! * CRTP class template from which a derived class can inherit operator== implemented by metaclass. */ @@ -158,36 +135,6 @@ namespace BlackMisc friend bool operator >=(const Derived &a, const Derived &b) { return compare(a, b) >= 0; } }; - /*! - * CRTP class template from which a derived class can inherit operator< implemented by metatuple. - */ - template - class LessThanByTuple : private Private::EncapsulationBreaker - { - public: - //! Less than - friend bool operator <(const Derived &a, const Derived &b) { return less(a, b); } - - //! Greater than - friend bool operator >(const Derived &a, const Derived &b) { return less(b, a); } - - //! Less than or equal - friend bool operator <=(const Derived &a, const Derived &b) { return ! less(b, a); } - - //! Greater than or equal - friend bool operator >=(const Derived &a, const Derived &b) { return ! less(a, b); } - - private: - static bool less(const Derived &a, const Derived &b) - { - if (baseLess(static_cast *>(&a), static_cast *>(&b))) { return true; } - return toMetaTuple(a) < toMetaTuple(b); - } - template static bool baseLess(const T *a, const T *b) { return *a < *b; } - static bool baseLess(const void *, const void *) { return false; } - static bool baseLess(const CEmpty *, const CEmpty *) { return false; } - }; - /*! * CRTP class template from which a derived class can inherit operator< implemented by metaclass. */ @@ -219,30 +166,6 @@ namespace BlackMisc static bool baseLess(const CEmpty *, const CEmpty *) { return false; } }; - /*! - * CRTP class template from which a derived class can inherit non-member compare() implemented by metatuple. - * - * \tparam Derived Must be registered with BLACK_DECLARE_TUPLE_CONVERSION. - */ - template - class CompareByTuple : private Private::EncapsulationBreaker - { - public: - //! Return negative, zero, or positive if a is less than, equal to, or greater than b. - friend int compare(const Derived &a, const Derived &b) { return compareImpl(a, b); } - - private: - static int compareImpl(const Derived &a, const Derived &b) - { - int baseCmp = baseCompare(static_cast *>(&a), static_cast *>(&b)); - if (baseCmp) { return baseCmp; } - return BlackMisc::compare(toMetaTuple(a), toMetaTuple(b)); - } - template static int baseCompare(const T *a, const T *b) { return compare(*a, *b); } - static int baseCompare(const void *, const void *) { return 0; } - static int baseCompare(const CEmpty *, const CEmpty *) { return 0; } - }; - /*! * CRTP class template from which a derived class can inherit non-member compare() implemented by metaclass. */ @@ -259,7 +182,7 @@ namespace BlackMisc int baseCmp = baseCompare(static_cast *>(&a), static_cast *>(&b)); if (baseCmp) { return baseCmp; } auto meta = introspect().without(MetaFlags()); - return BlackMisc::compareTuples(meta.toCaseAwareTuple(a), meta.toCaseAwareTuple(b)); + return BlackMisc::compare(meta.toCaseAwareTuple(a), meta.toCaseAwareTuple(b)); } template static int baseCompare(const T *a, const T *b) { return compare(*a, *b); } static int baseCompare(const void *, const void *) { return 0; } diff --git a/src/blackmisc/dbus.h b/src/blackmisc/dbus.h index 8f6368bec..4d4c953af 100644 --- a/src/blackmisc/dbus.h +++ b/src/blackmisc/dbus.h @@ -12,7 +12,6 @@ #ifndef BLACKMISC_DBUS_H #define BLACKMISC_DBUS_H -#include "blackmisc/tuple.h" #include "blackmisc/metaclass.h" #include "blackmisc/inheritancetraits.h" #include @@ -20,6 +19,8 @@ namespace BlackMisc { + class CEmpty; + namespace Mixin { /*! @@ -50,45 +51,6 @@ namespace BlackMisc } }; - /*! - * CRTP class template from which a derived class can inherit common methods dealing with marshalling instances by metatuple. - * - * \tparam Derived Must be registered with BLACK_DECLARE_TUPLE_CONVERSION. - * - * \see BLACKMISC_DECLARE_USING_MIXIN_DBUS - */ - template - class DBusByTuple : public DBusOperators, private Private::EncapsulationBreaker - { - public: - //! Marshall without begin/endStructure, for when composed within another object - void marshallToDbus(QDBusArgument &arg) const - { - baseMarshall(static_cast *>(derived()), arg); - using BlackMisc::operator<<; - arg << Private::EncapsulationBreaker::toMetaTuple(*derived()); - } - - //! Unmarshall without begin/endStructure, for when composed within another object - void unmarshallFromDbus(const QDBusArgument &arg) - { - baseUnmarshall(static_cast *>(derived()), arg); - using BlackMisc::operator>>; - arg >> Private::EncapsulationBreaker::toMetaTuple(*derived()); - } - - private: - const Derived *derived() const { return static_cast(this); } - Derived *derived() { return static_cast(this); } - - template static void baseMarshall(const T *base, QDBusArgument &arg) { base->marshallToDbus(arg); } - template static void baseUnmarshall(T *base, const QDBusArgument &arg) { base->unmarshallFromDbus(arg); } - static void baseMarshall(const void *, QDBusArgument &) {} - static void baseUnmarshall(void *, const QDBusArgument &) {} - static void baseMarshall(const CEmpty *, QDBusArgument &) {} - static void baseUnmarshall(CEmpty *, const QDBusArgument &) {} - }; - /*! * CRTP class template from which a derived class can inherit common methods dealing with marshalling instances by metaclass. * diff --git a/src/blackmisc/dictionary.h b/src/blackmisc/dictionary.h index a804fc46d..1408635da 100644 --- a/src/blackmisc/dictionary.h +++ b/src/blackmisc/dictionary.h @@ -26,6 +26,11 @@ namespace BlackMisc { + // Needed so that our qHash overload doesn't hide the qHash overloads in the global namespace. + // This will be safe as long as no global qHash has the same signature as ours. + // Alternative would be to qualify all our invokations of the global qHash as ::qHash. + using ::qHash; + namespace Private { //! \cond PRIVATE @@ -459,32 +464,6 @@ namespace BlackMisc namespace Mixin { - /*! - * CRTP class template from which a derived class can inherit common methods dealing with hashing instances by metatuple. - * - * \tparam Derived Must be registered with BLACK_DECLARE_TUPLE_CONVERSION. - */ - template - class HashByTuple : private Private::EncapsulationBreaker - { - public: - //! qHash overload, needed for storing value in a QSet. - friend uint qHash(const Derived &value, uint seed = 0) - { - return ::qHash(hashImpl(value), seed); - } - - private: - static uint hashImpl(const Derived &value) - { - return BlackMisc::qHash(toMetaTuple(value)) ^ baseHash(static_cast *>(&value)); - } - - template static uint baseHash(const T *base) { return qHash(*base); } - static uint baseHash(const void *) { return 0; } - static uint baseHash(const CEmpty *) { return 0; } - }; - /*! * CRTP class template from which a derived class can inherit common methods dealing with hashing instances by metaclass. * diff --git a/src/blackmisc/icon.h b/src/blackmisc/icon.h index b1ef4f880..762dbe8bd 100644 --- a/src/blackmisc/icon.h +++ b/src/blackmisc/icon.h @@ -15,7 +15,6 @@ #include "blackmiscexport.h" #include "icons.h" #include "variant.h" -#include "tuple.h" #include "inheritancetraits.h" #include "dictionary.h" #include diff --git a/src/blackmisc/json.h b/src/blackmisc/json.h index 8ac400a72..3c78f72fc 100644 --- a/src/blackmisc/json.h +++ b/src/blackmisc/json.h @@ -13,7 +13,6 @@ #define BLACKMISC_JSON_H #include "blackmisc/blackmiscexport.h" -#include "blackmisc/tuple.h" #include "blackmisc/metaclass.h" #include "blackmisc/inheritancetraits.h" #include "blackmisc/fileutils.h" @@ -146,6 +145,8 @@ BLACKMISC_EXPORT QJsonObject &operator<<(QJsonObject &json, const std::pair - class JsonByTuple : public JsonOperators, private Private::EncapsulationBreaker - { - public: - //! Cast to JSON object - QJsonObject toJson() const - { - QJsonObject json = BlackMisc::serializeJson(Private::EncapsulationBreaker::toMetaTuple(*derived())); - return Json::appendJsonObject(json, baseToJson(static_cast *>(derived()))); - } - - //! Convenience function JSON as string - QString toJsonString(QJsonDocument::JsonFormat format = QJsonDocument::Indented) const - { - QJsonDocument jsonDoc(toJson()); - return jsonDoc.toJson(format); - } - - //! Assign from JSON object - void convertFromJson(const QJsonObject &json) - { - baseConvertFromJson(static_cast *>(derived()), json); - BlackMisc::deserializeJson(json, Private::EncapsulationBreaker::toMetaTuple(*derived())); - } - - //! Assign from JSON object string - void convertFromJson(const QString &jsonString) - { - convertFromJson(BlackMisc::Json::jsonObjectFromString(jsonString)); - } - - private: - const Derived *derived() const { return static_cast(this); } - Derived *derived() { return static_cast(this); } - - template static QJsonObject baseToJson(const T *base) { return base->toJson(); } - template static void baseConvertFromJson(T *base, const QJsonObject &json) { base->convertFromJson(json); } - static QJsonObject baseToJson(const void *) { return {}; } - static void baseConvertFromJson(void *, const QJsonObject &) {} - static QJsonObject baseToJson(const CEmpty *) { return {}; } - static void baseConvertFromJson(CEmpty *, const QJsonObject &) {} - }; - /*! * CRTP class template from which a derived class can inherit common methods dealing with JSON by metatuple. * diff --git a/src/blackmisc/metaclass.h b/src/blackmisc/metaclass.h index f15778edd..f8108cbd6 100644 --- a/src/blackmisc/metaclass.h +++ b/src/blackmisc/metaclass.h @@ -14,7 +14,6 @@ #include "blackmisc/metaclassprivate.h" #include "blackmisc/invoke.h" -#include "blackmisc/tuple.h" // just for TupleConverterFlags /*! * \defgroup MetaClass Metaclass system @@ -77,19 +76,17 @@ namespace BlackMisc /*! * Metadata flags attached to members of a meta class. - * \todo Remove TupleConverterFlags and change MetaFlag to a full enum. * \ingroup MetaClass */ - using MetaFlag = TupleConverterFlags; - //enum MetaFlag - //{ - // DisabledForComparison = 1 << 0, //!< Element will be ignored by compare() and comparison operators - // DisabledForMarshalling = 1 << 1, //!< Element will be ignored during DBus marshalling - // DisabledForDebugging = 1 << 2, //!< Element will be ignored when streaming to QDebug - // DisabledForHashing = 1 << 3, //!< Element will be ignored by qHash() - // DisabledForJson = 1 << 4, //!< Element will be ignored during JSON serialization - // CaseInsensitiveComparison = 1 << 5 //!< Element will be compared case insensitively (must be a QString) - //}; + enum MetaFlag + { + DisabledForComparison = 1 << 0, //!< Element will be ignored by compare() and comparison operators + DisabledForMarshalling = 1 << 1, //!< Element will be ignored during DBus marshalling + DisabledForDebugging = 1 << 2, //!< Element will be ignored when streaming to QDebug + DisabledForHashing = 1 << 3, //!< Element will be ignored by qHash() + DisabledForJson = 1 << 4, //!< Element will be ignored during JSON serialization + CaseInsensitiveComparison = 1 << 5 //!< Element will be compared case insensitively (must be a QString) + }; /*! * Type wrapper for passing MetaFlag to CMetaClassIntrospector::with and CMetaClassIntrospector::without. diff --git a/src/blackmisc/pq/pqstring.cpp b/src/blackmisc/pq/pqstring.cpp index 3306c99c9..d5d6da742 100644 --- a/src/blackmisc/pq/pqstring.cpp +++ b/src/blackmisc/pq/pqstring.cpp @@ -8,7 +8,6 @@ */ #include "blackmisc/pq/pqstring.h" -#include "blackmisc/tuple.h" #include "blackmisc/pq/pq.h" #include diff --git a/src/blackmisc/propertyindexvariantmap.h b/src/blackmisc/propertyindexvariantmap.h index ff535d633..981482b9b 100644 --- a/src/blackmisc/propertyindexvariantmap.h +++ b/src/blackmisc/propertyindexvariantmap.h @@ -15,7 +15,6 @@ #include "variant.h" #include "propertyindexlist.h" #include "blackmiscexport.h" -#include "tuple.h" #include "inheritancetraits.h" #include #include diff --git a/src/blackmisc/tuple.cpp b/src/blackmisc/tuple.cpp deleted file mode 100644 index d3f3643e7..000000000 --- a/src/blackmisc/tuple.cpp +++ /dev/null @@ -1,41 +0,0 @@ -/* Copyright (C) 2013 - * swift Project Community / Contributors - * - * This file is part of swift project. It is subject to the license terms in the LICENSE file found in the top-level - * directory of this distribution and at http://www.swift-project.org/license.html. No part of swift project, - * including this file, may be copied, modified, propagated, or distributed except according to the terms - * contained in the LICENSE file. - */ - -#include "tuple.h" - -namespace BlackMisc -{ - - TupleConverterBase::Parser::Parser(QString string) - { - string.remove(QRegExp("^\\s*\\(\\s*")); // remove first '(' - string.remove(QRegExp("\\s*\\)\\s*$")); // remove last ')' - QString current; - int level = 0; - for (const auto c : string) - { - if (c == '(') { level++; } - if (c == ')') { level--; } - if (c == ',' && level == 0) { m_raw.push_back(current.trimmed()); current.clear(); } - else { current += c; } - } - if (! current.trimmed().isEmpty()) { m_raw.push_back(current.trimmed()); current.clear(); } - - for (const auto &member : m_raw) - { - QRegExp simple("^o\\.(\\w+)$"); - if (member.contains(simple)) { m_names.push_back(simple.cap(1)); continue; } - QRegExp meta("^attr\\s*\\(\\s*o\\.(\\w+)"); - if (member.contains(meta)) { m_names.push_back(meta.cap(1)); continue; } - qFatal("BLACK_DECLARE_TUPLE_CONVERSION: Parser couldn't extract member name from \"%s\"", qPrintable(member)); - } - for (auto &name : m_names) { name.remove(QRegExp("^m_")); } - } - -} // namespace diff --git a/src/blackmisc/tuple.h b/src/blackmisc/tuple.h deleted file mode 100644 index 8754e6253..000000000 --- a/src/blackmisc/tuple.h +++ /dev/null @@ -1,431 +0,0 @@ -/* Copyright (C) 2013 - * swift project Community / Contributors - * - * This file is part of swift project. It is subject to the license terms in the LICENSE file found in the top-level - * directory of this distribution and at http://www.swift-project.org/license.html. No part of swift project, - * including this file, may be copied, modified, propagated, or distributed except according to the terms - * contained in the LICENSE file. - */ - -//! \file - -#ifndef BLACKMISC_TUPLE_H -#define BLACKMISC_TUPLE_H - -#include "blackmiscexport.h" - -/*! - * \defgroup Tuples Tuple conversion of object data members - */ - -namespace BlackMisc -{ - //! Metadata flags attached to tuple elements. - //! \ingroup Tuples - enum TupleConverterFlags - { - DisabledForComparison = 1 << 0, //!< Element will be ignored by compare() and comparison operators - DisabledForMarshalling = 1 << 1, //!< Element will be ignored during DBus marshalling - DisabledForDebugging = 1 << 2, //!< Element will be ignored when streaming to QDebug - DisabledForHashing = 1 << 3, //!< Element will be ignored by qHash() - DisabledForJson = 1 << 4, //!< Element will be ignored during JSON serialization - CaseInsensitiveComparison = 1 << 5 //!< Element will be compared case insensitively (must be a QString) - }; -} - -#include "tupleprivate.h" - -/*! - * \brief Macro to make a class available to TupleConverter. - * \details Put this macro anywhere in the private section of a class declaration to make it usable in TupleConverter. - * \param T The name of the class. - * \hideinitializer - * \ingroup Tuples - */ -#define BLACK_ENABLE_TUPLE_CONVERSION(T) \ - public: using EnabledTupleConversion = std::true_type; \ - private: friend class BlackMisc::TupleConverter; - -/*! - * \brief Macro to make a class known to TupleConverter. - * \details Put this macro outside of any namespace, in the same header as T, to make it usable in TupleConverter. - * \param T The fully qualified name of the class. - * \param MEMBERS A parenthesized, comma-separated list of the data members of T, with each member prefixed by "o." - * (the letter o followed by dot). Can also use any types or functions inherited from TupleConverterBase. - * \par Example - * If class Things::MyThing has data members m_first, m_second, and m_third: - * \code - * BLACK_DEFINE_TUPLE_CONVERSION(Things::MyThing, (o.m_first, o.m_second, o.m_third)) - * \endcode - * To disable m_third from participating in hash value generation: - * \code - * BLACK_DEFINE_TUPLE_CONVERSION(Things::MyThing, (o.m_first, o.m_second, attr(o.m_third, flags()))) - * \endcode - * \see BLACK_DECLARE_TUPLE_CONVERSION_TEMPLATE If T is a template, use this instead. - * \hideinitializer - * \ingroup Tuples - */ -#define BLACK_DECLARE_TUPLE_CONVERSION(T, MEMBERS) \ - namespace BlackMisc \ - { \ - template <> class TupleConverter : TupleConverterBase \ - { \ - friend class T; \ - template friend class BlackMisc::CValueObject; \ - friend class BlackMisc::Private::EncapsulationBreaker; \ - static_assert(Private::HasEnabledTupleConversion::value, \ - "Missing BLACK_ENABLE_TUPLE_CONVERSION macro in " #T); \ - static auto toTuple(const T &o) \ - { \ - return BlackMisc::tie MEMBERS; \ - } \ - static auto toTuple(T &o) \ - { \ - return BlackMisc::tie MEMBERS; \ - } \ - static auto toMetaTuple(const T &o) \ - { \ - auto tu = BlackMisc::tieMeta MEMBERS; \ - parser().extendMetaTuple(tu); \ - return tu; \ - } \ - static auto toMetaTuple(T &o) \ - { \ - auto tu = BlackMisc::tieMeta MEMBERS; \ - parser().extendMetaTuple(tu); \ - return tu; \ - } \ - static const Parser &parser() \ - { \ - static const Parser p(#MEMBERS); \ - return p; \ - } \ - static const QStringList &jsonMembers() \ - { \ - return parser().m_names; \ - } \ - public: \ - static auto constToTuple(const T &o) \ - { \ - return BlackMisc::tie MEMBERS; \ - } \ - }; \ - } - -/*! - * \brief Same as BLACK_DECLARE_TUPLE_CONVERSION(), but T can be a class template. - * \hideinitializer - * \ingroup Tuples - */ -#define BLACK_DECLARE_TUPLE_CONVERSION_TEMPLATE(T, MEMBERS) \ - namespace BlackMisc \ - { \ - template class TupleConverter> : TupleConverterBase \ - { \ - friend class T; \ - template friend class BlackMisc::CValueObject; \ - friend class BlackMisc::Private::EncapsulationBreaker; \ - static_assert(Private::HasEnabledTupleConversion>::value, \ - "Missing BLACK_ENABLE_TUPLE_CONVERSION macro in " #T); \ - static auto toTuple(const T &o) \ - { \ - return BlackMisc::tie MEMBERS; \ - } \ - static auto toTuple(T &o) \ - { \ - return BlackMisc::tie MEMBERS; \ - } \ - static auto toMetaTuple(const T &o) \ - { \ - auto tu = BlackMisc::tieMeta MEMBERS; \ - parser().extendMetaTuple(tu); \ - return tu; \ - } \ - static auto toMetaTuple(T &o) \ - { \ - auto tu = BlackMisc::tieMeta MEMBERS; \ - parser().extendMetaTuple(tu); \ - return tu; \ - } \ - static const Parser &parser() \ - { \ - static const Parser p(#MEMBERS); \ - return p; \ - } \ - static const QStringList &jsonMembers() \ - { \ - return parser().m_names; \ - } \ - public: \ - static auto constToTuple(const T &o) \ - { \ - return BlackMisc::tie MEMBERS; \ - } \ - }; \ - } - -namespace BlackMisc -{ - - /*! - * \brief Base class for TupleConverter. - * \details Defines common types and functions which can be used inside the BLACK_DECLARE_TUPLE_CONVERSION() macro. - * \ingroup Tuples - */ - class TupleConverterBase - { - protected: - //! \brief A shorthand alias for passing flags as a compile-time constant. - template - using flags = std::integral_constant; - - //! \brief Create a tuple element with default metadata. - template - static Private::Attribute attr(T &obj) - { - return { obj }; - } - - //! \brief Create a tuple element with attached metadata. - //! @{ - template - static Private::Attribute attr(T &obj, std::integral_constant) - { - return { obj }; - } - template - static Private::Attribute attr(T &obj, QString jsonName) - { - return { obj, jsonName }; - } - template - static Private::Attribute attr(T &obj, QString jsonName, std::integral_constant) - { - return { obj, jsonName }; - } - //! @} - - //! \brief Helper class which parses the stringified macro argument. - struct BLACKMISC_EXPORT Parser - { - Parser(QString); //!< Constructor. - QStringList m_raw; //!< The raw macro argument, split by top-level commas. - QStringList m_names; //!< The names of the tuple members, stripped of any o.m_ prefix. - - //! Fills in any incomplete metadata in a tuple using information from the Parser. - template - void extendMetaTuple(Tu &&tu) const - { - Private::extendMeta(std::forward(tu), m_names, - Private::make_index_sequence>::value>()); - } - }; - }; - - /*! - * \brief Class template for converting class objects to tuples - * \details If a class T uses the BLACK_ENABLE_TUPLE_CONVERSION() and BLACK_DECLARE_TUPLE_CONVERSION() macros, and object - * is an instance of T, then TupleConverter::toTuple(object) will return a std::tuple representing object. - * This tuple can then be passed to a generic function like one of those listed under See Also: - * \see BlackMisc::compare(), BlackMisc::qHash(), BlackMisc::operator<<(), BlackMisc::operator>>(), std::operator==(). - * \remarks The toTuple() function is a private member of TupleConverter, and the class T is declared to be its friend. - * \nosubgrouping - * \ingroup Tuples - */ - template class TupleConverter : private TupleConverterBase - { - // BLACK_DECLARE_TUPLE_CONVERSION generates an explicit specialization of TupleConverter, - // so this unspecialized template will only be used if the macro is missing. It is also - // a good place to put Doxygen comments to document the API of the macro-generated specializations. - - static_assert(std::is_void::value, // always false; is_void<> trick is just to make the condition dependent on the template parameter T - "Missing BLACK_DECLARE_TUPLE_CONVERSION macro for T"); - - public: - /*! - * \name Static Private Member Functions - * \brief Returns a tuple of references to object's data members listed in BLACK_DECLARE_TUPLE_CONVERSION(). - * Can be used like std::tie . - */ - //! @{ - static std::tuple<> toTuple(const T &object) = delete; - static std::tuple<> toTuple(T &object) = delete; - static std::tuple<> constToTuple(const T &object) = delete; - //! @} - - /*! - * \name Static Private Member Functions - * \brief Returns a tuple of structs, each of which contains a reference to one of object's data members and its attched metadata. - */ - //! @{ - static std::tuple<> toMetaTuple(const T &object) = delete; - static std::tuple<> toMetaTuple(T &object) = delete; - //! @} - - /*! - * \name Static Private Member Functions - * \brief Returns an object with information extracted from the stringified macro argument. - */ - static const Parser &parser() = delete; - - /*! - * \name Static Private Member Functions - * \brief Returns a list of the names of the tuple members. - * \deprecated This information is now embedded in the meta tuples. - */ - static const QStringList &jsonMembers() = delete; - }; - - // Needed so that our qHash overload doesn't hide the qHash overloads in the global namespace. - // This will be safe as long as no global qHash has the same signature as ours. - // Alternative would be to qualify all our invokations of the global qHash as ::qHash. - using ::qHash; - - /*! - * \brief Works like std::tie, returning a tuple of references to just the values, with metadata removed. - * \ingroup Tuples - */ - template - auto tie(Ts &&... args) - { - return std::make_tuple(Private::tieHelper(args)...); - } - - /*! - * \brief Works like std::tie, returning a tuple of objects, each of which contains metadata plus a reference to a value. - * \ingroup Tuples - */ - template - auto tieMeta(Ts &&... args) - { - return std::make_tuple(Private::tieMetaHelper(args)...); - } - - /*! - * \brief Lexicographical tuple comparison function which is CValueObject-aware. - * \details Tuple members which are CValueObjects are compared using the compare() friend function of CValueObject; - * other tuple members are compared using operator< and operator>. - * \ingroup Tuples - */ - template - int compare(std::tuple a, std::tuple b) - { - auto metaA = Private::recoverMeta(a, Private::make_index_sequence()); - auto metaB = Private::recoverMeta(b, Private::make_index_sequence()); - return Private::TupleHelper::compare_(metaA, metaB, Private::skipFlaggedIndices(metaA)); - } - - /*! - * \brief Marshall the elements of a tuple into a QDBusArgument. - * \ingroup Tuples - */ - template - QDBusArgument &operator <<(QDBusArgument &arg, std::tuple tu) - { - auto valueTu = Private::stripMeta(tu, Private::make_index_sequence()); - auto metaTu = Private::recoverMeta(tu, Private::make_index_sequence()); - return Private::TupleHelper::marshall(arg, valueTu, Private::skipFlaggedIndices(metaTu)); - } - - /*! - * \brief Unmarshall a QDBusArgument into the elements of a tuple. - * \ingroup Tuples - */ - template - const QDBusArgument &operator >>(const QDBusArgument &arg, std::tuple tu) - { - auto valueTu = Private::stripMeta(tu, Private::make_index_sequence()); - auto metaTu = Private::recoverMeta(tu, Private::make_index_sequence()); - return Private::TupleHelper::unmarshall(arg, valueTu, Private::skipFlaggedIndices(metaTu)); - } - - /*! - * \brief Stream a tuple to qDebug. - * \ingroup Tuples - */ - template - QDebug operator <<(QDebug debug, std::tuple tu) - { - auto valueTu = Private::stripMeta(tu, Private::make_index_sequence()); - auto metaTu = Private::recoverMeta(tu, Private::make_index_sequence()); - return Private::TupleHelper::debug(debug, valueTu, Private::skipFlaggedIndices(metaTu)); - } - - /*! - * \brief Stream a tuple to qDebug. - * \ingroup Tuples - */ - template - QNoDebug operator <<(QNoDebug noDebug, std::tuple tu) - { - Q_UNUSED(tu); - return noDebug; - } - - /*! - * \brief Generate a hash value from the elements of a tuple. - * \ingroup Tuples - */ - template - uint qHash(std::tuple tu) - { - auto valueTu = Private::stripMeta(tu, Private::make_index_sequence()); - auto metaTu = Private::recoverMeta(tu, Private::make_index_sequence()); - return Private::TupleHelper::hash(valueTu, Private::skipFlaggedIndices(metaTu)); - } - - /*! - * \brief Convert to a JSON object - * \ingroup Tuples - * \deprecated The QStringList members can be embedded in tuple metadata. - */ - template - QJsonObject serializeJson(const QStringList &members, std::tuple tu) - { - QJsonObject json; - auto valueTu = Private::stripMeta(tu, Private::make_index_sequence()); - auto metaTu = Private::recoverMeta(tu, Private::make_index_sequence()); - Private::TupleHelper::serializeJson(json, members, valueTu, Private::skipFlaggedIndices(metaTu)); - return json; - } - - /*! - * \brief Convert from JSON to object - * \ingroup Tuples - * \deprecated The QStringList members can be embedded in tuple metadata. - */ - template - void deserializeJson(const QJsonObject &json, const QStringList &members, std::tuple tu) - { - auto valueTu = Private::stripMeta(tu, Private::make_index_sequence()); - auto metaTu = Private::recoverMeta(tu, Private::make_index_sequence()); - Private::TupleHelper::deserializeJson(json, members, valueTu, Private::skipFlaggedIndices(metaTu)); - } - - /*! - * \brief Convert to a JSON object - * \ingroup Tuples - */ - template - QJsonObject serializeJson(std::tuple tu) - { - QJsonObject json; - Private::assertMeta(tu); - Private::TupleHelper::serializeJson(json, tu, Private::skipFlaggedIndices(tu)); - return json; - } - - /*! - * \brief Convert from JSON to object - * \ingroup Tuples - */ - template - void deserializeJson(const QJsonObject &json, std::tuple tu) - { - Private::assertMeta(tu); - Private::TupleHelper::deserializeJson(json, tu, Private::skipFlaggedIndices(tu)); - } - -} // namespace BlackMisc - -#endif // guard diff --git a/src/blackmisc/tupleprivate.h b/src/blackmisc/tupleprivate.h deleted file mode 100644 index 214bea865..000000000 --- a/src/blackmisc/tupleprivate.h +++ /dev/null @@ -1,377 +0,0 @@ -/* Copyright (C) 2013 - * swift project Community / Contributors - * - * This file is part of swift project. It is subject to the license terms in the LICENSE file found in the top-level - * directory of this distribution and at http://www.swift-project.org/license.html. No part of swift project, - * including this file, may be copied, modified, propagated, or distributed except according to the terms - * contained in the LICENSE file. - */ - -#ifndef BLACKMISC_TUPLE_PRIVATE_H -#define BLACKMISC_TUPLE_PRIVATE_H - -#include "integersequence.h" -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -namespace BlackMisc -{ - class CEmpty; - template class TupleConverter; - template class CValueObject; - - namespace Private - { - - // Inhibit doxygen warnings about missing documentation - //! \cond PRIVATE - - // To allow CValueObject policy classes to use the tuple system - class EncapsulationBreaker - { - protected: - template - static auto toMetaTuple(T &o) - { - return TupleConverter>::toMetaTuple(o); - } - }; - - // Using SFINAE to help detect missing BLACK_ENABLE_TUPLE_CONVERSION macro in static_assert - std::false_type hasEnabledTupleConversionHelper(...); - template - typename T::EnabledTupleConversion hasEnabledTupleConversionHelper(T *); - template - struct HasEnabledTupleConversion - { - using type = decltype(hasEnabledTupleConversionHelper(static_cast(nullptr))); - static constexpr bool value = type::value; - }; - - // Using tag dispatch to select which implementation of compare() to use - template - int compareHelper(const T &a, const T &b, std::true_type isCValueObjectTag) - { - Q_UNUSED(isCValueObjectTag); - return compare(a, b); - } - template - int compareHelper(const T &a, const T &b, std::false_type isCValueObjectTag) - { - Q_UNUSED(isCValueObjectTag); - if (a < b) { return -1; } - if (a > b) { return 1; } - return 0; - } - - // Create an index_sequence containing indices which match a given predicate. - template - struct GenSequenceOnPredicate; - template - struct GenSequenceOnPredicate - { - static constexpr bool test = P::template test::value; - using type = typename GenSequenceOnPredicate::type; - }; - template - struct GenSequenceOnPredicate - { - static constexpr bool test = P::template test::value; - using type = typename GenSequenceOnPredicate::type; - }; - template - struct GenSequenceOnPredicate - { - using type = index_sequence; - }; - template - struct GenSequenceOnPredicate - { - using type = index_sequence; - }; - template - using make_index_sequence_if = typename GenSequenceOnPredicate::value>::type; - - // Predicates used with make_index_sequence_if. - template - struct FlagPresent - { - using tuple_type = Tu; - template - struct test : std::integral_constant::flags & F)> {}; - }; - template - struct FlagMissing - { - using tuple_type = Tu; - template - struct test : std::integral_constant::flags & F)> {}; - }; - - // Combine make_index_sequence_if with predicates to get the indices of tuple elements with certain flags. - template - auto findFlaggedIndices(Tu &&) -> make_index_sequence_if>> - { - return {}; - } - template - auto skipFlaggedIndices(Tu &&) -> make_index_sequence_if>> - { - return {}; - } - - // CRTP base class for Attribute, to select appropriate method of comparison. - template - struct AttributeComparable; - template - struct AttributeComparable - { - friend int compare(const Derived &, const Derived &) { return 0; } - friend bool operator ==(const Derived &, const Derived &) { return true; } - friend bool operator !=(const Derived &, const Derived &) { return false; } - friend bool operator <(const Derived &, const Derived &) { return false; } - friend bool operator <=(const Derived &, const Derived &) { return true; } - friend bool operator >(const Derived &, const Derived &) { return false; } - friend bool operator >=(const Derived &, const Derived &) { return true; } - }; - template - struct AttributeComparable - { - template using isCValueObject = typename std::is_base_of::type; // historical use case, may need tweaking in future - friend int compare(const Derived &a, const Derived &b) { return compareHelper(a.m_obj, b.m_obj, isCValueObject()); } - friend bool operator ==(const Derived &a, const Derived &b) { return a.m_obj == b.m_obj; } - friend bool operator !=(const Derived &a, const Derived &b) { return a.m_obj != b.m_obj; } - friend bool operator <(const Derived &a, const Derived &b) { return a.m_obj < b.m_obj; } - friend bool operator <=(const Derived &a, const Derived &b) { return a.m_obj <= b.m_obj; } - friend bool operator >(const Derived &a, const Derived &b) { return a.m_obj > b.m_obj; } - friend bool operator >=(const Derived &a, const Derived &b) { return a.m_obj >= b.m_obj; } - }; - template - struct AttributeComparable - { - friend int compare(const Derived &a, const Derived &b) { return a.m_obj.compare(b.m_obj, Qt::CaseInsensitive); } - friend bool operator ==(const Derived &a, const Derived &b) { return a.m_obj.compare(b.m_obj, Qt::CaseInsensitive) == 0; } - friend bool operator !=(const Derived &a, const Derived &b) { return a.m_obj.compare(b.m_obj, Qt::CaseInsensitive) != 0; } - friend bool operator <(const Derived &a, const Derived &b) { return a.m_obj.compare(b.m_obj, Qt::CaseInsensitive) < 0; } - friend bool operator <=(const Derived &a, const Derived &b) { return a.m_obj.compare(b.m_obj, Qt::CaseInsensitive) <= 0; } - friend bool operator >(const Derived &a, const Derived &b) { return a.m_obj.compare(b.m_obj, Qt::CaseInsensitive) > 0; } - friend bool operator >=(const Derived &a, const Derived &b) { return a.m_obj.compare(b.m_obj, Qt::CaseInsensitive) >= 0; } - }; - - // A tuple element with attached metadata. - template - struct Attribute : public AttributeComparable, bool(Flags & DisabledForComparison), bool(Flags & CaseInsensitiveComparison)> - { - using type = T; - static constexpr qint64 flags = Flags; - - Attribute(T &obj, QString jsonName = {}) : m_obj(obj), m_jsonName(jsonName) {} - void extend(QString jsonName) { if (m_jsonName.isEmpty()) m_jsonName = jsonName; } - T &m_obj; - QString m_jsonName; - }; - - // Helpers used in tie(), tieMeta(), and elsewhere, which arrange for the correct types to be passed to std::make_tuple. - // See http://en.cppreference.com/w/cpp/utility/tuple/make_tuple - // "For each Ti in Types..., the corresponding type Vi in Vtypes... is std::decay::type - // unless application of std::decay results in std::reference_wrapper, in which case the deduced type is X&." - template - std::reference_wrapper tieHelper(T &obj) - { - return obj; - } - template - std::reference_wrapper tieHelper(Attribute attr) - { - return attr.m_obj; - } - template - Attribute tieMetaHelper(T &obj) - { - return obj; - } - template - Attribute tieMetaHelper(Attribute attr) - { - return attr; - } - - // Compile-time assert for functions which require a meta tuple - template - void assertMeta(const Tu &) { static_assert(std::is_void::value, "Function expected a meta tuple, got a value tuple"); } - template - void assertMeta(const std::tuple...> &) {} - - // Convert a meta tuple to a value tuple - template - auto stripMeta(Tu &&tu, index_sequence) - { - return std::make_tuple(tieHelper(std::get(std::forward(tu)))...); - } - - // Convert a value tuple to a meta tuple with default metadata - template - auto recoverMeta(Tu &&tu, index_sequence) - { - return std::make_tuple(tieMetaHelper(std::get(std::forward(tu)))...); - } - - // Fill in any incomplete metadata in a meta tuple, from an appropriate source - template - void extendMeta(Tu &&tu, const QStringList &jsonNames, index_sequence) - { - [](...){}((std::get(std::forward(tu)).extend(jsonNames[Is]), 0)...); - } - - // Applying operations to all elements in a tuple, using index_sequence for clean recursion - class TupleHelper - { - public: - template - static int compare_(const Tu &a, const Tu &b, index_sequence) // underscore to avoid hiding the name "compare" in other scopes - { - return compareImpl(std::make_pair(std::get(a), std::get(b))...); - } - - template - static QDBusArgument &marshall(QDBusArgument &arg, const Tu &tu, index_sequence) - { - marshallImpl(arg, std::get(tu)...); - return arg; - } - - template - static const QDBusArgument &unmarshall(const QDBusArgument &arg, Tu &tu, index_sequence) - { - unmarshallImpl(arg, std::get(tu)...); - return arg; - } - - template - static QDebug debug(QDebug dbg, const Tu &tu, index_sequence) - { - debugImpl(dbg, std::get(tu)...); - return dbg; - } - - template - static uint hash(const Tu &tu, index_sequence) - { - return hashImpl(qHash(std::get(tu))...); - } - - template - static void serializeJson(QJsonObject &json, const QStringList &names, const Tu &tu, index_sequence) - { - serializeJsonImpl(json, std::make_pair(names[Is], get_ref(tu))...); - } - - template - static void deserializeJson(const QJsonObject &json, const QStringList &names, Tu &tu, index_sequence) - { - deserializeJsonImpl(json, std::make_pair(names[Is], get_ref(tu))...); - } - - template - static void serializeJson(QJsonObject &json, const Tu &tu, index_sequence) - { - serializeJsonImpl(json, std::make_pair(std::get(tu).m_jsonName, get_ref(tu))...); - Q_UNUSED(tu); // avoid compiler warning when all attributes are JSON disabled - } - - template - static void deserializeJson(const QJsonObject &json, Tu &tu, index_sequence) - { - deserializeJsonImpl(json, std::make_pair(std::get(tu).m_jsonName, get_ref(tu))...); - Q_UNUSED(tu); // avoid compiler warning when all attributes are JSON disabled - } - - private: - template - static auto get_ref(Tu &&tu) - { - return tieHelper(std::get(std::forward(tu))); - } - - static int compareImpl() { return 0; } - template - static int compareImpl(const std::pair &head, const Ts &... tail) - { - int result = compare(head.first, head.second); - if (result) return result; - return compareImpl(tail...); - } - - static void marshallImpl(QDBusArgument &) {} - template - static void marshallImpl(QDBusArgument &arg, const T &head, const Ts &... tail) - { - marshallHelper(arg, head, 0); - marshallImpl(arg, tail...); - } - template ::value, int> = 0> - static void marshallHelper(QDBusArgument &arg, const T &val, int) { static_cast(val).marshallToDbus(arg); } - template ::value, int> = 0> - static void marshallHelper(QDBusArgument &arg, const T &val, int) { arg << static_cast(val); } - template - static void marshallHelper(QDBusArgument &arg, const T &val, ...) { arg << val; } - - static void unmarshallImpl(const QDBusArgument &) {} - template - static void unmarshallImpl(const QDBusArgument &arg, T &head, Ts &... tail) - { - unmarshallHelper(arg, head, 0); - unmarshallImpl(arg, tail...); - } - template ::value, int> = 0> - static void unmarshallHelper(const QDBusArgument &arg, T &val, int) { static_cast(val).unmarshallFromDbus(arg); } - template ::value, int> = 0> - static void unmarshallHelper(const QDBusArgument &arg, T &val, int) { int i; arg >> i; val = static_cast(i); } - template - static void unmarshallHelper(const QDBusArgument &arg, T &val, ...) { arg >> val; } - - static void debugImpl(QDebug) {} - template - static void debugImpl(QDebug dbg, const T &head, const Ts &... tail) - { - dbg << head; - debugImpl(dbg, tail...); - } - - static void serializeJsonImpl(QJsonObject &) {} - template - static void serializeJsonImpl(QJsonObject &json, std::pair head, Ts... tail) - { - json << head; - serializeJsonImpl(json, tail...); - } - - static void deserializeJsonImpl(const QJsonObject &) {} - template - static void deserializeJsonImpl(const QJsonObject &json, std::pair head, Ts... tail) - { - json.value(head.first) >> head.second; - deserializeJsonImpl(json, tail...); - } - - static uint hashImpl() { return 0; } - template - static uint hashImpl(uint head, Ts... tail) { return head ^ hashImpl(tail...); } - }; - - //! \endcond - - } // namespace Private - -} // namespace BlackMisc - -#endif // guard diff --git a/src/blackmisc/valueobject.h b/src/blackmisc/valueobject.h index d0aae73d0..4d9edaf5b 100644 --- a/src/blackmisc/valueobject.h +++ b/src/blackmisc/valueobject.h @@ -15,7 +15,6 @@ #include "blackmiscexport.h" #include "dbus.h" #include "metaclass.h" -#include "tuple.h" #include "json.h" #include "compare.h" #include "variant.h" @@ -68,7 +67,7 @@ namespace BlackMisc * \tparam Base The class which this one shall inherit from (default is CEmpty, * but this can be changed to create a deeper inheritance hierarchy). */ - template class CValueObject : + template class CValueObject : public Base, public Mixin::MetaType, public Mixin::HashByMetaClass, diff --git a/src/blackmisc/variant.h b/src/blackmisc/variant.h index 0a025f1e3..d450e079d 100644 --- a/src/blackmisc/variant.h +++ b/src/blackmisc/variant.h @@ -15,7 +15,6 @@ #include "variantprivate.h" #include "blackmiscexport.h" #include "stringutils.h" -#include "tuple.h" #include "compare.h" #include "dbus.h" #include "json.h" diff --git a/tests/blackmisc/testvariantandmap.cpp b/tests/blackmisc/testvariantandmap.cpp index 5841b8636..c5bf665cb 100644 --- a/tests/blackmisc/testvariantandmap.cpp +++ b/tests/blackmisc/testvariantandmap.cpp @@ -17,7 +17,6 @@ #include "testvariantandmap.h" #include "blackmisc/aviation/atcstation.h" #include "blackmisc/propertyindexallclasses.h" -#include "blackmisc/tuple.h" #include #include #include