diff options
| author | Ahmad Samir <a.samirh78@gmail.com> | 2024-11-29 18:29:16 +0200 |
|---|---|---|
| committer | Ahmad Samir <a.samirh78@gmail.com> | 2024-12-07 17:30:37 +0200 |
| commit | d89cef439f5c1a58aeff879a12d9a33292764b7f (patch) | |
| tree | 89665b375ecbaa90c85be188240ba8f2dd479043 /src | |
| parent | 84a5f50c7766c99f62b22bb4388137e0aa8dd13d (diff) | |
QUuid: add support for creating UUID v7
Thanks to Thiago for the more efficient way of using 12 bits of
the sub-milliseconds part of the timestamp. Previously I used the method
described in the RFC (value of type double multiplied by 4096).
Add a private helper to check the version since now there is a gap in
the Version enum values (UUID v6 isn't supported).
Drive-by, document Version::Sha1 enumerator.
[ChangeLog][QtCore][QUuid] Added support for creating UUID v7 as
described in
https://datatracker.ietf.org/doc/html/rfc9562#name-uuid-version-7
Fixes: QTBUG-130672
Change-Id: Idfea9fbb12a7f28e25b27b56a3b402799afb4864
Reviewed-by: Thiago Macieira <thiago.macieira@intel.com>
Diffstat (limited to 'src')
| -rw-r--r-- | src/corelib/CMakeLists.txt | 2 | ||||
| -rw-r--r-- | src/corelib/plugin/quuid.cpp | 28 | ||||
| -rw-r--r-- | src/corelib/plugin/quuid.h | 25 | ||||
| -rw-r--r-- | src/corelib/plugin/quuid_p.h | 61 |
4 files changed, 110 insertions, 6 deletions
diff --git a/src/corelib/CMakeLists.txt b/src/corelib/CMakeLists.txt index 063bb859b48..7adbc7014fa 100644 --- a/src/corelib/CMakeLists.txt +++ b/src/corelib/CMakeLists.txt @@ -194,7 +194,7 @@ qt_internal_add_module(Core plugin/qfactoryloader.cpp plugin/qfactoryloader_p.h plugin/qplugin.h plugin/qplugin_p.h plugin/qpluginloader.cpp plugin/qpluginloader.h - plugin/quuid.cpp plugin/quuid.h + plugin/quuid.cpp plugin/quuid.h plugin/quuid_p.h serialization/qcborarray.h serialization/qcborcommon.cpp serialization/qcborcommon.h serialization/qcborcommon_p.h serialization/qcbordiagnostic.cpp diff --git a/src/corelib/plugin/quuid.cpp b/src/corelib/plugin/quuid.cpp index 0b1615c6499..e0d621dec80 100644 --- a/src/corelib/plugin/quuid.cpp +++ b/src/corelib/plugin/quuid.cpp @@ -3,6 +3,7 @@ // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only #include "quuid.h" +#include "quuid_p.h" #include "qcryptographichash.h" #include "qdatastream.h" @@ -543,7 +544,7 @@ QUuid QUuid::fromString(QAnyStringView text) noexcept \note In Qt versions prior to 6.8, this function took QByteArray, not QByteArrayView. - \sa variant(), version(), createUuidV5() + \sa variant(), version(), createUuidV5(), createUuidV7() */ /*! @@ -553,7 +554,7 @@ QUuid QUuid::fromString(QAnyStringView text) noexcept This function returns a new UUID with variant QUuid::DCE and version QUuid::Md5. \a ns is the namespace and \a baseData is the basic data as described by RFC 4122. - \sa variant(), version(), createUuidV5() + \sa variant(), version(), createUuidV5(), createUuidV7() */ /*! @@ -591,6 +592,25 @@ QUuid QUuid::createUuidV5(QUuid ns, QByteArrayView baseData) noexcept } /*! + \since 6.9 + + This function returns a new UUID with variant QUuid::DCE and version + QUuid::UnixEpoch. + + It uses a time-ordered value field derived from the number of milliseconds + since the UNIX Epoch as described by + \l {https://datatracker.ietf.org/doc/html/rfc9562#name-uuid-version-7}{RFC9562}. + + \sa variant(), version(), createUuidV3(), createUuidV5() +*/ +#ifndef QT_BOOTSTRAPPED +QUuid QUuid::createUuidV7() +{ + return createUuidV7_internal(std::chrono::system_clock::now()); +} +#endif // !defined(QT_BOOTSTRAPPED) + +/*! Creates a QUuid object from the binary representation of the UUID, as specified by RFC 4122 section 4.1.2. See toRfc4122() for a further explanation of the order of \a bytes required. @@ -861,7 +881,9 @@ QDataStream &operator>>(QDataStream &s, QUuid &id) \value Name Name-based, by using values from a name for all sections \value Md5 Alias for Name \value Random Random-based, by using random numbers for all sections - \value Sha1 + \value Sha1 Name-based version that uses SHA-1 hashing + \value UnixEpoch Time-based UUID using the number of milliseconds since + the UNIX epoch */ /*! diff --git a/src/corelib/plugin/quuid.h b/src/corelib/plugin/quuid.h index 34a14cbc641..e19a4b7c52e 100644 --- a/src/corelib/plugin/quuid.h +++ b/src/corelib/plugin/quuid.h @@ -48,7 +48,8 @@ public: Md5 = 3, // 0 0 1 1 Name = Md5, Random = 4, // 0 1 0 0 - Sha1 = 5 // 0 1 0 1 + Sha1 = 5, // 0 1 0 1 + UnixEpoch = 7, // 0 1 1 1 }; enum StringFormat { @@ -277,6 +278,26 @@ public: return QUuid::createUuidV5(ns, qToByteArrayViewIgnoringNull(baseData.toUtf8())); } + static QUuid createUuidV7(); + +private: + static constexpr bool isKnownVersion(Version v) noexcept + { + switch (v) { + case VerUnknown: + return false; + case Time: + case EmbeddedPOSIX: + case Md5: + case Random: + case Sha1: + case UnixEpoch: + return true; + } + return false; + } + +public: #if QT_CORE_REMOVED_SINCE(6, 9) QUuid::Variant variant() const noexcept; QUuid::Version version() const noexcept; @@ -296,7 +317,7 @@ public: // Check the 4 MSB of data3 const Version ver = Version(data3 >> 12); // Check that variant() == DCE and version is in a valid range - if (ver >= Time && ver <= Sha1 && (data4[0] & 0xC0) == 0x80) + if (isKnownVersion(ver) && (data4[0] & 0xC0) == 0x80) return ver; return VerUnknown; } diff --git a/src/corelib/plugin/quuid_p.h b/src/corelib/plugin/quuid_p.h new file mode 100644 index 00000000000..871fc57195d --- /dev/null +++ b/src/corelib/plugin/quuid_p.h @@ -0,0 +1,61 @@ +// Copyright (C) 2020 The Qt Company Ltd. +// Copyright (C) 2021 Intel Corporation. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only + +#ifndef QUUID_P_H +#define QUUID_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists for the convenience +// of the QLibrary class. This header file may change from +// version to version without notice, or even be removed. +// +// We mean it. +// + +#include "quuid.h" + +#include <QtCore/qrandom.h> + +#include <chrono> + +QT_BEGIN_NAMESPACE + +#ifndef QT_BOOTSTRAPPED +static inline QUuid createUuidV7_internal( + std::chrono::time_point<std::chrono::system_clock, std::chrono::nanoseconds> tp) +{ + QUuid result; + + using namespace std::chrono; + const nanoseconds nsecSinceEpoch = tp.time_since_epoch(); + const auto msecSinceEpoch = floor<milliseconds>(nsecSinceEpoch); + const quint64 frac = (nsecSinceEpoch - msecSinceEpoch).count(); + // Lower 48 bits of the timestamp + const quint64 msecs = quint64(msecSinceEpoch.count()) & 0xffffffffffff; + result.data1 = uint(msecs >> 16); + result.data2 = ushort(msecs); + // rand_a: use a 12-bit sub-millisecond timestamp for additional monotonicity + // https://datatracker.ietf.org/doc/html/rfc9562#monotonicity_counters (Method 3) + + // "frac" is a number between 0 and 999,999, so the lowest 20 bits + // should be roughly random. Use the high 12 of those for additional + // monotonicity. + result.data3 = frac >> 8; + result.data3 &= 0x0FFF; + result.data3 |= ushort(7) << 12; + + // rand_b: 62 bits of random data (64 - 2 bits for the variant) + const quint64 random = QRandomGenerator::system()->generate64(); + memcpy(result.data4, &random, sizeof(quint64)); + result.data4[0] = (result.data4[0] & 0x3F) | 0x80; // UV_DCE + return result; +} +#endif + +QT_END_NAMESPACE + +#endif // QUUID_P_H |
