summaryrefslogtreecommitdiffstats
path: root/tests/auto
diff options
context:
space:
mode:
authorUlf Hermann <ulf.hermann@qt.io>2022-05-03 12:06:25 +0200
committerUlf Hermann <ulf.hermann@qt.io>2022-05-07 08:37:42 +0200
commit38002df2065d3730defe3513f73088b444e68139 (patch)
tree62963389291a81acf1ec4544696c014fb90d8e0e /tests/auto
parentb94ec982c1bbc9cf4e0efdbd0c4b8f14ec4ebdcc (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.cpp106
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"