summaryrefslogtreecommitdiffstats
path: root/src/corelib/io/qdebug.cpp
diff options
context:
space:
mode:
authorMarc Mutz <marc.mutz@qt.io>2023-09-14 18:22:12 +0200
committerMarc Mutz <marc.mutz@qt.io>2023-12-09 21:00:13 +0100
commitab910e09c713161f568a867a09af5a52eb79c35f (patch)
tree0c03a2cab401ad7d806389edc51d19769461df86 /src/corelib/io/qdebug.cpp
parentf9f1272e7c438b79591032877f2b386af8085c3f (diff)
Long live QDebug::operator<<(q(u)int128)!
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. ² <insert here the convoluted scenario under which this is false> Fixes: QTBUG-117011 Change-Id: Ia4e56d26c6ffd18b7d69a7ceaed65b2211d258b2 Reviewed-by: Qt CI Bot <qt_ci_bot@qt-project.org> Reviewed-by: Volker Hilsheimer <volker.hilsheimer@qt.io>
Diffstat (limited to 'src/corelib/io/qdebug.cpp')
-rw-r--r--src/corelib/io/qdebug.cpp99
1 files changed, 99 insertions, 0 deletions
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 <private/qtextstream_p.h>
#include <private/qtools_p.h>
+#include <array>
#include <q20chrono.h>
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<char, Int128BufferSize>;
+ // numeric_limits<qint128>::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
@@ -903,6 +985,23 @@ QDebug &QDebug::resetFormat()
*/
/*!
+ \fn template <typename T, if_qint128<T>> QDebug::operator<<(T i)
+ \fn template <typename T, if_quint128<T>> 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 <class T> QString QDebug::toString(T &&object)
\since 6.0