diff options
Diffstat (limited to 'src/corelib/global/qendian.h')
-rw-r--r-- | src/corelib/global/qendian.h | 235 |
1 files changed, 154 insertions, 81 deletions
diff --git a/src/corelib/global/qendian.h b/src/corelib/global/qendian.h index 4e9cd2e6e3..3337829de0 100644 --- a/src/corelib/global/qendian.h +++ b/src/corelib/global/qendian.h @@ -52,22 +52,6 @@ QT_BEGIN_NAMESPACE /* * ENDIAN FUNCTIONS */ -inline void qbswap_helper(const void *src, void *dest, int size) -{ - for (int i = 0; i < size ; ++i) - static_cast<uchar *>(dest)[i] = static_cast<const uchar *>(src)[size - 1 - i]; -} - -/* - * qbswap(const T src, const void *dest); - * Changes the byte order of \a src from big endian to little endian or vice versa - * and stores the result in \a dest. - * There is no alignment requirements for \a dest. -*/ -template <typename T> inline void qbswap(const T src, void *dest) -{ - qbswap_helper(&src, dest, sizeof(T)); -} // Used to implement a type-safe and alignment-safe copy operation // If you want to avoid the memcpy, you must write specializations for these functions @@ -103,30 +87,11 @@ template <typename T> Q_ALWAYS_INLINE T qFromUnaligned(const void *src) * This function can be used if you are not concerned about alignment issues, * and it is therefore a bit more convenient and in most cases more efficient. */ -template <typename T> T qbswap(T source); - -// GCC 4.3 implemented all the intrinsics, but the 16-bit one only got implemented in 4.8; -// Clang 2.6 implemented the 32- and 64-bit but waited until 3.2 to implement the 16-bit one -#if (defined(Q_CC_GNU) && Q_CC_GNU >= 403) || QT_HAS_BUILTIN(__builtin_bswap32) -template <> inline quint64 qbswap<quint64>(quint64 source) -{ - return __builtin_bswap64(source); -} -template <> inline quint32 qbswap<quint32>(quint32 source) -{ - return __builtin_bswap32(source); -} +template <typename T> Q_DECL_CONSTEXPR T qbswap(T source); -template <> inline void qbswap<quint64>(quint64 source, void *dest) -{ - qToUnaligned<quint64>(__builtin_bswap64(source), dest); -} -template <> inline void qbswap<quint32>(quint32 source, void *dest) -{ - qToUnaligned<quint32>(__builtin_bswap32(source), dest); -} -#else -template <> inline quint64 qbswap<quint64>(quint64 source) +// These definitions are written so that they are recognized by most compilers +// as bswap and replaced with single instruction builtins if available. +template <> inline Q_DECL_CONSTEXPR quint64 qbswap<quint64>(quint64 source) { return 0 | ((source & Q_UINT64_C(0x00000000000000ff)) << 56) @@ -139,7 +104,7 @@ template <> inline quint64 qbswap<quint64>(quint64 source) | ((source & Q_UINT64_C(0xff00000000000000)) >> 56); } -template <> inline quint32 qbswap<quint32>(quint32 source) +template <> inline Q_DECL_CONSTEXPR quint32 qbswap<quint32>(quint32 source) { return 0 | ((source & 0x000000ff) << 24) @@ -147,65 +112,61 @@ template <> inline quint32 qbswap<quint32>(quint32 source) | ((source & 0x00ff0000) >> 8) | ((source & 0xff000000) >> 24); } -#endif // GCC & Clang intrinsics -#if (defined(Q_CC_GNU) && Q_CC_GNU >= 408) || QT_HAS_BUILTIN(__builtin_bswap16) -template <> inline quint16 qbswap<quint16>(quint16 source) -{ - return __builtin_bswap16(source); -} -template <> inline void qbswap<quint16>(quint16 source, void *dest) -{ - qToUnaligned<quint16>(__builtin_bswap16(source), dest); -} -#else -template <> inline quint16 qbswap<quint16>(quint16 source) + +template <> inline Q_DECL_CONSTEXPR quint16 qbswap<quint16>(quint16 source) { return quint16( 0 | ((source & 0x00ff) << 8) | ((source & 0xff00) >> 8) ); } -#endif // GCC & Clang intrinsics + +template <> inline Q_DECL_CONSTEXPR quint8 qbswap<quint8>(quint8 source) +{ + return source; +} // signed specializations -template <> inline qint64 qbswap<qint64>(qint64 source) +template <> inline Q_DECL_CONSTEXPR qint64 qbswap<qint64>(qint64 source) { return qbswap<quint64>(quint64(source)); } -template <> inline qint32 qbswap<qint32>(qint32 source) +template <> inline Q_DECL_CONSTEXPR qint32 qbswap<qint32>(qint32 source) { return qbswap<quint32>(quint32(source)); } -template <> inline qint16 qbswap<qint16>(qint16 source) +template <> inline Q_DECL_CONSTEXPR qint16 qbswap<qint16>(qint16 source) { return qbswap<quint16>(quint16(source)); } -template <> inline void qbswap<qint64>(qint64 source, void *dest) +template <> inline Q_DECL_CONSTEXPR qint8 qbswap<qint8>(qint8 source) { - qbswap<quint64>(quint64(source), dest); + return source; } -template <> inline void qbswap<qint32>(qint32 source, void *dest) +/* + * qbswap(const T src, const void *dest); + * Changes the byte order of \a src from big endian to little endian or vice versa + * and stores the result in \a dest. + * There is no alignment requirements for \a dest. +*/ +template <typename T> inline void qbswap(const T src, void *dest) { - qbswap<quint32>(quint32(source), dest); + qToUnaligned<T>(qbswap<T>(src), dest); } -template <> inline void qbswap<qint16>(qint16 source, void *dest) -{ - qbswap<quint16>(quint16(source), dest); -} #if Q_BYTE_ORDER == Q_BIG_ENDIAN -template <typename T> inline T qToBigEndian(T source) +template <typename T> inline Q_DECL_CONSTEXPR T qToBigEndian(T source) { return source; } -template <typename T> inline T qFromBigEndian(T source) +template <typename T> inline Q_DECL_CONSTEXPR T qFromBigEndian(T source) { return source; } -template <typename T> inline T qToLittleEndian(T source) +template <typename T> inline Q_DECL_CONSTEXPR T qToLittleEndian(T source) { return qbswap<T>(source); } -template <typename T> inline T qFromLittleEndian(T source) +template <typename T> inline Q_DECL_CONSTEXPR T qFromLittleEndian(T source) { return qbswap<T>(source); } template <typename T> inline void qToBigEndian(T src, void *dest) { qToUnaligned<T>(src, dest); } @@ -213,13 +174,13 @@ template <typename T> inline void qToLittleEndian(T src, void *dest) { qbswap<T>(src, dest); } #else // Q_LITTLE_ENDIAN -template <typename T> inline T qToBigEndian(T source) +template <typename T> inline Q_DECL_CONSTEXPR T qToBigEndian(T source) { return qbswap<T>(source); } -template <typename T> inline T qFromBigEndian(T source) +template <typename T> inline Q_DECL_CONSTEXPR T qFromBigEndian(T source) { return qbswap<T>(source); } -template <typename T> inline T qToLittleEndian(T source) +template <typename T> inline Q_DECL_CONSTEXPR T qToLittleEndian(T source) { return source; } -template <typename T> inline T qFromLittleEndian(T source) +template <typename T> inline Q_DECL_CONSTEXPR T qFromLittleEndian(T source) { return source; } template <typename T> inline void qToBigEndian(T src, void *dest) { qbswap<T>(src, dest); } @@ -228,15 +189,6 @@ template <typename T> inline void qToLittleEndian(T src, void *dest) #endif // Q_BYTE_ORDER == Q_BIG_ENDIAN -template <> inline quint8 qbswap<quint8>(quint8 source) -{ - return source; -} - -template <> inline qint8 qbswap<qint8>(qint8 source) -{ - return source; -} /* T qFromLittleEndian(const void *src) * This function will read a little-endian encoded value from \a src @@ -267,6 +219,127 @@ template <> inline quint8 qFromBigEndian<quint8>(const void *src) template <> inline qint8 qFromBigEndian<qint8>(const void *src) { return static_cast<const qint8 *>(src)[0]; } +template<class S> +class QSpecialInteger +{ + typedef typename S::StorageType T; + T val; +public: + QSpecialInteger() = default; + explicit Q_DECL_CONSTEXPR QSpecialInteger(T i) : val(S::toSpecial(i)) {} + + QSpecialInteger &operator =(T i) { val = S::toSpecial(i); return *this; } + operator T() const { return S::fromSpecial(val); } + + bool operator ==(QSpecialInteger<S> i) const { return val == i.val; } + bool operator !=(QSpecialInteger<S> i) const { return val != i.val; } + + QSpecialInteger &operator +=(T i) + { return (*this = S::fromSpecial(val) + i); } + QSpecialInteger &operator -=(T i) + { return (*this = S::fromSpecial(val) - i); } + QSpecialInteger &operator *=(T i) + { return (*this = S::fromSpecial(val) * i); } + QSpecialInteger &operator >>=(T i) + { return (*this = S::fromSpecial(val) >> i); } + QSpecialInteger &operator <<=(T i) + { return (*this = S::fromSpecial(val) << i); } + QSpecialInteger &operator /=(T i) + { return (*this = S::fromSpecial(val) / i); } + QSpecialInteger &operator %=(T i) + { return (*this = S::fromSpecial(val) % i); } + QSpecialInteger &operator |=(T i) + { return (*this = S::fromSpecial(val) | i); } + QSpecialInteger &operator &=(T i) + { return (*this = S::fromSpecial(val) & i); } + QSpecialInteger &operator ^=(T i) + { return (*this = S::fromSpecial(val) ^ i); } +}; + +template<typename T> +class QLittleEndianStorageType { +public: + typedef T StorageType; + static Q_DECL_CONSTEXPR T toSpecial(T source) { return qToLittleEndian(source); } + static Q_DECL_CONSTEXPR T fromSpecial(T source) { return qFromLittleEndian(source); } +}; + +template<typename T> +class QBigEndianStorageType { +public: + typedef T StorageType; + static Q_DECL_CONSTEXPR T toSpecial(T source) { return qToBigEndian(source); } + static Q_DECL_CONSTEXPR T fromSpecial(T source) { return qFromBigEndian(source); } +}; + +#ifdef Q_QDOC +class QLEInteger { +public: + explicit Q_DECL_CONSTEXPR QLEInteger(T i); + QLEInteger &operator =(T i); + operator T() const; + bool operator ==(QLEInteger i) const; + bool operator !=(QLEInteger i) const; + QLEInteger &operator +=(T i); + QLEInteger &operator -=(T i); + QLEInteger &operator *=(T i); + QLEInteger &operator >>=(T i); + QLEInteger &operator <<=(T i); + QLEInteger &operator /=(T i); + QLEInteger &operator %=(T i); + QLEInteger &operator |=(T i); + QLEInteger &operator &=(T i); + QLEInteger &operator ^=(T i); +}; + +class QBEInteger { +public: + explicit Q_DECL_CONSTEXPR QBEInteger(T i); + QBEInteger &operator =(T i); + operator T() const; + bool operator ==(QBEInteger i) const; + bool operator !=(QBEInteger i) const; + QBEInteger &operator +=(T i); + QBEInteger &operator -=(T i); + QBEInteger &operator *=(T i); + QBEInteger &operator >>=(T i); + QBEInteger &operator <<=(T i); + QBEInteger &operator /=(T i); + QBEInteger &operator %=(T i); + QBEInteger &operator |=(T i); + QBEInteger &operator &=(T i); + QBEInteger &operator ^=(T i); +}; +#else + +template<typename T> +using QLEInteger = QSpecialInteger<QLittleEndianStorageType<T>>; + +template<typename T> +using QBEInteger = QSpecialInteger<QBigEndianStorageType<T>>; +#endif +template <typename T> +class QTypeInfo<QLEInteger<T> > + : public QTypeInfoMerger<QLEInteger<T>, T> {}; + +template <typename T> +class QTypeInfo<QBEInteger<T> > + : public QTypeInfoMerger<QBEInteger<T>, T> {}; + +typedef QLEInteger<qint16> qint16_le; +typedef QLEInteger<qint32> qint32_le; +typedef QLEInteger<qint64> qint64_le; +typedef QLEInteger<quint16> quint16_le; +typedef QLEInteger<quint32> quint32_le; +typedef QLEInteger<quint64> quint64_le; + +typedef QBEInteger<qint16> qint16_be; +typedef QBEInteger<qint32> qint32_be; +typedef QBEInteger<qint64> qint64_be; +typedef QBEInteger<quint16> quint16_be; +typedef QBEInteger<quint32> quint32_be; +typedef QBEInteger<quint64> quint64_be; + QT_END_NAMESPACE #endif // QENDIAN_H |