summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/corelib/io/qdebug.cpp98
-rw-r--r--src/corelib/io/qdebug.h9
-rw-r--r--src/testlib/qtest.h13
-rw-r--r--src/testlib/qtestcase.h3
4 files changed, 123 insertions, 0 deletions
diff --git a/src/corelib/io/qdebug.cpp b/src/corelib/io/qdebug.cpp
index 0a72696a372..56deeb7cf75 100644
--- a/src/corelib/io/qdebug.cpp
+++ b/src/corelib/io/qdebug.cpp
@@ -15,6 +15,8 @@
#include <private/qtextstream_p.h>
#include <private/qtools_p.h>
+#include <q20chrono.h>
+
QT_BEGIN_NAMESPACE
using namespace QtMiscUtils;
@@ -346,6 +348,90 @@ void QDebug::putByteArray(const char *begin, size_t length, Latin1Content conten
}
/*!
+ \since 6.6
+ \internal
+ Helper to the std::chrono::duration debug streaming output.
+ */
+QByteArray QDebug::timeUnit(qint64 num, qint64 den)
+{
+ using namespace std::chrono;
+ using namespace q20::chrono;
+
+ if (num == 1 && den > 1) {
+ // sub-multiple of seconds
+ char prefix = '\0';
+ auto tryprefix = [&](auto d, char c) {
+ static_assert(decltype(d)::num == 1, "not an SI prefix");
+ if (den == decltype(d)::den)
+ prefix = c;
+ };
+
+ // "u" should be "ยต", but debugging output is not always UTF-8-safe
+ tryprefix(std::milli{}, 'm');
+ tryprefix(std::micro{}, 'u');
+ tryprefix(std::nano{}, 'n');
+ tryprefix(std::pico{}, 'p');
+ tryprefix(std::femto{}, 'f');
+ tryprefix(std::atto{}, 'a');
+ // uncommon ones later
+ tryprefix(std::centi{}, 'c');
+ tryprefix(std::deci{}, 'd');
+ if (prefix) {
+ char unit[3] = { prefix, 's' };
+ return QByteArray(unit, sizeof(unit) - 1);
+ }
+ }
+
+ const char *unit = nullptr;
+ if (num > 1 && den == 1) {
+ // multiple of seconds - but we don't use SI prefixes
+ auto tryunit = [&](auto d, const char *name) {
+ static_assert(decltype(d)::period::den == 1, "not a multiple of a second");
+ if (unit || num % decltype(d)::period::num)
+ return;
+ unit = name;
+ num /= decltype(d)::period::num;
+ };
+ tryunit(years{}, "yr");
+ tryunit(weeks{}, "wk");
+ tryunit(days{}, "d");
+ tryunit(hours{}, "h");
+ tryunit(minutes{}, "min");
+ }
+ if (!unit)
+ unit = "s";
+
+ if (num == 1 && den == 1)
+ return unit;
+ if (Q_UNLIKELY(num < 1 || den < 1))
+ return QString::asprintf("<invalid time unit %lld/%lld>", num, den).toLatin1();
+
+ // uncommon units: will return something like "[2/3]s"
+ // strlen("[/]min") = 6
+ char buf[2 * (std::numeric_limits<qint64>::digits10 + 2) + 10];
+ size_t len = 0;
+ auto appendChar = [&](char c) {
+ Q_ASSERT(len < sizeof(buf));
+ buf[len++] = c;
+ };
+ auto appendNumber = [&](qint64 value) {
+ if (value >= 10'000 && (value % 1000) == 0)
+ len += qsnprintf(buf + len, sizeof(buf) - len, "%.6g", double(value)); // "1e+06"
+ else
+ len += qsnprintf(buf + len, sizeof(buf) - len, "%lld", value);
+ };
+ appendChar('[');
+ appendNumber(num);
+ if (den != 1) {
+ appendChar('/');
+ appendNumber(den);
+ }
+ appendChar(']');
+ memcpy(buf + len, unit, strlen(unit));
+ return QByteArray(buf, len + strlen(unit));
+}
+
+/*!
\fn QDebug::swap(QDebug &other)
\since 5.0
@@ -777,6 +863,18 @@ QDebug &QDebug::resetFormat()
*/
/*!
+ \since 6.6
+ \fn template <typename Rep, typename Period> QDebug &QDebug::operator<<(std::chrono::duration<Rep, Period> duration)
+
+ Prints the time duration \a duration to the stream and returns a reference
+ to the stream. The printed string is the numeric representation of the
+ period followed by the time unit, similar to what the C++ Standard Library
+ would produce with \c{std::ostream}.
+
+ The unit is not localized.
+*/
+
+/*!
\fn template <class T> QString QDebug::toString(T &&object)
\since 6.0
diff --git a/src/corelib/io/qdebug.h b/src/corelib/io/qdebug.h
index e39f9afd316..3fa9c420525 100644
--- a/src/corelib/io/qdebug.h
+++ b/src/corelib/io/qdebug.h
@@ -16,6 +16,7 @@
#include <QtCore/qsharedpointer.h>
// all these have already been included by various headers above, but don't rely on indirect includes:
+#include <chrono>
#include <list>
#include <map>
#include <string>
@@ -67,6 +68,7 @@ class QT6_ONLY(Q_CORE_EXPORT) QDebug : public QIODeviceBase
QT7_ONLY(Q_CORE_EXPORT) void putUcs4(uint ucs4);
QT7_ONLY(Q_CORE_EXPORT) void putString(const QChar *begin, size_t length);
QT7_ONLY(Q_CORE_EXPORT) void putByteArray(const char *begin, size_t length, Latin1Content content);
+ QT7_ONLY(Q_CORE_EXPORT) static QByteArray timeUnit(qint64 num, qint64 den);
public:
explicit QDebug(QIODevice *device) : stream(new Stream(device)) {}
explicit QDebug(QString *string) : stream(new Stream(string)) {}
@@ -189,6 +191,13 @@ public:
{ return *this << QString::fromUcs4(s.data(), s.size()); }
#endif // !Q_QDOC
+ template <typename Rep, typename Period>
+ QDebug &operator<<(std::chrono::duration<Rep, Period> duration)
+ {
+ stream->ts << duration.count() << timeUnit(Period::num, Period::den);
+ return maybeSpace();
+ }
+
template <typename T>
static QString toString(T &&object)
{
diff --git a/src/testlib/qtest.h b/src/testlib/qtest.h
index 175affebcf5..73278791caa 100644
--- a/src/testlib/qtest.h
+++ b/src/testlib/qtest.h
@@ -356,6 +356,19 @@ template<> inline char *toString(const QCborMap &m)
return Internal::QCborValueFormatter::format(m);
}
+template <typename Rep, typename Period> char *toString(std::chrono::duration<Rep, Period> dur)
+{
+ QString r;
+ QDebug d(&r);
+ d.nospace() << qSetRealNumberPrecision(9) << dur;
+ if constexpr (Period::num != 1 || Period::den != 1) {
+ // include the equivalent value in seconds, in parentheses
+ using namespace std::chrono;
+ d << " (" << duration_cast<duration<qreal>>(dur).count() << "s)";
+ }
+ return qstrdup(std::move(r).toUtf8().constData());
+}
+
template <typename T1, typename T2>
inline char *toString(const std::pair<T1, T2> &pair)
{
diff --git a/src/testlib/qtestcase.h b/src/testlib/qtestcase.h
index 3e0b2b3fb3c..bd65c0ecab3 100644
--- a/src/testlib/qtestcase.h
+++ b/src/testlib/qtestcase.h
@@ -360,6 +360,9 @@ namespace QTest
template <class... Types>
inline char *toString(const std::tuple<Types...> &tuple);
+ template <typename Rep, typename Period>
+ inline char *toString(std::chrono::duration<Rep, Period> duration);
+
Q_TESTLIB_EXPORT char *toHexRepresentation(const char *ba, qsizetype length);
Q_TESTLIB_EXPORT char *toPrettyCString(const char *unicode, qsizetype length);
Q_TESTLIB_EXPORT char *toPrettyUnicode(QStringView string);