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 QT_BEGIN_NAMESPACE @@ -136,6 +136,88 @@ typedef QBEInteger quint16_be; typedef QBEInteger quint32_be; typedef QBEInteger 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 QSpecialIntegerBitfield +{ +protected: + typedef typename S::StorageType T; + typedef typename std::make_unsigned::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::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 i) const + { return ((val ^ i.val) & S::toSpecial(mask())) == 0; } + bool operator !=(QSpecialIntegerBitfield 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 +using QLEIntegerBitfield = QSpecialIntegerBitfield, pos, width>; + +template +using QBEIntegerBitfield = QSpecialIntegerBitfield, pos, width>; + +template +using qint32_le_bitfield = QLEIntegerBitfield; +template +using quint32_le_bitfield = QLEIntegerBitfield; +template +using qint32_be_bitfield = QBEIntegerBitfield; +template +using quint32_be_bitfield = QBEIntegerBitfield; + + 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 qle_int; typedef q_littleendian qle_uint; template -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; template -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; 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 #include +#include 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("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(&vi16), vi16); + QCOMPARE(*reinterpret_cast(&vi32), vi32); + QCOMPARE(*reinterpret_cast(&vi64), vi64); + QCOMPARE(*reinterpret_cast(&vi16), qbswap(vi16)); + QCOMPARE(*reinterpret_cast(&vi32), qbswap(vi32)); + QCOMPARE(*reinterpret_cast(&vi64), qbswap(vi64)); + QCOMPARE(*reinterpret_cast(&vu16), vu16); + QCOMPARE(*reinterpret_cast(&vu32), vu32); + QCOMPARE(*reinterpret_cast(&vu64), vu64); + QCOMPARE(*reinterpret_cast(&vu16), qbswap(vu16)); + QCOMPARE(*reinterpret_cast(&vu32), qbswap(vu32)); + QCOMPARE(*reinterpret_cast(&vu64), qbswap(vu64)); +#else + QCOMPARE(*reinterpret_cast(&vi16), qbswap(vi16)); + QCOMPARE(*reinterpret_cast(&vi32), qbswap(vi32)); + QCOMPARE(*reinterpret_cast(&vi64), qbswap(vi64)); + QCOMPARE(*reinterpret_cast(&vi16), vi16); + QCOMPARE(*reinterpret_cast(&vi32), vi32); + QCOMPARE(*reinterpret_cast(&vi64), vi64); + QCOMPARE(*reinterpret_cast(&vu16), qbswap(vu16)); + QCOMPARE(*reinterpret_cast(&vu32), qbswap(vu32)); + QCOMPARE(*reinterpret_cast(&vu64), qbswap(vu64)); + QCOMPARE(*reinterpret_cast(&vu16), vu16); + QCOMPARE(*reinterpret_cast(&vu32), vu32); + QCOMPARE(*reinterpret_cast(&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"