Long live QDebug::toBytes()!

I've seen over and over again how test authors are plagued by the
impedance mismatch between their 8-bit actual data and the result of
QString::toString() being in UTF-16. They invariably ditch their 8-bit
inputs and go to QString, but the mere fact that they start out with
8-bit input and then run into problems means we have a gaping API hole
here. QTest::toString() also suffers from this.

So add the option to a) construct a QDebug object over a QByteArray
(already supported by underlying QTextStream) and b) to stream into
QByteArray like toString() streams into QString.

Finally, make QTest::toString() use the new toBytes() function instead
of the old toString() one.

This saves 1% (91122→90248) in tst_tostring exeutable size on
optimized Linux AMD64 GCC 9 builds.

[ChangeLog][QtCore][QDebug] Added ctor from QByteArray* and a static
toBytes() function.

Change-Id: I2b021513d6427a1a961f39e751eaf4faaf527ba8
Reviewed-by: Thiago Macieira <thiago.macieira@intel.com>
This commit is contained in:
Marc Mutz 2024-07-18 22:57:10 +02:00
parent b892b39a7a
commit b57fac818b
3 changed files with 34 additions and 1 deletions

View File

@ -1000,6 +1000,8 @@ QDebug &QDebug::resetFormat()
\since 6.0
\include qdebug-toString.qdocinc
\sa toBytes()
*/
/*! \internal */
@ -1013,6 +1015,26 @@ QString QDebug::toStringImpl(StreamTypeErased s, const void *obj)
return result;
}
/*!
\fn template <class T> QByteArray QDebug::toBytes(const T &object)
\since 6.9
This is equivalent to \c{QDebug::toString(object).toUtf8()}, but more efficient.
\sa toString()
*/
/*! \internal */
QByteArray QDebug::toBytesImpl(StreamTypeErased s, const void *obj)
{
QByteArray result;
{
QDebug d(&result);
s(d.nospace(), obj);
}
return result;
}
/*!
\fn template <class T> QDebug operator<<(QDebug debug, const QList<T> &list)
\relates QDebug

View File

@ -51,6 +51,9 @@ class QT6_ONLY(Q_CORE_EXPORT) QDebug : public QIODeviceBase
explicit Stream(QString *string)
: ts(string, WriteOnly)
{}
explicit Stream(QByteArray *ba)
: ts(ba, WriteOnly)
{}
explicit Stream(QtMsgType t)
: ts(&buffer, WriteOnly),
type(t),
@ -78,6 +81,7 @@ class QT6_ONLY(Q_CORE_EXPORT) QDebug : public QIODeviceBase
public:
explicit QDebug(QIODevice *device) : stream(new Stream(device)) {}
explicit QDebug(QString *string) : stream(new Stream(string)) {}
explicit QDebug(QByteArray *bytes) : stream(new Stream(bytes)) {}
explicit QDebug(QtMsgType t) : stream(new Stream(t)) {}
QDebug(const QDebug &o) : stream(o.stream) { ++stream->ref; }
QDebug(QDebug &&other) noexcept : stream{std::exchange(other.stream, nullptr)} {}
@ -232,12 +236,19 @@ private:
}
using StreamTypeErased = void(*)(QDebug&, const void*);
QT7_ONLY(Q_CORE_EXPORT) static QString toStringImpl(StreamTypeErased s, const void *obj);
QT7_ONLY(Q_CORE_EXPORT) static QByteArray toBytesImpl(StreamTypeErased s, const void *obj);
public:
template <typename T>
static QString toString(const T &object)
{
return toStringImpl(&streamTypeErased<T>, &object);
}
template <typename T>
static QByteArray toBytes(const T &object)
{
return toBytesImpl(&streamTypeErased<T>, &object);
}
};
Q_DECLARE_SHARED(QDebug)

View File

@ -55,7 +55,7 @@ inline typename std::enable_if<!QtPrivate::IsQEnumHelper<T>::Value && !std::is_e
char *result = nullptr;
#ifndef QT_NO_DEBUG_STREAM
if constexpr (QTypeTraits::has_ostream_operator_v<QDebug, T>) {
result = qstrdup(QDebug::toString(t).toUtf8().constData());
result = qstrdup(QDebug::toBytes(t).constData());
} else {
static_assert(!QMetaTypeId2<T>::IsBuiltIn,
"Built-in type must implement debug streaming operator "