diff options
author | Thiago Macieira <thiago.macieira@intel.com> | 2022-11-17 20:37:15 -0800 |
---|---|---|
committer | Ivan Solovev <ivan.solovev@qt.io> | 2022-12-16 19:29:09 +0100 |
commit | 0f932b9a5de21060fb9763eed24298ae929e9821 (patch) | |
tree | 9133d101c456ef8af891de99b960c1d649eff260 | |
parent | c3c5d2cab07ffed1ddfb7978870c05917d89fa39 (diff) |
QUuid: add a trivial structure to support exactly 128 bits
This is inspired by QBluetoothUuid's quint128, but with a better
name. It also matches systemd's sd_id128.
Change-Id: Id8e48e8f498c4a029619fffd172893dc1545adda
Reviewed-by: Ivan Solovev <ivan.solovev@qt.io>
-rw-r--r-- | src/corelib/plugin/quuid.cpp | 89 | ||||
-rw-r--r-- | src/corelib/plugin/quuid.h | 44 | ||||
-rw-r--r-- | tests/auto/corelib/plugin/quuid/tst_quuid.cpp | 24 |
3 files changed, 117 insertions, 40 deletions
diff --git a/src/corelib/plugin/quuid.cpp b/src/corelib/plugin/quuid.cpp index 8613f96c21..a980c9a5ba 100644 --- a/src/corelib/plugin/quuid.cpp +++ b/src/corelib/plugin/quuid.cpp @@ -13,6 +13,9 @@ QT_BEGIN_NAMESPACE +// ensure QList of this is efficient +static_assert(QTypeInfo<QUuid::Id128Bytes>::isRelocatable); + // 16 bytes (a uint, two shorts and a uchar[8]), each represented by two hex // digits; plus four dashes and a pair of enclosing brace: 16*2 + 4 + 2 = 38. enum { MaxStringUuidLength = 38 }; @@ -287,6 +290,46 @@ static QUuid createFromName(const QUuid &ns, const QByteArray &baseData, QCrypto */ /*! + \class QUuid::Id128Bytes + \inmodule QtCore + \since 6.6 + + This trivial structure is 128 bits (16 bytes) in size and holds the binary + representation of a UUID. Applications can \c{memcpy()} its contents to and + from many other libraries' UUID or GUID structures that take 128-bit + values. +*/ + +/*! + \fn QUuid::QUuid(Id128Bytes id128) noexcept + \since 6.6 + + Creates a QUuid based on the integral \a id128 parameter. + + \sa fromBytes(), toBytes(), toRfc4122() +*/ + +/*! + \fn QUuid::Id128Bytes QUuid::toBytes() const noexcept + \since 6.6 + + Returns an 128-bit ID created from this QUuid. The binary content of this + function is the same as toRfc4122(). See that function for more details. + + \sa toRfc4122(), fromBytes(), QUuid() +*/ + +/*! + \fn QUuid QUuid::fromBytes(const void *bytes) noexcept + \since 6.6 + + Reads 128 bits (16 bytes) from \a bytes and returns the QUuid corresponding + to those bytes. This function does the same as fromRfc4122(). + + \sa fromRfc4122() +*/ + +/*! \fn QUuid::QUuid(const GUID &guid) Casts a Windows \a guid to a Qt QUuid. @@ -468,32 +511,13 @@ QUuid QUuid::createUuidV5(const QUuid &ns, const QByteArray &baseData) \since 4.8 - \sa toRfc4122(), QUuid() + \sa toRfc4122(), QUuid(), fromBytes() */ QUuid QUuid::fromRfc4122(QByteArrayView bytes) noexcept { if (bytes.isEmpty() || bytes.size() != 16) return QUuid(); - - uint d1; - ushort d2, d3; - uchar d4[8]; - - const uchar *data = reinterpret_cast<const uchar *>(bytes.data()); - - d1 = qFromBigEndian<quint32>(data); - data += sizeof(quint32); - d2 = qFromBigEndian<quint16>(data); - data += sizeof(quint16); - d3 = qFromBigEndian<quint16>(data); - data += sizeof(quint16); - - for (int i = 0; i < 8; ++i) { - d4[i] = *(data); - data++; - } - - return QUuid(d1, d2, d3, d4[0], d4[1], d4[2], d4[3], d4[4], d4[5], d4[6], d4[7]); + return fromBytes(bytes.data()); } /*! @@ -623,27 +647,16 @@ QByteArray QUuid::toByteArray(QUuid::StringFormat mode) const \endtable + The bytes in the byte array returned by this function contains the same + binary content as toBytes(). + + \sa toBytes() \since 4.8 */ QByteArray QUuid::toRfc4122() const { - // we know how many bytes a UUID has, I hope :) - QByteArray bytes(16, Qt::Uninitialized); - uchar *data = reinterpret_cast<uchar *>(bytes.data()); - - qToBigEndian(data1, data); - data += sizeof(quint32); - qToBigEndian(data2, data); - data += sizeof(quint16); - qToBigEndian(data3, data); - data += sizeof(quint16); - - for (int i = 0; i < 8; ++i) { - *(data) = data4[i]; - data++; - } - - return bytes; + Id128Bytes bytes = toBytes(); + return QByteArrayView(bytes).toByteArray(); } #ifndef QT_NO_DATASTREAM diff --git a/src/corelib/plugin/quuid.h b/src/corelib/plugin/quuid.h index bcd78d85e7..21833efe03 100644 --- a/src/corelib/plugin/quuid.h +++ b/src/corelib/plugin/quuid.h @@ -4,6 +4,7 @@ #ifndef QUUID_H #define QUUID_H +#include <QtCore/qendian.h> #include <QtCore/qstring.h> #if defined(Q_OS_WIN) || defined(Q_QDOC) @@ -26,7 +27,6 @@ Q_FORWARD_DECLARE_OBJC_CLASS(NSUUID); QT_BEGIN_NAMESPACE - class Q_CORE_EXPORT QUuid { QUuid(Qt::Initialization) {} @@ -55,11 +55,24 @@ public: Id128 = 3 }; + union Id128Bytes { + quint8 data[16]; + quint16 data16[8]; + quint32 data32[4]; + quint64 data64[2]; + + constexpr explicit operator QByteArrayView() const noexcept + { + return QByteArrayView(data, sizeof(data)); + } + }; + constexpr QUuid() noexcept {} constexpr QUuid(uint l, ushort w1, ushort w2, uchar b1, uchar b2, uchar b3, uchar b4, uchar b5, uchar b6, uchar b7, uchar b8) noexcept : data1(l), data2(w1), data3(w2), data4{b1, b2, b3, b4, b5, b6, b7, b8} {} + QUuid(Id128Bytes id128) noexcept; explicit QUuid(QAnyStringView string) noexcept : QUuid{fromString(string)} {} @@ -73,11 +86,15 @@ public: #endif QString toString(StringFormat mode = WithBraces) const; QByteArray toByteArray(StringFormat mode = WithBraces) const; + Id128Bytes toBytes() const noexcept; QByteArray toRfc4122() const; + + static QUuid fromBytes(const void *bytes) noexcept; #if QT_CORE_REMOVED_SINCE(6, 3) static QUuid fromRfc4122(const QByteArray &); #endif static QUuid fromRfc4122(QByteArrayView) noexcept; + bool isNull() const noexcept; constexpr bool operator==(const QUuid &orig) const noexcept @@ -177,6 +194,31 @@ Q_CORE_EXPORT QDebug operator<<(QDebug, const QUuid &); Q_CORE_EXPORT size_t qHash(const QUuid &uuid, size_t seed = 0) noexcept; +inline QUuid::QUuid(Id128Bytes uuid) noexcept +{ + data1 = qFromBigEndian<quint32>(&uuid.data[0]); + data2 = qFromBigEndian<quint16>(&uuid.data[4]); + data3 = qFromBigEndian<quint16>(&uuid.data[6]); + memcpy(data4, &uuid.data[8], sizeof(data4)); +} + +inline QUuid::Id128Bytes QUuid::toBytes() const noexcept +{ + Id128Bytes result = {}; + qToBigEndian(data1, &result.data[0]); + qToBigEndian(data2, &result.data[4]); + qToBigEndian(data3, &result.data[6]); + memcpy(&result.data[8], data4, sizeof(data4)); + return result; +} + +inline QUuid QUuid::fromBytes(const void *bytes) noexcept +{ + Id128Bytes result = {}; + memcpy(result.data, bytes, sizeof(result)); + return QUuid(result); +} + inline bool operator<=(const QUuid &lhs, const QUuid &rhs) noexcept { return !(rhs < lhs); } inline bool operator>=(const QUuid &lhs, const QUuid &rhs) noexcept diff --git a/tests/auto/corelib/plugin/quuid/tst_quuid.cpp b/tests/auto/corelib/plugin/quuid/tst_quuid.cpp index 6b1e6003b8..b2eb4c420e 100644 --- a/tests/auto/corelib/plugin/quuid/tst_quuid.cpp +++ b/tests/auto/corelib/plugin/quuid/tst_quuid.cpp @@ -25,6 +25,7 @@ private slots: void fromByteArray(); void toRfc4122(); void fromRfc4122(); + void id128(); void createUuidV3OrV5(); void check_QDataStream(); void isNull(); @@ -98,7 +99,7 @@ void tst_QUuid::fromChar() QCOMPARE(QUuid(), QUuid("fc69b59e-cc34-")); QCOMPARE(QUuid(), QUuid("fc69b59e-cc34")); QCOMPARE(QUuid(), QUuid("cc34")); - QCOMPARE(QUuid(), QUuid(NULL)); + QCOMPARE(QUuid(), QUuid(nullptr)); QCOMPARE(uuidB, QUuid(QString("{1ab6e93a-b1cb-4a87-ba47-ec7e99039a7b}"))); } @@ -217,6 +218,27 @@ void tst_QUuid::fromRfc4122() QCOMPARE(uuidB, QUuid::fromRfc4122(QByteArray::fromHex("1ab6e93ab1cb4a87ba47ec7e99039a7b"))); } +void tst_QUuid::id128() +{ + constexpr QUuid::Id128Bytes bytesA = { { + 0xfc, 0x69, 0xb5, 0x9e, + 0xcc, 0x34, + 0x44, 0x36, + 0xa4, 0x3c, 0xee, 0x95, 0xd1, 0x28, 0xb8, 0xc5, + } }; + constexpr QUuid::Id128Bytes bytesB = { { + 0x1a, 0xb6, 0xe9, 0x3a, + 0xb1, 0xcb, + 0x4a, 0x87, + 0xba, 0x47, 0xec, 0x7e, 0x99, 0x03, 0x9a, 0x7b, + } }; + + QCOMPARE(QUuid(bytesA), uuidA); + QCOMPARE(QUuid(bytesB), uuidB); + QVERIFY(memcmp(uuidA.toBytes().data, bytesA.data, sizeof(QUuid::Id128Bytes)) == 0); + QVERIFY(memcmp(uuidB.toBytes().data, bytesB.data, sizeof(QUuid::Id128Bytes)) == 0); +} + void tst_QUuid::createUuidV3OrV5() { //"www.widgets.com" is also from RFC4122 |