moc: add support for storing 64-bit enums and flags
The metatype format is extended by storing the high parts of all enumerations after the (name, low part) section, for a total of 12 bytes per enumeration instead of 8. This allows 32-bit flags and enums to remain unchanged. In fact, older meta object parsers remain unchanged, aside from not knowing what this new bit in the flags field means. Because this is entirely done in the C++ constexpr side, moc knows nothing about it so it can't update the JSON output with a new field. Task-number: QTBUG-111926 Change-Id: I8a96935cf6c742259c9dfffd17e9512e4f4add19 Reviewed-by: Fabian Kosmale <fabian.kosmale@qt.io>
This commit is contained in:
parent
d40a2265ea
commit
0d26dc6727
@ -29,7 +29,7 @@ namespace QtMocConstants {
|
|||||||
// and metamethods store a flag stating whether they are const
|
// and metamethods store a flag stating whether they are const
|
||||||
// revision 11 is Qt 6.5: The metatype for void is stored in the metatypes array
|
// revision 11 is Qt 6.5: The metatype for void is stored in the metatypes array
|
||||||
// revision 12 is Qt 6.6: It adds the metatype for enums
|
// revision 12 is Qt 6.6: It adds the metatype for enums
|
||||||
// revision 13 is Qt 6.9: It moves the location of the meta method revisions
|
// revision 13 is Qt 6.9: Adds support for 64-bit QFlags and moves the method revision
|
||||||
enum { OutputRevision = 13 }; // Used by moc, qmetaobjectbuilder and qdbus
|
enum { OutputRevision = 13 }; // Used by moc, qmetaobjectbuilder and qdbus
|
||||||
|
|
||||||
enum PropertyFlags : uint {
|
enum PropertyFlags : uint {
|
||||||
@ -88,6 +88,7 @@ enum MetaDataFlags : uint {
|
|||||||
enum EnumFlags : uint {
|
enum EnumFlags : uint {
|
||||||
EnumIsFlag = 0x1,
|
EnumIsFlag = 0x1,
|
||||||
EnumIsScoped = 0x2,
|
EnumIsScoped = 0x2,
|
||||||
|
EnumIs64Bit = 0x40,
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace QtMocConstants
|
} // namespace QtMocConstants
|
||||||
|
@ -83,6 +83,16 @@ template <uint... Nx> constexpr auto stringData(const char (&...strings)[Nx])
|
|||||||
struct NoType {};
|
struct NoType {};
|
||||||
|
|
||||||
namespace detail {
|
namespace detail {
|
||||||
|
template<typename Enum> constexpr int payloadSizeForEnum()
|
||||||
|
{
|
||||||
|
// How many uint blocks do we need to store the values of this enum and the
|
||||||
|
// string indices for the enumeration labels? We only support 8- 16-, 32-
|
||||||
|
// and 64-bit enums at the time of this writing, so this code is extra
|
||||||
|
// pedantic allowing for 48-, 96-, 128-bit, etc.
|
||||||
|
int n = int(sizeof(Enum) + sizeof(uint)) - 1;
|
||||||
|
return 1 + n / sizeof(uint);
|
||||||
|
}
|
||||||
|
|
||||||
template <uint H, uint P> struct UintDataBlock
|
template <uint H, uint P> struct UintDataBlock
|
||||||
{
|
{
|
||||||
static constexpr uint headerSize() { return H; }
|
static constexpr uint headerSize() { return H; }
|
||||||
@ -207,10 +217,10 @@ struct PropertyData : detail::UintDataBlock<5, 0>
|
|||||||
};
|
};
|
||||||
|
|
||||||
template <typename Enum, int N = 0>
|
template <typename Enum, int N = 0>
|
||||||
struct EnumData : detail::UintDataBlock<5, 2 * N>
|
struct EnumData : detail::UintDataBlock<5, N * detail::payloadSizeForEnum<Enum>()>
|
||||||
{
|
{
|
||||||
private:
|
private:
|
||||||
static_assert(sizeof(Enum) <= sizeof(uint), "Cannot store enumeration of this size");
|
static_assert(sizeof(Enum) <= 2 * sizeof(uint), "Cannot store enumeration of this size");
|
||||||
template <typename T> struct RealEnum { using Type = T; };
|
template <typename T> struct RealEnum { using Type = T; };
|
||||||
template <typename T> struct RealEnum<QFlags<T>> { using Type = T; };
|
template <typename T> struct RealEnum<QFlags<T>> { using Type = T; };
|
||||||
public:
|
public:
|
||||||
@ -219,7 +229,6 @@ public:
|
|||||||
typename RealEnum<Enum>::Type value;
|
typename RealEnum<Enum>::Type value;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
constexpr EnumData(uint nameOffset, uint aliasOffset, uint flags)
|
constexpr EnumData(uint nameOffset, uint aliasOffset, uint flags)
|
||||||
{
|
{
|
||||||
this->header[0] = nameOffset;
|
this->header[0] = nameOffset;
|
||||||
@ -234,7 +243,7 @@ public:
|
|||||||
this->header[2] |= QtMocConstants::EnumIsScoped;
|
this->header[2] |= QtMocConstants::EnumIsScoped;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <int Added> constexpr auto add(const EnumEntry (&entries)[Added])
|
template <int Added> constexpr auto add(const EnumEntry (&entries)[Added]) const
|
||||||
{
|
{
|
||||||
EnumData<Enum, N + Added> result(this->header[0], this->header[1], this->header[2]);
|
EnumData<Enum, N + Added> result(this->header[0], this->header[1], this->header[2]);
|
||||||
|
|
||||||
@ -245,6 +254,15 @@ public:
|
|||||||
auto value = qToUnderlying(entry.value);
|
auto value = qToUnderlying(entry.value);
|
||||||
result.payload[o++] = uint(value);
|
result.payload[o++] = uint(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if constexpr (sizeof(Enum) > sizeof(uint)) {
|
||||||
|
static_assert(N == 0, "Unimplemented: merging with non-empty EnumData");
|
||||||
|
result.header[2] |= QtMocConstants::EnumIs64Bit;
|
||||||
|
for (auto entry : entries) {
|
||||||
|
auto value = qToUnderlying(entry.value);
|
||||||
|
result.payload[o++] = uint(value >> 32);
|
||||||
|
}
|
||||||
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -152,12 +152,12 @@ public:
|
|||||||
enum MetaEnumTest_Enum0 { MetaEnumTest_Enum0_dummy = 2, MetaEnumTest_Enum0_value = 42, MetaEnsureSignedEnum0 = -1 };
|
enum MetaEnumTest_Enum0 { MetaEnumTest_Enum0_dummy = 2, MetaEnumTest_Enum0_value = 42, MetaEnsureSignedEnum0 = -1 };
|
||||||
Q_ENUM(MetaEnumTest_Enum0)
|
Q_ENUM(MetaEnumTest_Enum0)
|
||||||
enum MetaEnumTest_Enum1 : qint64 { MetaEnumTest_Enum1_value = 42, MetaEnumTest_Enum1_bigValue = (Q_INT64_C(1) << 33) + 50 };
|
enum MetaEnumTest_Enum1 : qint64 { MetaEnumTest_Enum1_value = 42, MetaEnumTest_Enum1_bigValue = (Q_INT64_C(1) << 33) + 50 };
|
||||||
// Q_ENUM(MetaEnumTest_Enum1)
|
Q_ENUM(MetaEnumTest_Enum1)
|
||||||
|
|
||||||
enum MetaEnumTest_Enum3 : qint64 { MetaEnumTest_Enum3_value = -47, MetaEnumTest_Enum3_bigValue = (Q_INT64_C(1) << 56) + 5, MetaEnumTest_Enum3_bigNegValue = -(Q_INT64_C(1) << 56) - 3 };
|
enum MetaEnumTest_Enum3 : qint64 { MetaEnumTest_Enum3_value = -47, MetaEnumTest_Enum3_bigValue = (Q_INT64_C(1) << 56) + 5, MetaEnumTest_Enum3_bigNegValue = -(Q_INT64_C(1) << 56) - 3 };
|
||||||
// Q_ENUM(MetaEnumTest_Enum3)
|
Q_ENUM(MetaEnumTest_Enum3)
|
||||||
enum MetaEnumTest_Enum4 : quint64 { MetaEnumTest_Enum4_value = 47, MetaEnumTest_Enum4_bigValue = (Q_INT64_C(1) << 52) + 45 };
|
enum MetaEnumTest_Enum4 : quint64 { MetaEnumTest_Enum4_value = 47, MetaEnumTest_Enum4_bigValue = (Q_INT64_C(1) << 52) + 45 };
|
||||||
// Q_ENUM(MetaEnumTest_Enum4)
|
Q_ENUM(MetaEnumTest_Enum4)
|
||||||
enum MetaEnumTest_Enum5 : uint { MetaEnumTest_Enum5_value = 47 };
|
enum MetaEnumTest_Enum5 : uint { MetaEnumTest_Enum5_value = 47 };
|
||||||
Q_ENUM(MetaEnumTest_Enum5)
|
Q_ENUM(MetaEnumTest_Enum5)
|
||||||
enum MetaEnumTest_Enum6 : uchar { MetaEnumTest_Enum6_value = 47 };
|
enum MetaEnumTest_Enum6 : uchar { MetaEnumTest_Enum6_value = 47 };
|
||||||
@ -5390,13 +5390,13 @@ void tst_QVariant::metaEnums_data()
|
|||||||
QTest::newRow(#Value) << &testVariantMetaEnum<decltype(Value), Value> << #Value;
|
QTest::newRow(#Value) << &testVariantMetaEnum<decltype(Value), Value> << #Value;
|
||||||
|
|
||||||
METAENUMS_TEST(MetaEnumTest_Enum0_value);
|
METAENUMS_TEST(MetaEnumTest_Enum0_value);
|
||||||
// METAENUMS_TEST(MetaEnumTest_Enum1_value);
|
METAENUMS_TEST(MetaEnumTest_Enum1_value);
|
||||||
// METAENUMS_TEST(MetaEnumTest_Enum1_bigValue);
|
METAENUMS_TEST(MetaEnumTest_Enum1_bigValue);
|
||||||
// METAENUMS_TEST(MetaEnumTest_Enum3_value);
|
METAENUMS_TEST(MetaEnumTest_Enum3_value);
|
||||||
// METAENUMS_TEST(MetaEnumTest_Enum3_bigValue);
|
METAENUMS_TEST(MetaEnumTest_Enum3_bigValue);
|
||||||
// METAENUMS_TEST(MetaEnumTest_Enum3_bigNegValue);
|
METAENUMS_TEST(MetaEnumTest_Enum3_bigNegValue);
|
||||||
// METAENUMS_TEST(MetaEnumTest_Enum4_value);
|
METAENUMS_TEST(MetaEnumTest_Enum4_value);
|
||||||
// METAENUMS_TEST(MetaEnumTest_Enum4_bigValue);
|
METAENUMS_TEST(MetaEnumTest_Enum4_bigValue);
|
||||||
METAENUMS_TEST(MetaEnumTest_Enum5_value);
|
METAENUMS_TEST(MetaEnumTest_Enum5_value);
|
||||||
METAENUMS_TEST(MetaEnumTest_Enum6_value);
|
METAENUMS_TEST(MetaEnumTest_Enum6_value);
|
||||||
METAENUMS_TEST(MetaEnumTest_Enum8_value);
|
METAENUMS_TEST(MetaEnumTest_Enum8_value);
|
||||||
|
@ -123,11 +123,17 @@ template <typename E, int N> void enumUintData_check(const E (&values)[N])
|
|||||||
QCOMPARE(result.payload[2 * i + 0], uint(namesAndOffsets[i].nameIndex));
|
QCOMPARE(result.payload[2 * i + 0], uint(namesAndOffsets[i].nameIndex));
|
||||||
QCOMPARE(result.payload[2 * i + 1], uint(values[i]));
|
QCOMPARE(result.payload[2 * i + 1], uint(values[i]));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if constexpr (sizeof(E) > sizeof(uint)) {
|
||||||
|
using U = std::underlying_type_t<E>;
|
||||||
|
for (uint i = 0; i < std::size(values); ++i)
|
||||||
|
QCOMPARE(result.payload[2 * N + i], uint(U(values[i]) >> 32));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
enum E1 { AnEnumValue };
|
enum E1 { AnEnumValue };
|
||||||
enum class E2 { V0 = INT_MAX, V1 = INT_MIN };
|
enum class E2 { V0 = INT_MAX, V1 = INT_MIN };
|
||||||
enum class E3 : int { V = 0x1111'2222, V2 = -V };
|
enum class E3 : qint64 { V = 0x1111'2222'3333'4444, V2 = -V };
|
||||||
void tst_MocHelpers::enumUintData()
|
void tst_MocHelpers::enumUintData()
|
||||||
{
|
{
|
||||||
using namespace QtMocHelpers;
|
using namespace QtMocHelpers;
|
||||||
@ -171,12 +177,14 @@ void tst_MocHelpers::enumUintData()
|
|||||||
.add({ { 2, E3::V }, {3, E3::V2 }, });
|
.add({ { 2, E3::V }, {3, E3::V2 }, });
|
||||||
QCOMPARE(result.header[0], 1U);
|
QCOMPARE(result.header[0], 1U);
|
||||||
QCOMPARE(result.header[1], 1U);
|
QCOMPARE(result.header[1], 1U);
|
||||||
QCOMPARE(result.header[2], EnumIsScoped);
|
QCOMPARE(result.header[2], EnumIsScoped | EnumIs64Bit);
|
||||||
QCOMPARE(result.header[3], 2U);
|
QCOMPARE(result.header[3], 2U);
|
||||||
QCOMPARE(result.payload[0], 2U);
|
QCOMPARE(result.payload[0], 2U);
|
||||||
QCOMPARE(result.payload[1], uint(E3::V));
|
QCOMPARE(result.payload[1], uint(E3::V));
|
||||||
QCOMPARE(result.payload[2], 3U);
|
QCOMPARE(result.payload[2], 3U);
|
||||||
QCOMPARE(result.payload[3], uint(E3::V2));
|
QCOMPARE(result.payload[3], uint(E3::V2));
|
||||||
|
QCOMPARE(result.payload[4], uint(quint64(E3::V) >> 32));
|
||||||
|
QCOMPARE(result.payload[5], uint(quint64(E3::V2) >> 32));
|
||||||
}
|
}
|
||||||
|
|
||||||
QTest::setThrowOnFail(true);
|
QTest::setThrowOnFail(true);
|
||||||
@ -184,6 +192,10 @@ void tst_MocHelpers::enumUintData()
|
|||||||
enum E { E0, E1 = -1, E2 = 123, E3 = INT_MIN };
|
enum E { E0, E1 = -1, E2 = 123, E3 = INT_MIN };
|
||||||
enumUintData_check({E0, E1, E2, E3});
|
enumUintData_check({E0, E1, E2, E3});
|
||||||
}
|
}
|
||||||
|
{
|
||||||
|
enum E : quint64 { E0, E1 = quint64(INT_MIN), E2 = 0x1'0000'0000, E3 = quint64(LLONG_MIN) };
|
||||||
|
enumUintData_check({E0, E1, E2, E3});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename Data> void testUintData(const Data &data)
|
template <typename Data> void testUintData(const Data &data)
|
||||||
@ -223,7 +235,7 @@ template <size_t N> static void checkEnums(const std::array<uint, N> &data)
|
|||||||
// E3:
|
// E3:
|
||||||
QCOMPARE(header[5 + 0], 4U);
|
QCOMPARE(header[5 + 0], 4U);
|
||||||
QCOMPARE(header[5 + 1], 5U);
|
QCOMPARE(header[5 + 1], 5U);
|
||||||
QCOMPARE(header[5 + 2], EnumIsFlag | EnumIsScoped);
|
QCOMPARE(header[5 + 2], EnumIsFlag | EnumIsScoped | EnumIs64Bit);
|
||||||
QCOMPARE(header[5 + 3], 2U);
|
QCOMPARE(header[5 + 3], 2U);
|
||||||
QCOMPARE_GE(header[5 + 4], 14U);
|
QCOMPARE_GE(header[5 + 4], 14U);
|
||||||
payload = data.data() + header[5 + 4];
|
payload = data.data() + header[5 + 4];
|
||||||
@ -231,6 +243,8 @@ template <size_t N> static void checkEnums(const std::array<uint, N> &data)
|
|||||||
QCOMPARE(payload[1], uint(E3::V));
|
QCOMPARE(payload[1], uint(E3::V));
|
||||||
QCOMPARE(payload[2], 8U);
|
QCOMPARE(payload[2], 8U);
|
||||||
QCOMPARE(payload[3], uint(E3::V2));
|
QCOMPARE(payload[3], uint(E3::V2));
|
||||||
|
QCOMPARE(payload[4], uint(quint64(E3::V) >> 32));
|
||||||
|
QCOMPARE(payload[5], uint(quint64(E3::V2) >> 32));
|
||||||
|
|
||||||
// E2:
|
// E2:
|
||||||
QCOMPARE(header[10 + 0], 7U);
|
QCOMPARE(header[10 + 0], 7U);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user