diff options
author | Ulf Hermann <ulf.hermann@qt.io> | 2022-05-03 12:06:25 +0200 |
---|---|---|
committer | Ulf Hermann <ulf.hermann@qt.io> | 2022-05-07 08:37:42 +0200 |
commit | 38002df2065d3730defe3513f73088b444e68139 (patch) | |
tree | 62963389291a81acf1ec4544696c014fb90d8e0e /tests/auto | |
parent | b94ec982c1bbc9cf4e0efdbd0c4b8f14ec4ebdcc (diff) |
Endian: Provide special integer bitfield unions
Our previous approach of creating a union from individual special
integer bitfields leads to undefined values because only one member of a
union can be active at any given time. Compilers have finally caught up
with us on that and have started removing "no-op" writes to members.
The primary user of the special integer bitfield unions is
qv4compileddata_p.h in qtdeclarative. We want our on-disk format of
QML compilation units to be platform agnostic and space efficient.
Pick-to: 5.15 6.2 6.3
Task-number: QTBUG-99545
Change-Id: I24847bda2c364eb8ba75f074cde2a9bec25ced06
Reviewed-by: Fabian Kosmale <fabian.kosmale@qt.io>
Reviewed-by: Thiago Macieira <thiago.macieira@intel.com>
Diffstat (limited to 'tests/auto')
-rw-r--r-- | tests/auto/corelib/global/qtendian/tst_qtendian.cpp | 106 |
1 files changed, 105 insertions, 1 deletions
diff --git a/tests/auto/corelib/global/qtendian/tst_qtendian.cpp b/tests/auto/corelib/global/qtendian/tst_qtendian.cpp index 74c2deff52..015c896f8f 100644 --- a/tests/auto/corelib/global/qtendian/tst_qtendian.cpp +++ b/tests/auto/corelib/global/qtendian/tst_qtendian.cpp @@ -30,11 +30,17 @@ #include <QTest> #include <QtCore/qendian.h> #include <QtCore/private/qendian_p.h> - +#include <QtCore/qsysinfo.h> class tst_QtEndian: public QObject { Q_OBJECT +public: + enum Signedness { + Unsigned, + Signed + }; + Q_ENUM(Signedness); private slots: void fromBigEndian(); @@ -55,6 +61,9 @@ private slots: void endianIntegers(); void endianBitfields(); + + void endianBitfieldUnions_data(); + void endianBitfieldUnions(); }; struct TestData @@ -387,5 +396,100 @@ void tst_QtEndian::endianBitfields() QCOMPARE(u.bottom, -8); } +template<template<typename... Accessors> typename Union, template<int, int, typename> typename Member> +void testBitfieldUnion() +{ + using upper = Member<21, 11, uint>; + using lower = Member<10, 11, uint>; + using bottom = Member<0, 10, int>; + + using UnionType = Union<upper, lower, bottom>; + UnionType u; + + u.template set<upper>(200); + QCOMPARE(u.template get<upper>(), 200U); + u.template set<lower>(1000); + u.template set<bottom>(-8); + QCOMPARE(u.template get<lower>(), 1000U); + QCOMPARE(u.template get<upper>(), 200U); + + u.template set<lower>(u.template get<lower>() + u.template get<upper>()); + QCOMPARE(u.template get<upper>(), 200U); + QCOMPARE(u.template get<lower>(), 1200U); + + u.template set<upper>(65536 + 7); + u.template set<lower>(65535); + QCOMPARE(u.template get<lower>(), 65535U & ((1<<11) - 1)); + QCOMPARE(u.template get<upper>(), 7U); + + QCOMPARE(u.template get<bottom>(), -8); + + UnionType u2(QSpecialIntegerBitfieldZero); + QCOMPARE(u2.data(), 0U); + + UnionType u3(42U); + QCOMPARE(u3.data(), 42U); + + using BEUintAccessor = QSpecialIntegerAccessor<QBigEndianStorageType<uint>, 21, 11>; + using LEUintAccessor = QSpecialIntegerAccessor<QLittleEndianStorageType<uint>, 21, 11>; + using BEIntAccessor = QSpecialIntegerAccessor<QBigEndianStorageType<int>, 0, 10>; + using LEIntAccessor = QSpecialIntegerAccessor<QLittleEndianStorageType<int>, 0, 10>; + + if constexpr (std::is_same_v<BEUintAccessor, upper>) { + QCOMPARE(u.template get<BEUintAccessor>(), 7U); + } else if constexpr (std::is_same_v<LEUintAccessor, upper>) { + QCOMPARE(u.template get<LEUintAccessor>(), 7U); + } else if constexpr (std::is_same_v<BEIntAccessor, bottom>) { + QCOMPARE(u.template get<BEIntAccessor>(), -8); + } else if constexpr (std::is_same_v<LEIntAccessor, bottom>) { + QCOMPARE(u.template get<LEIntAccessor>(), -8); + } else { + QFAIL("none of the manually defined accessors match"); + } +} + +void tst_QtEndian::endianBitfieldUnions_data() +{ + QTest::addColumn<QSysInfo::Endian>("byteOrder"); + QTest::addColumn<Signedness>("signedness"); + + QTest::addRow("little endian unsigned") << QSysInfo::LittleEndian << Unsigned; + QTest::addRow("little endian signed") << QSysInfo::LittleEndian << Signed; + QTest::addRow("big endian unsigned") << QSysInfo::BigEndian << Unsigned; + QTest::addRow("big endian signed") << QSysInfo::BigEndian << Signed; +} + +void tst_QtEndian::endianBitfieldUnions() +{ + QFETCH(QSysInfo::Endian, byteOrder); + QFETCH(Signedness, signedness); + + switch (byteOrder) { + case QSysInfo::LittleEndian: + switch (signedness) { + case Unsigned: + testBitfieldUnion<quint32_le_bitfield_union, quint32_le_bitfield_member>(); + return; + case Signed: + testBitfieldUnion<qint32_le_bitfield_union, qint32_le_bitfield_member>(); + return; + } + Q_UNREACHABLE(); + return; + case QSysInfo::BigEndian: + switch (signedness) { + case Unsigned: + testBitfieldUnion<quint32_be_bitfield_union, quint32_be_bitfield_member>(); + return; + case Signed: + testBitfieldUnion<qint32_be_bitfield_union, qint32_be_bitfield_member>(); + return; + } + Q_UNREACHABLE(); + return; + } +} + + QTEST_MAIN(tst_QtEndian) #include "tst_qtendian.moc" |