From 8566c2db85a6f579a1a0432d0b7621633158e04c Mon Sep 17 00:00:00 2001 From: Thiago Macieira Date: Fri, 18 Nov 2022 12:57:09 -0800 Subject: [PATCH] QUuid: add support for 128-bit integers [ChangeLog][QtCore][QUuid] Added support for converting between QUuid and quint128, on platforms that offer 128-bit integer types (all 64-bit ones supported by Qt, except MSVC). Change-Id: Id8e48e8f498c4a029619fffd1728c9553e871df5 Reviewed-by: Volker Hilsheimer --- src/corelib/plugin/quuid.cpp | 32 +++++++++++++++- src/corelib/plugin/quuid.h | 37 ++++++++++++++++++- tests/auto/corelib/plugin/quuid/tst_quuid.cpp | 26 +++++++++++++ 3 files changed, 92 insertions(+), 3 deletions(-) diff --git a/src/corelib/plugin/quuid.cpp b/src/corelib/plugin/quuid.cpp index baf9a8bd3e..dcf2529ef1 100644 --- a/src/corelib/plugin/quuid.cpp +++ b/src/corelib/plugin/quuid.cpp @@ -307,14 +307,42 @@ static QUuid createFromName(const QUuid &ns, const QByteArray &baseData, QCrypto Creates a QUuid based on the integral \a id128 parameter and respecting the byte order \a order. - \sa fromBytes(), toBytes(), toRfc4122() + \sa fromBytes(), toBytes(), toRfc4122(), toUInt128() +*/ + +/*! + \fn QUuid::QUuid(quint128 uuid, QSysInfo::Endian order) noexcept + \since 6.6 + + Creates a QUuid based on the integral \a uuid parameter and respecting the + byte order \a order. + + \note This function is only present on platforms that offer a 128-bit + integer type. + + \sa toUInt128(), fromBytes(), toBytes(), toRfc4122() +*/ + +/*! + \fn quint128 QUuid::toUInt128(QSysInfo::Endian order) const noexcept + \since 6.6 + + Returns a 128-bit integer created from this QUuid on the byte order + specified by \a order. The binary content of this function is the same as + toRfc4122() if the order is QSysInfo::BigEndian. See that function for more + details. + + \note This function is only present on platforms that offer a 128-bit + integer type. + + \sa toRfc4122(), toBytes(), fromBytes(), QUuid() */ /*! \fn QUuid::Id128Bytes QUuid::toBytes(QSysInfo::Endian order) const noexcept \since 6.6 - Returns an 128-bit ID created from this QUuid on the byte order specified + Returns a 128-bit ID created from this QUuid on the byte order specified by \a order. The binary content of this function is the same as toRfc4122() if the order is QSysInfo::BigEndian. See that function for more details. diff --git a/src/corelib/plugin/quuid.h b/src/corelib/plugin/quuid.h index 9ba6564ef0..b977446d97 100644 --- a/src/corelib/plugin/quuid.h +++ b/src/corelib/plugin/quuid.h @@ -60,6 +60,9 @@ public: quint16 data16[8]; quint32 data32[4]; quint64 data64[2]; +#ifdef __SIZEOF_INT128__ + quint128 data128[1]; +#endif constexpr explicit operator QByteArrayView() const noexcept { @@ -72,7 +75,7 @@ public: 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, QSysInfo::Endian order = QSysInfo::BigEndian) noexcept; + explicit QUuid(Id128Bytes id128, QSysInfo::Endian order = QSysInfo::BigEndian) noexcept; explicit QUuid(QAnyStringView string) noexcept : QUuid{fromString(string)} {} @@ -97,6 +100,11 @@ public: bool isNull() const noexcept; +#ifdef __SIZEOF_INT128__ + constexpr QUuid(quint128 uuid, QSysInfo::Endian order = QSysInfo::BigEndian) noexcept; + constexpr quint128 toUInt128(QSysInfo::Endian order = QSysInfo::BigEndian) const noexcept; +#endif + constexpr bool operator==(const QUuid &orig) const noexcept { if (data1 != orig.data1 || data2 != orig.data2 || @@ -233,6 +241,33 @@ inline QUuid QUuid::fromBytes(const void *bytes, QSysInfo::Endian order) noexcep return QUuid(result, order); } +#ifdef __SIZEOF_INT128__ +constexpr inline QUuid::QUuid(quint128 uuid, QSysInfo::Endian order) noexcept +{ + if (order == QSysInfo::LittleEndian) + uuid = qbswap(uuid); + data1 = uint(uuid >> 96); + data2 = ushort(uuid >> 80); + data3 = ushort(uuid >> 64); + for (int i = 0; i < 8; ++i) + data4[i] = uchar(uuid >> (56 - i * 8)); +} + +constexpr inline quint128 QUuid::toUInt128(QSysInfo::Endian order) const noexcept +{ + quint128 result = {}; + result = data1; + result <<= 32; + result |= (data2 << 16) | uint(data3); + result <<= 64; + for (int i = 0; i < 8; ++i) + result |= quint64(data4[i]) << (56 - i * 8); + if (order == QSysInfo::LittleEndian) + return qbswap(result); + return result; +} +#endif + 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 e2f8762080..e759bdac85 100644 --- a/tests/auto/corelib/plugin/quuid/tst_quuid.cpp +++ b/tests/auto/corelib/plugin/quuid/tst_quuid.cpp @@ -26,6 +26,7 @@ private slots: void toRfc4122(); void fromRfc4122(); void id128(); + void uint128(); void createUuidV3OrV5(); void check_QDataStream(); void isNull(); @@ -245,6 +246,31 @@ void tst_QUuid::id128() QVERIFY(memcmp(uuidA.toBytes(QSysInfo::LittleEndian).data, leBytesA.data, sizeof(leBytesA)) == 0); } +void tst_QUuid::uint128() +{ +#ifdef __SIZEOF_INT128__ + constexpr quint128 u = quint128(Q_UINT64_C(0xfc69b59ecc344436)) << 64 + | Q_UINT64_C(0xa43cee95d128b8c5); + constexpr QUuid uuid(u); + static_assert(uuid.toUInt128() == u, "Round-trip through QUuid failed"); + + QCOMPARE(uuid, uuidA); + QCOMPARE(quint64(uuid.toUInt128() >> 64), quint64(u >> 64)); + QCOMPARE(quint64(uuid.toUInt128()), quint64(u)); + + quint128 le = qFromBigEndian(u); + QCOMPARE(quint64(uuid.toUInt128(QSysInfo::LittleEndian) >> 64), quint64(le >> 64)); + QCOMPARE(quint64(uuid.toUInt128(QSysInfo::LittleEndian)), quint64(le)); + QCOMPARE(QUuid(le, QSysInfo::LittleEndian), uuidA); + + QUuid::Id128Bytes bytes = { .data128 = { qToBigEndian(u) } }; + QUuid uuid2(bytes); + QCOMPARE(uuid2, uuid); +#else + QSKIP("This platform has no support for 128-bit integer"); +#endif +} + void tst_QUuid::createUuidV3OrV5() { //"www.widgets.com" is also from RFC4122