QUuid: make more methods constexpr

Use QT6_{DECL,CALL}_NEW_OVERLOAD mechanism to provide new constexpr
overloads for isNull(), variant(), and version(). Move the old
methods into removed_api.cpp

Use this as an opportunity to optimize the implementaiton of the
methods. Also add compile-time checks to the tests.

It turns out that QNX compiler fails to compile the default
QUuid::isNull() implementation in constexpr context, so rewrite
it using a loop.

Change-Id: Ia23c81194ea27b369f00ce73b016695600187e46
Reviewed-by: Marc Mutz <marc.mutz@qt.io>
Reviewed-by: Thiago Macieira <thiago.macieira@intel.com>
This commit is contained in:
Ivan Solovev 2024-06-27 12:24:30 +02:00
parent 637fcc69c8
commit 81d31d2760
4 changed files with 75 additions and 28 deletions

View File

@ -1240,6 +1240,22 @@ QUuid QUuid::createUuidV5(const QUuid &ns, const QByteArray &baseData) noexcept
#if QT_CORE_REMOVED_SINCE(6, 9)
#include "quuid.h"
bool QUuid::isNull() const noexcept
{
return isNull(QT6_CALL_NEW_OVERLOAD);
}
QUuid::Variant QUuid::variant() const noexcept
{
return variant(QT6_CALL_NEW_OVERLOAD);
}
QUuid::Version QUuid::version() const noexcept
{
return version(QT6_CALL_NEW_OVERLOAD);
}
// #include "qotherheader.h"
// // implement removed functions from qotherheader.h

View File

@ -823,15 +823,11 @@ QDataStream &operator>>(QDataStream &s, QUuid &id)
#endif // QT_NO_DATASTREAM
/*!
\fn bool QUuid::isNull() const
Returns \c true if this is the null UUID
{00000000-0000-0000-0000-000000000000}; otherwise returns \c false.
*/
bool QUuid::isNull() const noexcept
{
return data4[0] == 0 && data4[1] == 0 && data4[2] == 0 && data4[3] == 0 &&
data4[4] == 0 && data4[5] == 0 && data4[6] == 0 && data4[7] == 0 &&
data1 == 0 && data2 == 0 && data3 == 0;
}
/*!
\enum QUuid::Variant
@ -875,17 +871,6 @@ bool QUuid::isNull() const noexcept
\sa version()
*/
QUuid::Variant QUuid::variant() const noexcept
{
if (isNull())
return VarUnknown;
// Check the 3 MSB of data4[0]
if ((data4[0] & 0x80) == 0x00) return NCS;
else if ((data4[0] & 0xC0) == 0x80) return DCE;
else if ((data4[0] & 0xE0) == 0xC0) return Microsoft;
else if ((data4[0] & 0xE0) == 0xE0) return Reserved;
return VarUnknown;
}
/*!
\fn QUuid::Version QUuid::version() const
@ -896,17 +881,6 @@ QUuid::Variant QUuid::variant() const noexcept
\sa variant()
*/
QUuid::Version QUuid::version() const noexcept
{
// Check the 4 MSB of data3
Version ver = (Version)(data3>>12);
if (isNull()
|| (variant() != DCE)
|| ver < Time
|| ver > Sha1)
return VerUnknown;
return ver;
}
/*!
\fn bool QUuid::operator<(const QUuid &lhs, const QUuid &rhs)

View File

@ -117,7 +117,25 @@ QT_WARNING_POP
#endif
static QUuid fromRfc4122(QByteArrayView) noexcept;
#if QT_CORE_REMOVED_SINCE(6, 9)
bool isNull() const noexcept;
#endif
constexpr bool isNull(QT6_DECL_NEW_OVERLOAD) const noexcept
{
#if defined(__cpp_lib_bit_cast) && defined(QT_SUPPORTS_INT128)
return std::bit_cast<quint128>(*this) == 0;
#else
// QNX fails to compile
// data4[0] == 0 && data4[1] == 0 && ...
// in constexpr context, so rewrite it using a loop. This way we have
// only single data4[i] != 0 check at each iteration
for (size_t i = 0; i < 8; ++i) {
if (data4[i] != 0)
return false;
}
return data1 == 0 && data2 == 0 && data3 == 0;
#endif
}
#ifdef QT_SUPPORTS_INT128
static constexpr QUuid fromUInt128(quint128 uuid, QSysInfo::Endian order = QSysInfo::BigEndian) noexcept;
@ -253,8 +271,29 @@ public:
return QUuid::createUuidV5(ns, qToByteArrayViewIgnoringNull(baseData.toUtf8()));
}
#if QT_CORE_REMOVED_SINCE(6, 9)
QUuid::Variant variant() const noexcept;
QUuid::Version version() const noexcept;
#endif
constexpr Variant variant(QT6_DECL_NEW_OVERLOAD) const noexcept
{
// Check the 3 MSB of data4[0]
const quint8 var = data4[0] & 0xE0;
if (var < 0x80)
return isNull(QT6_CALL_NEW_OVERLOAD) ? VarUnknown : NCS;
if (var < 0xC0)
return DCE;
return Variant(var >> 5); // Microsoft or Reserved
}
constexpr Version version(QT6_DECL_NEW_OVERLOAD) const noexcept
{
// 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)
return ver;
return VerUnknown;
}
#if defined(Q_OS_DARWIN) || defined(Q_QDOC)
static QUuid fromCFUUID(CFUUIDRef uuid);

View File

@ -349,6 +349,12 @@ void tst_QUuid::check_QDataStream()
void tst_QUuid::isNull()
{
constexpr QUuid null;
static_assert(null.isNull());
constexpr QUuid nonNull{1, 2, 3, 4, 0, 1, 2, 3, 4, 5, 6};
static_assert(!nonNull.isNull());
QVERIFY( !uuidA.isNull() );
QUuid should_be_null_uuid;
@ -561,6 +567,12 @@ void tst_QUuid::variants_data()
QTest::newRow("uuidA") << uuidA << QUuid::DCE;
QTest::newRow("uuidB") << uuidB << QUuid::DCE;
QTest::newRow("NCS") << QUuid("{3a2f883c-4000-000d-0000-00fb40000000}") << QUuid::NCS;
// compile-time checks
constexpr QUuid defaultConstructed;
static_assert(defaultConstructed.variant() == QUuid::Variant::VarUnknown);
constexpr QUuid minDCE = make_minimal(QUuid::Variant::DCE);
static_assert(minDCE.variant() == QUuid::Variant::DCE);
}
void tst_QUuid::variants()
@ -607,6 +619,12 @@ void tst_QUuid::versions_data()
<< QUuid::VerUnknown;
QTest::newRow("uuidA") << uuidA << QUuid::Random;
QTest::newRow("uuidB") << uuidB << QUuid::Random;
// compile-time checks
constexpr QUuid defaultConstructed;
static_assert(defaultConstructed.version() == QUuid::Version::VerUnknown);
constexpr QUuid timeVer = {0, 0, 0x1000, 0b1000'0000, 0, 0, 0, 0, 0, 0, 0};
static_assert(timeVer.version() == QUuid::Version::Time);
}
void tst_QUuid::versions()