mirror of https://github.com/qt/qtbase.git
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>
This commit is contained in:
parent
c3c5d2cab0
commit
0f932b9a5d
|
@ -13,6 +13,9 @@
|
||||||
|
|
||||||
QT_BEGIN_NAMESPACE
|
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
|
// 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.
|
// digits; plus four dashes and a pair of enclosing brace: 16*2 + 4 + 2 = 38.
|
||||||
enum { MaxStringUuidLength = 38 };
|
enum { MaxStringUuidLength = 38 };
|
||||||
|
@ -286,6 +289,46 @@ static QUuid createFromName(const QUuid &ns, const QByteArray &baseData, QCrypto
|
||||||
cannot parse this back again as input.
|
cannot parse this back again as input.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\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)
|
\fn QUuid::QUuid(const GUID &guid)
|
||||||
|
|
||||||
|
@ -468,32 +511,13 @@ QUuid QUuid::createUuidV5(const QUuid &ns, const QByteArray &baseData)
|
||||||
|
|
||||||
\since 4.8
|
\since 4.8
|
||||||
|
|
||||||
\sa toRfc4122(), QUuid()
|
\sa toRfc4122(), QUuid(), fromBytes()
|
||||||
*/
|
*/
|
||||||
QUuid QUuid::fromRfc4122(QByteArrayView bytes) noexcept
|
QUuid QUuid::fromRfc4122(QByteArrayView bytes) noexcept
|
||||||
{
|
{
|
||||||
if (bytes.isEmpty() || bytes.size() != 16)
|
if (bytes.isEmpty() || bytes.size() != 16)
|
||||||
return QUuid();
|
return QUuid();
|
||||||
|
return fromBytes(bytes.data());
|
||||||
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]);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
|
@ -623,27 +647,16 @@ QByteArray QUuid::toByteArray(QUuid::StringFormat mode) const
|
||||||
|
|
||||||
\endtable
|
\endtable
|
||||||
|
|
||||||
|
The bytes in the byte array returned by this function contains the same
|
||||||
|
binary content as toBytes().
|
||||||
|
|
||||||
|
\sa toBytes()
|
||||||
\since 4.8
|
\since 4.8
|
||||||
*/
|
*/
|
||||||
QByteArray QUuid::toRfc4122() const
|
QByteArray QUuid::toRfc4122() const
|
||||||
{
|
{
|
||||||
// we know how many bytes a UUID has, I hope :)
|
Id128Bytes bytes = toBytes();
|
||||||
QByteArray bytes(16, Qt::Uninitialized);
|
return QByteArrayView(bytes).toByteArray();
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifndef QT_NO_DATASTREAM
|
#ifndef QT_NO_DATASTREAM
|
||||||
|
|
|
@ -4,6 +4,7 @@
|
||||||
#ifndef QUUID_H
|
#ifndef QUUID_H
|
||||||
#define QUUID_H
|
#define QUUID_H
|
||||||
|
|
||||||
|
#include <QtCore/qendian.h>
|
||||||
#include <QtCore/qstring.h>
|
#include <QtCore/qstring.h>
|
||||||
|
|
||||||
#if defined(Q_OS_WIN) || defined(Q_QDOC)
|
#if defined(Q_OS_WIN) || defined(Q_QDOC)
|
||||||
|
@ -26,7 +27,6 @@ Q_FORWARD_DECLARE_OBJC_CLASS(NSUUID);
|
||||||
|
|
||||||
QT_BEGIN_NAMESPACE
|
QT_BEGIN_NAMESPACE
|
||||||
|
|
||||||
|
|
||||||
class Q_CORE_EXPORT QUuid
|
class Q_CORE_EXPORT QUuid
|
||||||
{
|
{
|
||||||
QUuid(Qt::Initialization) {}
|
QUuid(Qt::Initialization) {}
|
||||||
|
@ -55,11 +55,24 @@ public:
|
||||||
Id128 = 3
|
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() noexcept {}
|
||||||
|
|
||||||
constexpr QUuid(uint l, ushort w1, ushort w2, uchar b1, uchar b2, uchar b3,
|
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
|
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} {}
|
: data1(l), data2(w1), data3(w2), data4{b1, b2, b3, b4, b5, b6, b7, b8} {}
|
||||||
|
QUuid(Id128Bytes id128) noexcept;
|
||||||
|
|
||||||
explicit QUuid(QAnyStringView string) noexcept
|
explicit QUuid(QAnyStringView string) noexcept
|
||||||
: QUuid{fromString(string)} {}
|
: QUuid{fromString(string)} {}
|
||||||
|
@ -73,11 +86,15 @@ public:
|
||||||
#endif
|
#endif
|
||||||
QString toString(StringFormat mode = WithBraces) const;
|
QString toString(StringFormat mode = WithBraces) const;
|
||||||
QByteArray toByteArray(StringFormat mode = WithBraces) const;
|
QByteArray toByteArray(StringFormat mode = WithBraces) const;
|
||||||
|
Id128Bytes toBytes() const noexcept;
|
||||||
QByteArray toRfc4122() const;
|
QByteArray toRfc4122() const;
|
||||||
|
|
||||||
|
static QUuid fromBytes(const void *bytes) noexcept;
|
||||||
#if QT_CORE_REMOVED_SINCE(6, 3)
|
#if QT_CORE_REMOVED_SINCE(6, 3)
|
||||||
static QUuid fromRfc4122(const QByteArray &);
|
static QUuid fromRfc4122(const QByteArray &);
|
||||||
#endif
|
#endif
|
||||||
static QUuid fromRfc4122(QByteArrayView) noexcept;
|
static QUuid fromRfc4122(QByteArrayView) noexcept;
|
||||||
|
|
||||||
bool isNull() const noexcept;
|
bool isNull() const noexcept;
|
||||||
|
|
||||||
constexpr bool operator==(const QUuid &orig) 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;
|
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
|
inline bool operator<=(const QUuid &lhs, const QUuid &rhs) noexcept
|
||||||
{ return !(rhs < lhs); }
|
{ return !(rhs < lhs); }
|
||||||
inline bool operator>=(const QUuid &lhs, const QUuid &rhs) noexcept
|
inline bool operator>=(const QUuid &lhs, const QUuid &rhs) noexcept
|
||||||
|
|
|
@ -25,6 +25,7 @@ private slots:
|
||||||
void fromByteArray();
|
void fromByteArray();
|
||||||
void toRfc4122();
|
void toRfc4122();
|
||||||
void fromRfc4122();
|
void fromRfc4122();
|
||||||
|
void id128();
|
||||||
void createUuidV3OrV5();
|
void createUuidV3OrV5();
|
||||||
void check_QDataStream();
|
void check_QDataStream();
|
||||||
void isNull();
|
void isNull();
|
||||||
|
@ -98,7 +99,7 @@ void tst_QUuid::fromChar()
|
||||||
QCOMPARE(QUuid(), QUuid("fc69b59e-cc34-"));
|
QCOMPARE(QUuid(), QUuid("fc69b59e-cc34-"));
|
||||||
QCOMPARE(QUuid(), QUuid("fc69b59e-cc34"));
|
QCOMPARE(QUuid(), QUuid("fc69b59e-cc34"));
|
||||||
QCOMPARE(QUuid(), QUuid("cc34"));
|
QCOMPARE(QUuid(), QUuid("cc34"));
|
||||||
QCOMPARE(QUuid(), QUuid(NULL));
|
QCOMPARE(QUuid(), QUuid(nullptr));
|
||||||
|
|
||||||
QCOMPARE(uuidB, QUuid(QString("{1ab6e93a-b1cb-4a87-ba47-ec7e99039a7b}")));
|
QCOMPARE(uuidB, QUuid(QString("{1ab6e93a-b1cb-4a87-ba47-ec7e99039a7b}")));
|
||||||
}
|
}
|
||||||
|
@ -217,6 +218,27 @@ void tst_QUuid::fromRfc4122()
|
||||||
QCOMPARE(uuidB, QUuid::fromRfc4122(QByteArray::fromHex("1ab6e93ab1cb4a87ba47ec7e99039a7b")));
|
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()
|
void tst_QUuid::createUuidV3OrV5()
|
||||||
{
|
{
|
||||||
//"www.widgets.com" is also from RFC4122
|
//"www.widgets.com" is also from RFC4122
|
||||||
|
|
Loading…
Reference in New Issue