From 2aa39be4c23ad837c6a09b5cf74c74da670d7ebf Mon Sep 17 00:00:00 2001 From: Tatiana Borisova Date: Thu, 11 Jul 2024 12:20:26 +0200 Subject: [PATCH] Add QDebug printing for the std/Qt::_ordering types [ChangeLog][QtCore][QDebug] Added possibility to print {std/Qt} weak/partial/strong_ordering values with QDebug << operator. Change-Id: Ie880cb34c19f79a404c692c2322b3460d72bfde4 Reviewed-by: Marc Mutz --- src/corelib/global/qcomparehelpers.h | 54 +++++++++++++++++++- src/corelib/io/qdebug.cpp | 49 ++++++++++++++++++ src/corelib/io/qdebug.h | 14 +++++ tests/auto/corelib/io/qdebug/tst_qdebug.cpp | 32 ++++++++++++ tests/auto/testlib/tostring/tst_tostring.cpp | 37 ++++++++++++++ 5 files changed, 184 insertions(+), 2 deletions(-) diff --git a/src/corelib/global/qcomparehelpers.h b/src/corelib/global/qcomparehelpers.h index 5f946dddd3c..922c62fbe21 100644 --- a/src/corelib/global/qcomparehelpers.h +++ b/src/corelib/global/qcomparehelpers.h @@ -14,6 +14,7 @@ #pragma qt_sync_stop_processing #endif +#include #include #include #include @@ -31,16 +32,34 @@ QT_BEGIN_NAMESPACE class QPartialOrdering; namespace QtOrderingPrivate { -#ifdef __cpp_lib_three_way_comparison +template struct is_std_ordering_type : std::false_type {}; +template struct is_qt_ordering_type : std::false_type {}; + +template constexpr bool is_std_ordering_type_v = is_std_ordering_type::value; +template constexpr bool is_qt_ordering_type_v = is_qt_ordering_type::value; + +enum class QtOrderingType { + QtOrder = 0x00, + StdOrder = 0x01, + Partial = 0x00, + Weak = 0x20, + Strong = 0x40, + StrengthMask = Weak|Strong, +}; +Q_DECLARE_FLAGS(QtOrderingTypeFlag, QtOrderingType) +Q_DECLARE_OPERATORS_FOR_FLAGS(QtOrderingPrivate::QtOrderingTypeFlag) template struct StdOrdering; template struct QtOrdering; +#ifdef __cpp_lib_three_way_comparison #define QT_STD_MAP(x) \ template <> struct StdOrdering< Qt::x##_ordering> : q20::type_identity {};\ template <> struct StdOrdering : q20::type_identity {};\ template <> struct QtOrdering : q20::type_identity< Qt::x##_ordering> {};\ template <> struct QtOrdering< Qt::x##_ordering> : q20::type_identity< Qt::x##_ordering> {};\ + template <> struct is_std_ordering_type : std::true_type {};\ + template <> struct is_qt_ordering_type< Qt::x##_ordering> : std::true_type {};\ /* end */ QT_STD_MAP(partial) QT_STD_MAP(weak) @@ -49,6 +68,11 @@ QT_STD_MAP(strong) template <> struct StdOrdering : q20::type_identity {}; template <> struct QtOrdering : q20::type_identity< Qt::partial_ordering> {}; +#else +template <> struct is_qt_ordering_type< Qt::partial_ordering> : std::true_type {}; +template <> struct is_qt_ordering_type< Qt::weak_ordering> : std::true_type {}; +template <> struct is_qt_ordering_type< Qt::strong_ordering> : std::true_type {}; +#endif // __cpp_lib_three_way_comparison template constexpr auto to_std(In in) noexcept -> typename QtOrderingPrivate::StdOrdering::type @@ -58,7 +82,33 @@ template constexpr auto to_Qt(In in) noexcept -> typename QtOrderingPrivate::QtOrdering::type { return in; } -#endif // __cpp_lib_three_way_comparison +template +constexpr bool is_ordering_type_v + = std::disjunction_v, is_std_ordering_type>; + +template +constexpr std::enable_if_t, QtOrderingTypeFlag> +orderingFlagsFor(T t) noexcept +{ + QtOrderingTypeFlag flags = QtOrderingType::QtOrder; + Qt::partial_ordering convertedOrder(t); + if constexpr (std::is_same_v) + flags = flags | QtOrderingType::Strong; + else if constexpr (std::is_same_v) + flags = flags | QtOrderingType::Partial; + else if constexpr (std::is_same_v) + flags = flags | QtOrderingType::Weak; + return flags; +} + +template +constexpr std::enable_if_t, QtOrderingTypeFlag> +orderingFlagsFor(T t) noexcept +{ + QtOrderingPrivate::QtOrderingTypeFlag flags = QtOrderingPrivate::QtOrderingType::StdOrder; + return QtOrderingTypeFlag(flags + | QtOrderingPrivate::orderingFlagsFor(QtOrderingPrivate::to_Qt(t))); +} } // namespace QtOrderingPrivate /* diff --git a/src/corelib/io/qdebug.cpp b/src/corelib/io/qdebug.cpp index 9a00b0b2006..cd835f548c0 100644 --- a/src/corelib/io/qdebug.cpp +++ b/src/corelib/io/qdebug.cpp @@ -511,6 +511,46 @@ void QDebug::putUInt128([[maybe_unused]] const void *p) stream->ts << int128Warning(); } +/*! + \since 6.9 + \internal + Helper to the ::<>_ordering debug output. + It generates the string in following format: + ::_ordering:: + */ +void QDebug::putQtOrdering(QtOrderingPrivate::QtOrderingTypeFlag flags, Qt::partial_ordering order) +{ + using QtOrderingPrivate::QtOrderingType; + std::string result; + if ((flags & QtOrderingType::StdOrder) == QtOrderingType::StdOrder) + result += "std"; + else if ((flags & QtOrderingType::QtOrder) == QtOrderingType::QtOrder) + result += "Qt"; + + result += "::"; + const bool isStrong = ((flags & QtOrderingType::Strong) == QtOrderingType::Strong); + if (isStrong) + result += "strong"; + else if ((flags & QtOrderingType::Weak) == QtOrderingType::Weak) + result += "weak"; + else if ((flags & QtOrderingType::Partial) == QtOrderingType::Partial) + result += "partial"; + result += "_ordering::"; + + if (order == Qt::partial_ordering::equivalent) { + if (isStrong) + result += "equal"; + else + result += "equivalent"; + } else if (order == Qt::partial_ordering::greater) { + result += "greater"; + } else if (order == Qt::partial_ordering::less) { + result += "less"; + } else { + result += "unordered"; + } + stream->ts << result.data(); +} /*! \fn QDebug::swap(QDebug &other) @@ -948,6 +988,15 @@ QDebug &QDebug::resetFormat() \internal */ +/*! + \fn template > QDebug::operator<<(QDebug debug, T t) + \since 6.9 + Prints the Qt or std ordering value \a t to the \a debug object. + + \note This function only participates in overload resolution if \c T + is one of ::_ordering. +*/ + /*! \since 6.5 \fn template QDebug &QDebug::operator<<(const std::basic_string &s) diff --git a/src/corelib/io/qdebug.h b/src/corelib/io/qdebug.h index 03f0886304a..f941bf40cb0 100644 --- a/src/corelib/io/qdebug.h +++ b/src/corelib/io/qdebug.h @@ -9,6 +9,7 @@ #pragma qt_class(QtDebug) #endif +#include #include #include #include @@ -79,6 +80,8 @@ class QT6_ONLY(Q_CORE_EXPORT) QDebug : public QIODeviceBase QT7_ONLY(Q_CORE_EXPORT) void putTimeUnit(qint64 num, qint64 den); QT7_ONLY(Q_CORE_EXPORT) void putInt128(const void *i); QT7_ONLY(Q_CORE_EXPORT) void putUInt128(const void *i); + QT7_ONLY(Q_CORE_EXPORT) void putQtOrdering(QtOrderingPrivate::QtOrderingTypeFlag flags, + Qt::partial_ordering order); public: explicit QDebug(QIODevice *device) : stream(new Stream(device)) {} explicit QDebug(QString *string) : stream(new Stream(string)) {} @@ -250,6 +253,17 @@ public: { return toBytesImpl(&streamTypeErased, std::addressof(object)); } + +private: + template + using if_ordering_type = std::enable_if_t, bool>; + + template = true> + friend QDebug operator<<(QDebug debug, T t) + { + debug.putQtOrdering(QtOrderingPrivate::orderingFlagsFor(t), Qt::partial_ordering(t)); + return debug; + } }; Q_DECLARE_SHARED(QDebug) diff --git a/tests/auto/corelib/io/qdebug/tst_qdebug.cpp b/tests/auto/corelib/io/qdebug/tst_qdebug.cpp index 9d9fc853ddf..8bc2985a46d 100644 --- a/tests/auto/corelib/io/qdebug/tst_qdebug.cpp +++ b/tests/auto/corelib/io/qdebug/tst_qdebug.cpp @@ -4,6 +4,7 @@ #include +#include #include #include @@ -90,6 +91,7 @@ private slots: void qDebugStdChrono_data() const; void qDebugStdChrono() const; void qDebugStdOptional() const; + void qDebugStdOrdering() const; void textStreamModifiers() const; void resetFormat() const; void defaultMessagehandler() const; @@ -1239,6 +1241,36 @@ void tst_QDebug::qDebugStdOptional() const QCOMPARE(QString::fromLatin1(s_function), function); } +void tst_QDebug::qDebugStdOrdering() const +{ + QLatin1StringView file, function; + MessageHandlerSetter mhs(myMessageHandler); + { + QDebug d = qDebug(); + d << Qt::partial_ordering::less + << Qt::partial_ordering::unordered + << Qt::weak_ordering::greater + << Qt::strong_ordering::equal; + } +#ifndef QT_NO_MESSAGELOGCONTEXT + file = QLatin1StringView(__FILE__); + function = QLatin1StringView(Q_FUNC_INFO); +#endif + const auto cmpStr = "Qt::partial_ordering::lessQt::partial_ordering::unorderedQt::weak_ordering::greaterQt::strong_ordering::equal"_L1; + QCOMPARE(s_msgType, QtDebugMsg); + QCOMPARE(s_msg, cmpStr); +#ifdef __cpp_lib_three_way_comparison + qDebug() << std::partial_ordering::less + << std::partial_ordering::unordered + << std::weak_ordering::greater + << std::strong_ordering::equal; + const auto stdStr = "std::partial_ordering::lessstd::partial_ordering::unorderedstd::weak_ordering::greaterstd::strong_ordering::equal"_L1; + QCOMPARE(s_msg, stdStr); +#endif + QCOMPARE(QLatin1StringView(s_file), file); + QCOMPARE(QLatin1StringView(s_function), function); +} + void tst_QDebug::textStreamModifiers() const { QString file, function; diff --git a/tests/auto/testlib/tostring/tst_tostring.cpp b/tests/auto/testlib/tostring/tst_tostring.cpp index 8d3c59f2578..df99f96f458 100644 --- a/tests/auto/testlib/tostring/tst_tostring.cpp +++ b/tests/auto/testlib/tostring/tst_tostring.cpp @@ -4,6 +4,7 @@ #include #include +#include #include @@ -21,6 +22,9 @@ private slots: void chrono_duration_data(); void chrono_duration() { testRows(); } + + void orderingTypeValue_data(); + void orderingTypeValue() { testRows(); } }; void tst_toString::addColumns() @@ -211,5 +215,38 @@ void tst_toString::chrono_duration_data() #endif } +void tst_toString::orderingTypeValue_data() +{ + addColumns(); +#define CHECK(x) ADD_ROW(#x, x, #x) + CHECK(Qt::strong_ordering::equal); + CHECK(Qt::strong_ordering::less); + CHECK(Qt::strong_ordering::greater); + + CHECK(Qt::partial_ordering::equivalent); + CHECK(Qt::partial_ordering::less); + CHECK(Qt::partial_ordering::greater); + CHECK(Qt::partial_ordering::unordered); + + CHECK(Qt::weak_ordering::equivalent); + CHECK(Qt::weak_ordering::less); + CHECK(Qt::weak_ordering::greater); +#ifdef __cpp_lib_three_way_comparison + CHECK(std::strong_ordering::equal); + CHECK(std::strong_ordering::less); + CHECK(std::strong_ordering::greater); + + CHECK(std::partial_ordering::equivalent); + CHECK(std::partial_ordering::less); + CHECK(std::partial_ordering::greater); + CHECK(std::partial_ordering::unordered); + + CHECK(std::weak_ordering::equivalent); + CHECK(std::weak_ordering::less); + CHECK(std::weak_ordering::greater); +#endif // __cpp_lib_three_way_comparison +#undef CHECK +} + QTEST_APPLESS_MAIN(tst_toString) #include "tst_tostring.moc"