summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/corelib/kernel/qmetaobjectbuilder.cpp148
-rw-r--r--src/corelib/kernel/qmetaobjectbuilder_p.h7
-rw-r--r--tests/auto/corelib/kernel/qmetaobjectbuilder/tst_qmetaobjectbuilder.cpp72
3 files changed, 189 insertions, 38 deletions
diff --git a/src/corelib/kernel/qmetaobjectbuilder.cpp b/src/corelib/kernel/qmetaobjectbuilder.cpp
index e511f14686c..e98e113413a 100644
--- a/src/corelib/kernel/qmetaobjectbuilder.cpp
+++ b/src/corelib/kernel/qmetaobjectbuilder.cpp
@@ -153,17 +153,24 @@ class QMetaEnumBuilderPrivate
{
public:
QMetaEnumBuilderPrivate(const QByteArray &_name)
- : name(_name), enumName(_name), isFlag(false), isScoped(false)
+ : name(_name), enumName(_name)
{
}
QByteArray name;
QByteArray enumName;
QMetaType metaType;
- bool isFlag;
- bool isScoped;
QList<QByteArray> keys;
- QList<int> values;
+ QList<quint64> values;
+ QFlags<EnumFlags> flags = {};
+
+ int addKey(const QByteArray &name, quint64 value)
+ {
+ int index = keys.size();
+ keys += name;
+ values += value;
+ return index;
+ }
};
Q_DECLARE_TYPEINFO(QMetaEnumBuilderPrivate, Q_RELOCATABLE_TYPE);
@@ -592,7 +599,9 @@ QMetaEnumBuilder QMetaObjectBuilder::addEnumerator(const QMetaEnum &prototype)
en.setIsScoped(prototype.isScoped());
int count = prototype.keyCount();
for (int index = 0; index < count; ++index)
- en.addKey(prototype.key(index), prototype.value(index));
+ en.addKey(prototype.key(index), prototype.value64(index).value_or(0));
+ // reset the is64Bit() flag if necessary
+ en.setIs64Bit(prototype.is64Bit());
return en;
}
@@ -1206,8 +1215,11 @@ static int buildMetaObject(QMetaObjectBuilderPrivate *d, char *buf,
// Allocate space for the enumerator key names and values.
enumIndex = dataIndex;
- for (const auto &enumerator : d->enumerators)
+ for (const auto &enumerator : d->enumerators) {
dataIndex += 2 * enumerator.keys.size();
+ if (enumerator.flags & EnumIs64Bit)
+ dataIndex += enumerator.keys.size();
+ }
// Zero terminator at the end of the data offset table.
++dataIndex;
@@ -1334,26 +1346,30 @@ static int buildMetaObject(QMetaObjectBuilderPrivate *d, char *buf,
for (const auto &enumerator : d->enumerators) {
[[maybe_unused]] int name = strings.enter(enumerator.name);
[[maybe_unused]] int enumName = strings.enter(enumerator.enumName);
- [[maybe_unused]] int isFlag = enumerator.isFlag ? EnumIsFlag : EnumFlags{};
- [[maybe_unused]] int isScoped = enumerator.isScoped ? EnumIsScoped : EnumFlags{};
int count = enumerator.keys.size();
- int enumOffset = enumIndex;
if constexpr (mode == Construct) {
data[dataIndex] = name;
data[dataIndex + 1] = enumName;
- data[dataIndex + 2] = isFlag | isScoped;
+ data[dataIndex + 2] = enumerator.flags.toInt();
data[dataIndex + 3] = count;
- data[dataIndex + 4] = enumOffset;
+ data[dataIndex + 4] = enumIndex;
}
for (int key = 0; key < count; ++key) {
[[maybe_unused]] int keyIndex = strings.enter(enumerator.keys[key]);
if constexpr (mode == Construct) {
- data[enumOffset++] = keyIndex;
- data[enumOffset++] = enumerator.values[key];
+ data[enumIndex + 0] = keyIndex;
+ data[enumIndex + 1] = uint(enumerator.values[key]);
+ }
+ enumIndex += 2;
+ }
+ bool is64Bit = enumerator.flags.testAnyFlags(EnumIs64Bit);
+ for (int key = 0; is64Bit && key < count; ++key) {
+ if constexpr (mode == Construct) {
+ data[enumIndex] = uint(enumerator.values[key] >> 32);
}
+ ++enumIndex;
}
dataIndex += QMetaObjectPrivate::IntsPerEnum;
- enumIndex += 2 * count;
}
// Output the constructors in the class.
@@ -2312,7 +2328,8 @@ QMetaType QMetaEnumBuilder::metaType() const
}
/*!
- Sets this enumerator to have the given \c metaType.
+ Sets this enumerator to have the given \c metaType. The is64Bit() flag will
+ be set to match \a metaType's size.
\since 6.6
\sa metaType()
@@ -2320,8 +2337,10 @@ QMetaType QMetaEnumBuilder::metaType() const
void QMetaEnumBuilder::setMetaType(QMetaType metaType)
{
QMetaEnumBuilderPrivate *d = d_func();
- if (d)
+ if (d) {
d->metaType = metaType;
+ setIs64Bit(metaType.sizeOf() > 4);
+ }
}
/*!
@@ -2334,7 +2353,7 @@ bool QMetaEnumBuilder::isFlag() const
{
QMetaEnumBuilderPrivate *d = d_func();
if (d)
- return d->isFlag;
+ return d->flags.toInt() & EnumIsFlag;
else
return false;
}
@@ -2348,7 +2367,7 @@ void QMetaEnumBuilder::setIsFlag(bool value)
{
QMetaEnumBuilderPrivate *d = d_func();
if (d)
- d->isFlag = value;
+ d->flags.setFlag(EnumIsFlag, value);
}
/*!
@@ -2360,7 +2379,7 @@ bool QMetaEnumBuilder::isScoped() const
{
QMetaEnumBuilderPrivate *d = d_func();
if (d)
- return d->isScoped;
+ return d->flags.toInt() & EnumIsScoped;
return false;
}
@@ -2373,7 +2392,37 @@ void QMetaEnumBuilder::setIsScoped(bool value)
{
QMetaEnumBuilderPrivate *d = d_func();
if (d)
- d->isScoped = value;
+ d->flags.setFlag(EnumIsScoped, value);
+}
+
+/*!
+ Return \c true if this enumerations in this enumerator are 64-bit.
+
+ This flag is autoamtically enabled if a 64-bit value is added with addKey().
+
+ \sa setIs64Bit()
+*/
+bool QMetaEnumBuilder::is64Bit() const
+{
+ QMetaEnumBuilderPrivate *d = d_func();
+ if (d)
+ return d->flags.toInt() & EnumIs64Bit;
+ return false;
+}
+
+/*!
+ Sets this enumerator to be 64-bit wide if \a value is true. If \a value is
+ false, any stored 64-bit keys will be truncated to 32 bits.
+
+ This flag is autoamtically enabled if a 64-bit value is added with addKey().
+
+ \sa is64Bit()
+*/
+void QMetaEnumBuilder::setIs64Bit(bool value)
+{
+ QMetaEnumBuilderPrivate *d = d_func();
+ if (d)
+ d->flags.setFlag(EnumIs64Bit, value);
}
/*!
@@ -2409,15 +2458,38 @@ QByteArray QMetaEnumBuilder::key(int index) const
Returns the value with the given \a index; or returns -1 if there
is no such value.
- \sa keyCount(), addKey(), key()
+ If this is a 64-bit enumeration (see is64Bit()), this function returns the
+ low 32-bit portion of the value. Use value64() to obtain the full value
+ instead.
+
+ \sa value64(), keyCount(), addKey(), key(), is64Bit()
*/
int QMetaEnumBuilder::value(int index) const
{
+ return value64(index).value_or(-1);
+}
+
+/*!
+ \since 6.9
+
+ Returns the value with the given \a index if it exists; or returns a
+ disengaged \c{std::optional} if it doesn't.
+
+ \include qmetaobject.cpp qmetaenum-32bit-zeroextend-64bit
+
+ \sa keyCount(), key(), addKey()
+*/
+std::optional<quint64> QMetaEnumBuilder::value64(int index) const
+{
QMetaEnumBuilderPrivate *d = d_func();
- if (d && index >= 0 && index < d->keys.size())
- return d->values[index];
- else
- return -1;
+ if (d && index >= 0 && index < d->keys.size()) {
+ quint64 v = d->values[index];
+ if (d->flags & EnumIs64Bit)
+ return v;
+ return uint(v); // return only the low 32 bits
+ } else {
+ return std::nullopt;
+ }
}
/*!
@@ -2430,16 +2502,34 @@ int QMetaEnumBuilder::addKey(const QByteArray &name, int value)
{
QMetaEnumBuilderPrivate *d = d_func();
if (d) {
- int index = d->keys.size();
- d->keys += name;
- d->values += value;
- return index;
+ return d->addKey(name, uint(value));
} else {
return -1;
}
}
/*!
+ \since 6.9
+
+ Adds a new key called \a name to this enumerator, associated
+ with \a value. Returns the index of the new key.
+
+ Using the 64-bit version of this function automatically makes this
+ enumeration be stored as 64-bit.
+
+ \sa keyCount(), key(), value(), removeKey(), is64Bit()
+*/
+int QMetaEnumBuilder::addKey(const QByteArray &name, quint64 value)
+{
+ QMetaEnumBuilderPrivate *d = d_func();
+ if (d) {
+ setIs64Bit(true);
+ return d->addKey(name, value);
+ }
+ return -1;
+}
+
+/*!
Removes the key at \a index from this enumerator.
\sa addKey()
diff --git a/src/corelib/kernel/qmetaobjectbuilder_p.h b/src/corelib/kernel/qmetaobjectbuilder_p.h
index b52487986ce..697398aa2b3 100644
--- a/src/corelib/kernel/qmetaobjectbuilder_p.h
+++ b/src/corelib/kernel/qmetaobjectbuilder_p.h
@@ -267,11 +267,16 @@ public:
bool isScoped() const;
void setIsScoped(bool value);
+ bool is64Bit() const;
+ void setIs64Bit(bool value);
+
int keyCount() const;
QByteArray key(int index) const;
int value(int index) const;
+ std::optional<quint64> value64(int index) const;
- int addKey(const QByteArray& name, int value);
+ int addKey(const QByteArray &name, int value);
+ int addKey(const QByteArray &name, quint64 value);
void removeKey(int index);
private:
diff --git a/tests/auto/corelib/kernel/qmetaobjectbuilder/tst_qmetaobjectbuilder.cpp b/tests/auto/corelib/kernel/qmetaobjectbuilder/tst_qmetaobjectbuilder.cpp
index 18e4e2a4a90..fa927536b77 100644
--- a/tests/auto/corelib/kernel/qmetaobjectbuilder/tst_qmetaobjectbuilder.cpp
+++ b/tests/auto/corelib/kernel/qmetaobjectbuilder/tst_qmetaobjectbuilder.cpp
@@ -75,6 +75,8 @@ class SomethingOfEverything : public QObject
Q_PROPERTY(QLocale::Language language READ language)
Q_ENUMS(SomethingEnum)
Q_FLAGS(SomethingFlag)
+ Q_ENUMS(SomethingEnum64)
+ Q_FLAGS(SomethingFlag64)
public:
Q_INVOKABLE SomethingOfEverything() {}
~SomethingOfEverything() {}
@@ -85,6 +87,12 @@ public:
JKL = 10
};
+ enum SomethingEnum64 : qint64
+ {
+ MNO = -1,
+ PQR = 0x1'2345'5678,
+ };
+
enum SomethingFlagEnum
{
XYZ = 1,
@@ -92,6 +100,13 @@ public:
};
Q_DECLARE_FLAGS(SomethingFlag, SomethingFlagEnum)
+ enum SomethingFlagEnum64 : quint64
+ {
+ RST = Q_UINT64_C(1) << 31,
+ OPQ = Q_UINT64_C(1) << 63,
+ };
+ Q_DECLARE_FLAGS(SomethingFlag64, SomethingFlagEnum64)
+
Q_INVOKABLE Q_SCRIPTABLE void method1() {}
QString prop() const { return QString(); }
@@ -806,6 +821,7 @@ void tst_QMetaObjectBuilder::enumerator()
QCOMPARE(enum1.name(), QByteArray("foo"));
QVERIFY(!enum1.isFlag());
QVERIFY(!enum1.isScoped());
+ QVERIFY(!enum1.is64Bit());
QCOMPARE(enum1.keyCount(), 0);
QCOMPARE(enum1.index(), 0);
QCOMPARE(builder.enumeratorCount(), 1);
@@ -815,6 +831,7 @@ void tst_QMetaObjectBuilder::enumerator()
QCOMPARE(enum2.name(), QByteArray("bar"));
QVERIFY(!enum2.isFlag());
QVERIFY(!enum2.isScoped());
+ QVERIFY(!enum2.is64Bit());
QCOMPARE(enum2.keyCount(), 0);
QCOMPARE(enum2.index(), 1);
QCOMPARE(builder.enumeratorCount(), 2);
@@ -831,9 +848,12 @@ void tst_QMetaObjectBuilder::enumerator()
enum1.setIsScoped(true);
enum1.setEnumName(QByteArrayLiteral("fooFlag"));
enum1.setMetaType(QMetaType(&fooFlagMetaType));
+ QVERIFY(enum1.is64Bit());
+ enum1.setIs64Bit(false);
+ QVERIFY(!enum1.is64Bit());
QCOMPARE(enum1.addKey("ABC", 0), 0);
QCOMPARE(enum1.addKey("DEF", 1), 1);
- QCOMPARE(enum1.addKey("GHI", -1), 2);
+ QCOMPARE(enum1.addKey("GHI", -2), 2);
// Check that enum1 is changed, but enum2 is not.
QCOMPARE(enum1.name(), QByteArray("foo"));
@@ -849,7 +869,10 @@ void tst_QMetaObjectBuilder::enumerator()
QCOMPARE(enum1.key(3), QByteArray());
QCOMPARE(enum1.value(0), 0);
QCOMPARE(enum1.value(1), 1);
- QCOMPARE(enum1.value(2), -1);
+ QCOMPARE(enum1.value(2), -2);
+ QCOMPARE(enum1.value64(0), 0);
+ QCOMPARE(enum1.value64(1), 1);
+ QCOMPARE(enum1.value64(2), uint(-2));
QCOMPARE(enum2.name(), QByteArray("bar"));
QVERIFY(!enum2.isFlag());
QVERIFY(!enum2.isScoped());
@@ -859,12 +882,14 @@ void tst_QMetaObjectBuilder::enumerator()
// Modify the attributes on enum2.
enum2.setIsFlag(true);
QCOMPARE(enum2.addKey("XYZ", 10), 0);
- QCOMPARE(enum2.addKey("UVW", 19), 1);
+ QCOMPARE(enum2.addKey("UVW", quint64(1) << 32), 1);
+ QVERIFY(enum2.is64Bit());
// This time check that only method2 changed.
QCOMPARE(enum1.name(), QByteArray("foo"));
QVERIFY(enum1.isFlag());
QVERIFY(enum1.isScoped());
+ QVERIFY(!enum1.is64Bit());
QCOMPARE(enum1.keyCount(), 3);
QCOMPARE(enum1.index(), 0);
QCOMPARE(enum1.key(0), QByteArray("ABC"));
@@ -873,17 +898,35 @@ void tst_QMetaObjectBuilder::enumerator()
QCOMPARE(enum1.key(3), QByteArray());
QCOMPARE(enum1.value(0), 0);
QCOMPARE(enum1.value(1), 1);
- QCOMPARE(enum1.value(2), -1);
+ QCOMPARE(enum1.value(2), -2);
+ QCOMPARE(enum1.value64(0), 0);
+ QCOMPARE(enum1.value64(1), 1);
+ QCOMPARE(enum1.value64(2), uint(-2));
QCOMPARE(enum2.name(), QByteArray("bar"));
QVERIFY(enum2.isFlag());
QVERIFY(!enum2.isScoped());
+ QVERIFY(enum2.is64Bit());
QCOMPARE(enum2.keyCount(), 2);
QCOMPARE(enum2.index(), 1);
QCOMPARE(enum2.key(0), QByteArray("XYZ"));
QCOMPARE(enum2.key(1), QByteArray("UVW"));
QCOMPARE(enum2.key(2), QByteArray());
QCOMPARE(enum2.value(0), 10);
- QCOMPARE(enum2.value(1), 19);
+ QCOMPARE(enum2.value(1), 0); // truncated!
+ QCOMPARE(enum2.value64(0), 10);
+ QCOMPARE(enum2.value64(1), quint64(1) << 32);
+
+ // Reset enum2 to 32 bits
+ enum2.setIs64Bit(false);
+ QCOMPARE(enum2.value(0), 10);
+ QCOMPARE(enum2.value(1), 0);
+ QCOMPARE(enum2.value64(0), 10);
+ QCOMPARE(enum2.value64(1), 0);
+
+ // Reset back restores it
+ enum2.setIs64Bit(true);
+ QCOMPARE(enum2.value64(0), 10);
+ QCOMPARE(enum2.value64(1), quint64(1) << 32);
// Remove enum1 key
enum1.removeKey(2);
@@ -898,6 +941,9 @@ void tst_QMetaObjectBuilder::enumerator()
QCOMPARE(enum1.value(0), 0);
QCOMPARE(enum1.value(1), 1);
QCOMPARE(enum1.value(2), -1);
+ QCOMPARE(enum1.value64(0), 0);
+ QCOMPARE(enum1.value64(1), 1);
+ QCOMPARE(enum1.value64(2), std::nullopt);
QCOMPARE(enum2.name(), QByteArray("bar"));
QVERIFY(enum2.isFlag());
QVERIFY(!enum2.isScoped());
@@ -907,7 +953,9 @@ void tst_QMetaObjectBuilder::enumerator()
QCOMPARE(enum2.key(1), QByteArray("UVW"));
QCOMPARE(enum2.key(2), QByteArray());
QCOMPARE(enum2.value(0), 10);
- QCOMPARE(enum2.value(1), 19);
+ QCOMPARE(enum2.value(1), 0); // truncated!
+ QCOMPARE(enum2.value64(0), 10);
+ QCOMPARE(enum2.value64(1), quint64(1) << 32);
// Remove enum1 and check that enum2 becomes index 0.
builder.removeEnumerator(0);
@@ -922,7 +970,9 @@ void tst_QMetaObjectBuilder::enumerator()
QCOMPARE(enum2.key(1), QByteArray("UVW"));
QCOMPARE(enum2.key(2), QByteArray());
QCOMPARE(enum2.value(0), 10);
- QCOMPARE(enum2.value(1), 19);
+ QCOMPARE(enum2.value(1), 0); // truncated!
+ QCOMPARE(enum2.value64(0), 10);
+ QCOMPARE(enum2.value64(1), quint64(1) << 32);
// Perform index-based lookup again.
QCOMPARE(builder.indexOfEnumerator("foo"), -1);
@@ -1185,13 +1235,19 @@ static bool sameEnumerator(const QMetaEnum& enum1, const QMetaEnum& enum2)
for (int index = 0; index < enum1.keyCount(); ++index) {
if (QByteArray(enum1.key(index)) != QByteArray(enum2.key(index)))
return false;
- if (enum1.value(index) != enum2.value(index))
+ if (enum1.value64(index) != enum2.value64(index))
return false;
}
if (QByteArray(enum1.scope()) != QByteArray(enum2.scope()))
return false;
+ if (enum1.isScoped() != enum2.isScoped())
+ return false;
+
+ if (enum1.is64Bit() != enum2.is64Bit())
+ return false;
+
return true;
}