From ab910e09c713161f568a867a09af5a52eb79c35f Mon Sep 17 00:00:00 2001 From: Marc Mutz Date: Thu, 14 Sep 2023 18:22:12 +0200 Subject: Long live QDebug::operator<<(q(u)int128)! MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Replace the ad-hoc implementation of QTest::toString() in tst_qglobal.cpp with a QDebug stream operator, so the QTest::toString() fall-back to QDebug::toString() kicks in. Since the ABI issues revolving around the new int128 types are not known, yet, avoid baking the types into the ABI by a) making the operators constrained templates¹ and b) passing though void* to the exported helpers. These functions return an error message if Qt was compiled without support for int128. Use the Thiago Trick™ (leaving obviouly dead code around for the compiler to remove without warning) to expose more code to more compilers. This appears to work elsewhere in Qt, so I hope it does here, too. This completes the minimum qint128 support so we're able to debug code and write tests that use these types. ¹ Templates, unlike inline member functions of wholly-exported classes, never² become part of the ABI. ² Fixes: QTBUG-117011 Change-Id: Ia4e56d26c6ffd18b7d69a7ceaed65b2211d258b2 Reviewed-by: Qt CI Bot Reviewed-by: Volker Hilsheimer --- src/corelib/io/qdebug.cpp | 99 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 99 insertions(+) (limited to 'src/corelib/io/qdebug.cpp') diff --git a/src/corelib/io/qdebug.cpp b/src/corelib/io/qdebug.cpp index 0eaeb5ccda..ca5da10022 100644 --- a/src/corelib/io/qdebug.cpp +++ b/src/corelib/io/qdebug.cpp @@ -15,6 +15,7 @@ #include #include +#include #include QT_BEGIN_NAMESPACE @@ -436,6 +437,87 @@ void QDebug::putTimeUnit(qint64 num, qint64 den) stream->ts << timeUnit(num, den); // ### optimize } +namespace { + +#ifdef QT_SUPPORTS_INT128 + +constexpr char Q_INT128_MIN_STR[] = "-170141183460469231731687303715884105728"; + +constexpr int Int128BufferSize = sizeof(Q_INT128_MIN_STR); +using Int128Buffer = std::array; + // numeric_limits::digits10 may not exist + +static char *i128ToStringHelper(Int128Buffer &buffer, quint128 n) +{ + auto dst = buffer.data() + buffer.size(); + *--dst = '\0'; // NUL-terminate + if (n == 0) { + *--dst = '0'; // and done + } else { + while (n != 0) { + *--dst = "0123456789"[n % 10]; + n /= 10; + } + } + return dst; +} +#endif // QT_SUPPORTS_INT128 + +[[maybe_unused]] +static const char *int128Warning() +{ + const char *msg = "Qt was not compiled with int128 support."; + qWarning("%s", msg); + return msg; +} + +} // unnamed namespace + +/*! + \since 6.7 + \internal + Helper to the qint128 debug streaming output. + */ +void QDebug::putInt128([[maybe_unused]] const void *p) +{ +#ifdef QT_SUPPORTS_INT128 + Q_ASSERT(p); + qint128 i; + memcpy(&i, p, sizeof(i)); // alignment paranoia + if (i == Q_INT128_MIN) { + // -i is not representable, hardcode the result: + stream->ts << Q_INT128_MIN_STR; + } else { + Int128Buffer buffer; + auto dst = i128ToStringHelper(buffer, i < 0 ? -i : i); + if (i < 0) + *--dst = '-'; + stream->ts << dst; + } + return; +#endif // QT_SUPPORTS_INT128 + stream->ts << int128Warning(); +} + +/*! + \since 6.7 + \internal + Helper to the quint128 debug streaming output. + */ +void QDebug::putUInt128([[maybe_unused]] const void *p) +{ +#ifdef QT_SUPPORTS_INT128 + Q_ASSERT(p); + quint128 i; + memcpy(&i, p, sizeof(i)); // alignment paranoia + Int128Buffer buffer; + stream->ts << i128ToStringHelper(buffer, i); + return; +#endif // QT_SUPPORTS_INT128 + stream->ts << int128Warning(); +} + + /*! \fn QDebug::swap(QDebug &other) \since 5.0 @@ -902,6 +984,23 @@ QDebug &QDebug::resetFormat() The unit is not localized. */ +/*! + \fn template > QDebug::operator<<(T i) + \fn template > QDebug::operator<<(T i) + \since 6.7 + + Prints the textual representation of the 128-bit integer \a i. + + \note This operator is only available if Qt supports 128-bit integer types. + If 128-bit integer types are available in your build, but the Qt libraries + were compiled without, the operator will print a warning instead. + + \note Because the operator is a function template, no implicit conversions + are performed on its argument. It must be exactly qint128/quint128. + + \sa QT_SUPPORTS_INT128 +*/ + /*! \fn template QString QDebug::toString(T &&object) \since 6.0 -- cgit v1.2.3