Long live QCryptographicHash::hashInto()!
Until now, QCryptographicHash had a big drawback over the underlying C APIs: at least one extra memory allocation: Either you created a QCryptographicHash object (allocates a Private), and enjoy noexcept addData() and resultView(), or you used the static hash() function (which creates a Private on the stack, so doesn't need to allocate one), but then we needed to return in an owning container. Enter QSpan and hashInto(), which allow the user to provide a buffer into which to write, and therefore can be completely noexcept and (apart from a missing optimization which, however, doesn't affect the API) deliver near C-API efficiency. We don't have QMutableByteArrayView, which would deal with the different types of equivalent char types for us, so we overload for QSpan<std::bytes>, QSpan<char> and QSpan<uchar>, which makes the overload set accept roughly what QByteArrayView would accept, too. Return by QByteArrayView because that has a richer API than QSpan, which lacks (on purpose) string-ish API. [ChangeLog][QtCore][QCryptographicHash] Added hashInto(). Task-number: QTBUG-125431 Change-Id: I80ecc7151d3418a36c4d5db6d22d0b82c869b19f Reviewed-by: Mårten Nordheim <marten.nordheim@qt.io>
This commit is contained in:
parent
39189190fe
commit
c70c81b371
@ -1153,13 +1153,42 @@ void QCryptographicHashPrivate::State::finalizeUnchecked(QCryptographicHash::Alg
|
||||
|
||||
\note In Qt versions prior to 6.3, this function took QByteArray,
|
||||
not QByteArrayView.
|
||||
|
||||
\sa hashInto()
|
||||
*/
|
||||
QByteArray QCryptographicHash::hash(QByteArrayView data, Algorithm method)
|
||||
{
|
||||
QByteArray ba(hashLengthInternal(method), Qt::Uninitialized);
|
||||
[[maybe_unused]] const auto r = hashInto(ba, data, method);
|
||||
Q_ASSERT(r.size() == ba.size());
|
||||
return ba;
|
||||
}
|
||||
|
||||
/*!
|
||||
\since 6.8
|
||||
\fn QCryptographicHash::hashInto(QSpan<char> buffer, QByteArrayView data, Algorithm method);
|
||||
\fn QCryptographicHash::hashInto(QSpan<uchar> buffer, QByteArrayView data, Algorithm method);
|
||||
\fn QCryptographicHash::hashInto(QSpan<std::byte> buffer, QByteArrayView data, Algorithm method);
|
||||
|
||||
Returns the hash of \a data using \a method, using \a buffer to store the result.
|
||||
|
||||
The return value will be a sub-span of \a buffer, unless \a buffer is of
|
||||
insufficient size, in which case a null QByteArrayView is returned.
|
||||
|
||||
\sa hash()
|
||||
*/
|
||||
QByteArrayView QCryptographicHash::hashInto(QSpan<std::byte> buffer, QByteArrayView data,
|
||||
Algorithm method) noexcept
|
||||
{
|
||||
QCryptographicHashPrivate hash(method);
|
||||
hash.addData(data);
|
||||
hash.finalizeUnchecked(); // no mutex needed: no-one but us has access to 'hash'
|
||||
return hash.resultView().toByteArray();
|
||||
auto result = hash.resultView();
|
||||
if (buffer.size() < result.size())
|
||||
return {}; // buffer too small
|
||||
// ### optimize: have the method directly write into `buffer`
|
||||
memcpy(buffer.data(), result.data(), result.size());
|
||||
return buffer.first(result.size());
|
||||
}
|
||||
|
||||
/*!
|
||||
|
@ -8,6 +8,7 @@
|
||||
|
||||
#include <QtCore/qbytearray.h>
|
||||
#include <QtCore/qobjectdefs.h>
|
||||
#include <QtCore/qspan.h>
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
|
||||
@ -91,6 +92,13 @@ public:
|
||||
static QByteArray hash(const QByteArray &data, Algorithm method);
|
||||
#endif
|
||||
static QByteArray hash(QByteArrayView data, Algorithm method);
|
||||
|
||||
static QByteArrayView hashInto(QSpan<char> buffer, QByteArrayView data, Algorithm method) noexcept
|
||||
{ return hashInto(as_writable_bytes(buffer), data, method); }
|
||||
static QByteArrayView hashInto(QSpan<uchar> buffer, QByteArrayView data, Algorithm method) noexcept
|
||||
{ return hashInto(as_writable_bytes(buffer), data, method); }
|
||||
static QByteArrayView hashInto(QSpan<std::byte> buffer, QByteArrayView data, Algorithm method) noexcept;
|
||||
|
||||
static int hashLength(Algorithm method);
|
||||
static bool supportsAlgorithm(Algorithm method);
|
||||
private:
|
||||
|
@ -209,6 +209,9 @@ void tst_QCryptographicHash::static_hash()
|
||||
const auto _algo = QCryptographicHash::Algorithm(algo);
|
||||
|
||||
QCOMPARE(QCryptographicHash::hash(first, _algo), hash_first);
|
||||
|
||||
std::byte buffer[1024];
|
||||
QCOMPARE(QCryptographicHash::hashInto(buffer, first, _algo), hash_first);
|
||||
}
|
||||
|
||||
|
||||
@ -511,6 +514,9 @@ void tst_QCryptographicHash::hashLength()
|
||||
expectedSize = 0;
|
||||
} else {
|
||||
expectedSize = QCryptographicHash::hash("test", algorithm).size();
|
||||
|
||||
std::byte buffer[1024];
|
||||
QCOMPARE(QCryptographicHash::hashInto(buffer, "foo", algorithm).size(), expectedSize);
|
||||
}
|
||||
QCOMPARE(QCryptographicHash::hashLength(algorithm), expectedSize);
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user