diff options
| author | Thiago Macieira <thiago.macieira@intel.com> | 2023-04-20 17:35:22 -0700 |
|---|---|---|
| committer | Thiago Macieira <thiago.macieira@intel.com> | 2023-05-06 17:54:23 +0000 |
| commit | a2551c45d496c23045eb8451e080e75b2f8b42c1 (patch) | |
| tree | 66ce1e4a0cb5341a34150d410484b4ff6e8009f2 /src/corelib | |
| parent | 59f8da17e6a2989b072254970d23281301114503 (diff) | |
Move the formatting of <chrono> durations to QDebug & QtTest
[ChangeLog][QtCore][QDebug] Added pretty formatting of C++ <chrono>
durations.
[ChangeLog][QtTest] Added pretty formatting of C++ <chrono> durations
for QCOMPARE expressions.
Change-Id: I3b169860d8bd41e9be6bfffd1757cc087ba957fa
Reviewed-by: Qt CI Bot <qt_ci_bot@qt-project.org>
Reviewed-by: Volker Hilsheimer <volker.hilsheimer@qt.io>
Diffstat (limited to 'src/corelib')
| -rw-r--r-- | src/corelib/io/qdebug.cpp | 98 | ||||
| -rw-r--r-- | src/corelib/io/qdebug.h | 9 |
2 files changed, 107 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) { |
