summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorAhmad Samir <a.samirh78@gmail.com>2024-11-29 18:29:16 +0200
committerAhmad Samir <a.samirh78@gmail.com>2024-12-07 17:30:37 +0200
commitd89cef439f5c1a58aeff879a12d9a33292764b7f (patch)
tree89665b375ecbaa90c85be188240ba8f2dd479043 /src
parent84a5f50c7766c99f62b22bb4388137e0aa8dd13d (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.txt2
-rw-r--r--src/corelib/plugin/quuid.cpp28
-rw-r--r--src/corelib/plugin/quuid.h25
-rw-r--r--src/corelib/plugin/quuid_p.h61
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