QMetaObjectBuilder: add support for 64-bit flags and enums
Task-number: QTBUG-111926 Change-Id: I8a96935cf6c742259c9dfffd17e9519aa2540313 Reviewed-by: Fabian Kosmale <fabian.kosmale@qt.io>
This commit is contained in:
parent
21f04d5d29
commit
f85a17abeb
@ -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,15 +2502,33 @@ 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.
|
||||
|
||||
|
@ -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:
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user