summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/corelib/global/qendian_p.h84
-rw-r--r--src/corelib/json/qjson_p.h91
-rw-r--r--tests/auto/corelib/global/qtendian/qtendian.pro2
-rw-r--r--tests/auto/corelib/global/qtendian/tst_qtendian.cpp84
4 files changed, 170 insertions, 91 deletions
diff --git a/src/corelib/global/qendian_p.h b/src/corelib/global/qendian_p.h
index b279701a31..42d91cf735 100644
--- a/src/corelib/global/qendian_p.h
+++ b/src/corelib/global/qendian_p.h
@@ -51,7 +51,7 @@
// We mean it.
//
-#include "qendian.h"
+#include <QtCore/qendian.h>
QT_BEGIN_NAMESPACE
@@ -136,6 +136,88 @@ typedef QBEInteger<quint16> quint16_be;
typedef QBEInteger<quint32> quint32_be;
typedef QBEInteger<quint64> quint64_be;
+// Note if using multiple of these bitfields in a union; the underlying storage type must
+// match. Since we always use an unsigned storage type, unsigned and signed versions may
+// be used together, but different bit-widths may not.
+template<class S, int pos, int width>
+class QSpecialIntegerBitfield
+{
+protected:
+ typedef typename S::StorageType T;
+ typedef typename std::make_unsigned<T>::type UT;
+
+ static Q_DECL_CONSTEXPR UT mask()
+ {
+ return ((UT(1) << width) - 1) << pos;
+ }
+public:
+ // FIXME: val is public until qtdeclarative is fixed to not access it directly.
+ UT val;
+
+ QSpecialIntegerBitfield &operator =(T t)
+ {
+ UT i = S::fromSpecial(val);
+ i &= ~mask();
+ i |= (UT(t) << pos) & mask();
+ val = S::toSpecial(i);
+ return *this;
+ }
+ operator T() const
+ {
+ if (std::is_signed<T>::value) {
+ UT i = S::fromSpecial(val);
+ i <<= (sizeof(T) * 8) - width - pos;
+ T t = T(i);
+ t >>= (sizeof(T) * 8) - width;
+ return t;
+ }
+ return (S::fromSpecial(val) & mask()) >> pos;
+ }
+
+ bool operator !() const { return !(val & S::toSpecial(mask())); }
+ bool operator ==(QSpecialIntegerBitfield<S, pos, width> i) const
+ { return ((val ^ i.val) & S::toSpecial(mask())) == 0; }
+ bool operator !=(QSpecialIntegerBitfield<S, pos, width> i) const
+ { return ((val ^ i.val) & S::toSpecial(mask())) != 0; }
+
+ QSpecialIntegerBitfield &operator +=(T i)
+ { return (*this = (T(*this) + i)); }
+ QSpecialIntegerBitfield &operator -=(T i)
+ { return (*this = (T(*this) - i)); }
+ QSpecialIntegerBitfield &operator *=(T i)
+ { return (*this = (T(*this) * i)); }
+ QSpecialIntegerBitfield &operator /=(T i)
+ { return (*this = (T(*this) / i)); }
+ QSpecialIntegerBitfield &operator %=(T i)
+ { return (*this = (T(*this) % i)); }
+ QSpecialIntegerBitfield &operator |=(T i)
+ { return (*this = (T(*this) | i)); }
+ QSpecialIntegerBitfield &operator &=(T i)
+ { return (*this = (T(*this) & i)); }
+ QSpecialIntegerBitfield &operator ^=(T i)
+ { return (*this = (T(*this) ^ i)); }
+ QSpecialIntegerBitfield &operator >>=(T i)
+ { return (*this = (T(*this) >> i)); }
+ QSpecialIntegerBitfield &operator <<=(T i)
+ { return (*this = (T(*this) << i)); }
+};
+
+template<typename T, int pos, int width>
+using QLEIntegerBitfield = QSpecialIntegerBitfield<QLittleEndianStorageType<T>, pos, width>;
+
+template<typename T, int pos, int width>
+using QBEIntegerBitfield = QSpecialIntegerBitfield<QBigEndianStorageType<T>, pos, width>;
+
+template<int pos, int width>
+using qint32_le_bitfield = QLEIntegerBitfield<int, pos, width>;
+template<int pos, int width>
+using quint32_le_bitfield = QLEIntegerBitfield<uint, pos, width>;
+template<int pos, int width>
+using qint32_be_bitfield = QBEIntegerBitfield<int, pos, width>;
+template<int pos, int width>
+using quint32_be_bitfield = QBEIntegerBitfield<uint, pos, width>;
+
+
QT_END_NAMESPACE
#endif // QENDIAN_P_H
diff --git a/src/corelib/json/qjson_p.h b/src/corelib/json/qjson_p.h
index 5d600843aa..131528376b 100644
--- a/src/corelib/json/qjson_p.h
+++ b/src/corelib/json/qjson_p.h
@@ -140,97 +140,10 @@ typedef q_littleendian<int> qle_int;
typedef q_littleendian<unsigned int> qle_uint;
template<int pos, int width>
-class qle_bitfield
-{
-public:
- uint val;
-
- enum {
- mask = ((1u << width) - 1) << pos
- };
-
- void operator =(uint t) {
- uint i = qFromLittleEndian(val);
- i &= ~mask;
- i |= t << pos;
- val = qToLittleEndian(i);
- }
- operator uint() const {
- uint t = qFromLittleEndian(val);
- t &= mask;
- t >>= pos;
- return t;
- }
- bool operator !() const {
- return !operator uint();
- }
-
- bool operator ==(uint t) { return uint(*this) == t; }
- bool operator !=(uint t) { return uint(*this) != t; }
- bool operator <(uint t) { return uint(*this) < t; }
- bool operator >(uint t) { return uint(*this) > t; }
- bool operator <=(uint t) { return uint(*this) <= t; }
- bool operator >=(uint t) { return uint(*this) >= t; }
- qle_bitfield &operator +=(uint i) {
- *this = (uint(*this) + i);
- return *this;
- }
- qle_bitfield &operator -=(uint i) {
- *this = (uint(*this) - i);
- return *this;
- }
- qle_bitfield &operator |=(uint i) {
- *this = (uint(*this) | i);
- return *this;
- }
- qle_bitfield &operator &=(uint i) {
- *this = (uint(*this) & i);
- return *this;
- }
-};
+using qle_bitfield = QLEIntegerBitfield<uint, pos, width>;
template<int pos, int width>
-class qle_signedbitfield
-{
-public:
- uint val;
-
- enum {
- mask = ((1u << width) - 1) << pos
- };
-
- void operator =(int t) {
- uint i = qFromLittleEndian(val);
- i &= ~mask;
- i |= t << pos;
- val = qToLittleEndian(i);
- }
- operator int() const {
- uint i = qFromLittleEndian(val);
- i <<= 32 - width - pos;
- int t = (int) i;
- t >>= 32 - width;
- return t;
- }
- bool operator !() const {
- return !operator int();
- }
-
- bool operator ==(int t) { return int(*this) == t; }
- bool operator !=(int t) { return int(*this) != t; }
- bool operator <(int t) { return int(*this) < t; }
- bool operator >(int t) { return int(*this) > t; }
- bool operator <=(int t) { return int(*this) <= t; }
- bool operator >=(int t) { return int(*this) >= t; }
- qle_signedbitfield &operator +=(int i) {
- *this = (int(*this) + i);
- return *this;
- }
- qle_signedbitfield &operator -=(int i) {
- *this = (int(*this) - i);
- return *this;
- }
-};
+using qle_signedbitfield = QLEIntegerBitfield<int, pos, width>;
typedef qle_uint offset;
diff --git a/tests/auto/corelib/global/qtendian/qtendian.pro b/tests/auto/corelib/global/qtendian/qtendian.pro
index 214c706ca5..890976d26c 100644
--- a/tests/auto/corelib/global/qtendian/qtendian.pro
+++ b/tests/auto/corelib/global/qtendian/qtendian.pro
@@ -1,4 +1,4 @@
CONFIG += testcase
TARGET = tst_qtendian
-QT = core testlib
+QT = core core-private testlib
SOURCES = tst_qtendian.cpp
diff --git a/tests/auto/corelib/global/qtendian/tst_qtendian.cpp b/tests/auto/corelib/global/qtendian/tst_qtendian.cpp
index 915e40954b..6934818dcf 100644
--- a/tests/auto/corelib/global/qtendian/tst_qtendian.cpp
+++ b/tests/auto/corelib/global/qtendian/tst_qtendian.cpp
@@ -29,6 +29,7 @@
#include <QtTest/QtTest>
#include <QtCore/qendian.h>
+#include <QtCore/private/qendian_p.h>
class tst_QtEndian: public QObject
@@ -41,6 +42,11 @@ private slots:
void toBigEndian();
void toLittleEndian();
+
+ void endianIntegers_data();
+ void endianIntegers();
+
+ void endianBitfields();
};
struct TestData
@@ -129,5 +135,83 @@ void tst_QtEndian::toLittleEndian()
#undef ENDIAN_TEST
+void tst_QtEndian::endianIntegers_data()
+{
+ QTest::addColumn<int>("val");
+
+ QTest::newRow("-30000") << -30000;
+ QTest::newRow("-1") << -1;
+ QTest::newRow("0") << 0;
+ QTest::newRow("1020") << 1020;
+ QTest::newRow("16385") << 16385;
+}
+
+void tst_QtEndian::endianIntegers()
+{
+ QFETCH(int, val);
+
+ qint16 vi16 = val;
+ qint32 vi32 = val;
+ qint64 vi64 = val;
+ quint16 vu16 = val;
+ quint32 vu32 = val;
+ quint64 vu64 = val;
+
+#if Q_BYTE_ORDER == Q_BIG_ENDIAN
+ QCOMPARE(*reinterpret_cast<qint16_be*>(&vi16), vi16);
+ QCOMPARE(*reinterpret_cast<qint32_be*>(&vi32), vi32);
+ QCOMPARE(*reinterpret_cast<qint64_be*>(&vi64), vi64);
+ QCOMPARE(*reinterpret_cast<qint16_le*>(&vi16), qbswap(vi16));
+ QCOMPARE(*reinterpret_cast<qint32_le*>(&vi32), qbswap(vi32));
+ QCOMPARE(*reinterpret_cast<qint64_le*>(&vi64), qbswap(vi64));
+ QCOMPARE(*reinterpret_cast<quint16_be*>(&vu16), vu16);
+ QCOMPARE(*reinterpret_cast<quint32_be*>(&vu32), vu32);
+ QCOMPARE(*reinterpret_cast<quint64_be*>(&vu64), vu64);
+ QCOMPARE(*reinterpret_cast<quint16_le*>(&vu16), qbswap(vu16));
+ QCOMPARE(*reinterpret_cast<quint32_le*>(&vu32), qbswap(vu32));
+ QCOMPARE(*reinterpret_cast<quint64_le*>(&vu64), qbswap(vu64));
+#else
+ QCOMPARE(*reinterpret_cast<qint16_be*>(&vi16), qbswap(vi16));
+ QCOMPARE(*reinterpret_cast<qint32_be*>(&vi32), qbswap(vi32));
+ QCOMPARE(*reinterpret_cast<qint64_be*>(&vi64), qbswap(vi64));
+ QCOMPARE(*reinterpret_cast<qint16_le*>(&vi16), vi16);
+ QCOMPARE(*reinterpret_cast<qint32_le*>(&vi32), vi32);
+ QCOMPARE(*reinterpret_cast<qint64_le*>(&vi64), vi64);
+ QCOMPARE(*reinterpret_cast<quint16_be*>(&vu16), qbswap(vu16));
+ QCOMPARE(*reinterpret_cast<quint32_be*>(&vu32), qbswap(vu32));
+ QCOMPARE(*reinterpret_cast<quint64_be*>(&vu64), qbswap(vu64));
+ QCOMPARE(*reinterpret_cast<quint16_le*>(&vu16), vu16);
+ QCOMPARE(*reinterpret_cast<quint32_le*>(&vu32), vu32);
+ QCOMPARE(*reinterpret_cast<quint64_le*>(&vu64), vu64);
+#endif
+}
+
+void tst_QtEndian::endianBitfields()
+{
+ union {
+ quint32_be_bitfield<21, 11> upper;
+ quint32_be_bitfield<10, 11> lower;
+ qint32_be_bitfield<0, 10> bottom;
+ } u;
+
+ u.upper = 200;
+ QCOMPARE(u.upper, 200U);
+ u.lower = 1000;
+ u.bottom = -8;
+ QCOMPARE(u.lower, 1000U);
+ QCOMPARE(u.upper, 200U);
+
+ u.lower += u.upper;
+ QCOMPARE(u.upper, 200U);
+ QCOMPARE(u.lower, 1200U);
+
+ u.upper = 65536 + 7;
+ u.lower = 65535;
+ QCOMPARE(u.lower, 65535U & ((1<<11) - 1));
+ QCOMPARE(u.upper, 7U);
+
+ QCOMPARE(u.bottom, -8);
+}
+
QTEST_MAIN(tst_QtEndian)
#include "tst_qtendian.moc"