From 3bbc1bf53bac7648637d92abecadc568acfffb2d Mon Sep 17 00:00:00 2001 From: Thiago Macieira Date: Wed, 3 Dec 2014 14:56:21 -0800 Subject: Implement the unaligned byteswap functions using the aligned ones This leaves the decision on whether to do unaligned stores to the compiler, as opposed to forcing it by ourselves. Since we're now implementing them using two calls, this invalidates the compiler bug that triggered the #ifdef for Sun Studio (whatever that bug was). Change-Id: I4e494ca860a15b9427b2a3000921bf5d92cbb5ef Reviewed-by: Thiago Macieira Reviewed-by: Shawn Rutledge Reviewed-by: Olivier Goffart (Woboq GmbH) --- src/corelib/global/qendian.h | 254 +++++++++++-------------------------------- 1 file changed, 63 insertions(+), 191 deletions(-) diff --git a/src/corelib/global/qendian.h b/src/corelib/global/qendian.h index 7c643f7592..1d72ba0fae 100644 --- a/src/corelib/global/qendian.h +++ b/src/corelib/global/qendian.h @@ -63,7 +63,7 @@ template inline void qbswap(const T src, uchar *dest) } // Used to implement a type-safe and alignment-safe copy operation -// If you want to avoid the memcopy, you must write specializations for this function +// If you want to avoid the memcpy, you must write specializations for these functions template inline void qToUnaligned(const T src, uchar *dest) { // Using sizeof(T) inside memcpy function produces internal compiler error with @@ -71,199 +71,14 @@ template inline void qToUnaligned(const T src, uchar *dest) const size_t size = sizeof(T); memcpy(dest, &src, size); } - -/* T qFromLittleEndian(const uchar *src) - * This function will read a little-endian encoded value from \a src - * and return the value in host-endian encoding. - * There is no requirement that \a src must be aligned. -*/ -#if defined Q_CC_SUN -inline quint64 qFromLittleEndian_helper(const uchar *src, quint64 *dest) -{ - return 0 - | src[0] - | src[1] * Q_UINT64_C(0x0000000000000100) - | src[2] * Q_UINT64_C(0x0000000000010000) - | src[3] * Q_UINT64_C(0x0000000001000000) - | src[4] * Q_UINT64_C(0x0000000100000000) - | src[5] * Q_UINT64_C(0x0000010000000000) - | src[6] * Q_UINT64_C(0x0001000000000000) - | src[7] * Q_UINT64_C(0x0100000000000000); -} - -inline quint32 qFromLittleEndian_helper(const uchar *src, quint32 *dest) -{ - return 0 - | src[0] - | src[1] * quint32(0x00000100) - | src[2] * quint32(0x00010000) - | src[3] * quint32(0x01000000); -} - -inline quint16 qFromLittleEndian_helper(const uchar *src, quint16 *dest) -{ - return 0 - | src[0] - | src[1] * 0x0100; -} - -inline qint64 qFromLittleEndian_helper(const uchar *src, qint64 * dest) -{ return static_cast(qFromLittleEndian_helper(src, reinterpret_cast(0))); } -inline qint32 qFromLittleEndian_helper(const uchar *src, qint32 * dest) -{ return static_cast(qFromLittleEndian_helper(src, reinterpret_cast(0))); } -inline qint16 qFromLittleEndian_helper(const uchar *src, qint16 * dest) -{ return static_cast(qFromLittleEndian_helper(src, reinterpret_cast(0))); } - -template inline T qFromLittleEndian(const uchar *src) -{ - return qFromLittleEndian_helper(src, reinterpret_cast(0)); -} - -#else -template inline T qFromLittleEndian(const uchar *src); -template <> inline quint64 qFromLittleEndian(const uchar *src) -{ - return 0 - | src[0] - | src[1] * Q_UINT64_C(0x0000000000000100) - | src[2] * Q_UINT64_C(0x0000000000010000) - | src[3] * Q_UINT64_C(0x0000000001000000) - | src[4] * Q_UINT64_C(0x0000000100000000) - | src[5] * Q_UINT64_C(0x0000010000000000) - | src[6] * Q_UINT64_C(0x0001000000000000) - | src[7] * Q_UINT64_C(0x0100000000000000); -} - -template <> inline quint32 qFromLittleEndian(const uchar *src) -{ - return 0 - | src[0] - | src[1] * quint32(0x00000100) - | src[2] * quint32(0x00010000) - | src[3] * quint32(0x01000000); -} - -template <> inline quint16 qFromLittleEndian(const uchar *src) -{ - return quint16(0 - | src[0] - | src[1] * 0x0100); -} - -// signed specializations -template <> inline qint64 qFromLittleEndian(const uchar *src) -{ return static_cast(qFromLittleEndian(src)); } - -template <> inline qint32 qFromLittleEndian(const uchar *src) -{ return static_cast(qFromLittleEndian(src)); } - -template <> inline qint16 qFromLittleEndian(const uchar *src) -{ return static_cast(qFromLittleEndian(src)); } -#endif - -template <> inline quint8 qFromLittleEndian(const uchar *src) -{ return static_cast(src[0]); } -template <> inline qint8 qFromLittleEndian(const uchar *src) -{ return static_cast(src[0]); } - -/* This function will read a big-endian (also known as network order) encoded value from \a src - * and return the value in host-endian encoding. - * There is no requirement that \a src must be aligned. -*/ -#if defined Q_CC_SUN -inline quint64 qFromBigEndian_helper(const uchar *src, quint64 *dest) -{ - return 0 - | src[7] - | src[6] * Q_UINT64_C(0x0000000000000100) - | src[5] * Q_UINT64_C(0x0000000000010000) - | src[4] * Q_UINT64_C(0x0000000001000000) - | src[3] * Q_UINT64_C(0x0000000100000000) - | src[2] * Q_UINT64_C(0x0000010000000000) - | src[1] * Q_UINT64_C(0x0001000000000000) - | src[0] * Q_UINT64_C(0x0100000000000000); -} - -inline quint32 qFromBigEndian_helper(const uchar *src, quint32 * dest) -{ - return 0 - | src[3] - | src[2] * quint32(0x00000100) - | src[1] * quint32(0x00010000) - | src[0] * quint32(0x01000000); -} - -inline quint16 qFromBigEndian_helper(const uchar *src, quint16 * des) -{ - return 0 - | src[1] - | src[0] * 0x0100; -} - - -inline qint64 qFromBigEndian_helper(const uchar *src, qint64 * dest) -{ return static_cast(qFromBigEndian_helper(src, reinterpret_cast(0))); } -inline qint32 qFromBigEndian_helper(const uchar *src, qint32 * dest) -{ return static_cast(qFromBigEndian_helper(src, reinterpret_cast(0))); } -inline qint16 qFromBigEndian_helper(const uchar *src, qint16 * dest) -{ return static_cast(qFromBigEndian_helper(src, reinterpret_cast(0))); } - -template inline T qFromBigEndian(const uchar *src) -{ - return qFromBigEndian_helper(src, reinterpret_cast(0)); -} - -#else -template inline T qFromBigEndian(const uchar *src); -template<> -inline quint64 qFromBigEndian(const uchar *src) -{ - return 0 - | src[7] - | src[6] * Q_UINT64_C(0x0000000000000100) - | src[5] * Q_UINT64_C(0x0000000000010000) - | src[4] * Q_UINT64_C(0x0000000001000000) - | src[3] * Q_UINT64_C(0x0000000100000000) - | src[2] * Q_UINT64_C(0x0000010000000000) - | src[1] * Q_UINT64_C(0x0001000000000000) - | src[0] * Q_UINT64_C(0x0100000000000000); -} - -template<> -inline quint32 qFromBigEndian(const uchar *src) -{ - return 0 - | src[3] - | src[2] * quint32(0x00000100) - | src[1] * quint32(0x00010000) - | src[0] * quint32(0x01000000); -} - -template<> -inline quint16 qFromBigEndian(const uchar *src) +template inline T qFromUnaligned(const uchar *src) { - return quint16( 0 - | src[1] - | src[0] * quint16(0x0100)); + T dest; + const size_t size = sizeof(T); + memcpy(&dest, src, size); + return dest; } - -// signed specializations -template <> inline qint64 qFromBigEndian(const uchar *src) -{ return static_cast(qFromBigEndian(src)); } - -template <> inline qint32 qFromBigEndian(const uchar *src) -{ return static_cast(qFromBigEndian(src)); } - -template <> inline qint16 qFromBigEndian(const uchar *src) -{ return static_cast(qFromBigEndian(src)); } -#endif - -template <> inline quint8 qFromBigEndian(const uchar *src) -{ return static_cast(src[0]); } -template <> inline qint8 qFromBigEndian(const uchar *src) -{ return static_cast(src[0]); } - /* * T qbswap(T source). * Changes the byte order of a value from big endian to little endian or vice versa. @@ -283,6 +98,15 @@ template <> inline quint32 qbswap(quint32 source) { return __builtin_bswap32(source); } + +template <> inline void qbswap(quint64 source, uchar *dest) +{ + qToUnaligned(__builtin_bswap64(source), dest); +} +template <> inline void qbswap(quint32 source, uchar *dest) +{ + qToUnaligned(__builtin_bswap32(source), dest); +} #else template <> inline quint64 qbswap(quint64 source) { @@ -311,6 +135,10 @@ template <> inline quint16 qbswap(quint16 source) { return __builtin_bswap16(source); } +template <> inline void qbswap(quint16 source, uchar *dest) +{ + qToUnaligned(__builtin_bswap16(source), dest); +} #else template <> inline quint16 qbswap(quint16 source) { @@ -336,6 +164,21 @@ template <> inline qint16 qbswap(qint16 source) return qbswap(quint16(source)); } +template <> inline void qbswap(qint64 source, uchar *dest) +{ + qbswap(quint64(source), dest); +} + +template <> inline void qbswap(qint32 source, uchar *dest) +{ + qbswap(quint32(source), dest); +} + +template <> inline void qbswap(qint16 source, uchar *dest) +{ + qbswap(quint16(source), dest); +} + #if Q_BYTE_ORDER == Q_BIG_ENDIAN template inline T qToBigEndian(T source) @@ -377,6 +220,35 @@ template <> inline qint8 qbswap(qint8 source) return source; } +/* T qFromLittleEndian(const uchar *src) + * This function will read a little-endian encoded value from \a src + * and return the value in host-endian encoding. + * There is no requirement that \a src must be aligned. +*/ +template inline T qFromLittleEndian(const uchar *src) +{ + return qFromLittleEndian(qFromUnaligned(src)); +} + +template <> inline quint8 qFromLittleEndian(const uchar *src) +{ return static_cast(src[0]); } +template <> inline qint8 qFromLittleEndian(const uchar *src) +{ return static_cast(src[0]); } + +/* This function will read a big-endian (also known as network order) encoded value from \a src + * and return the value in host-endian encoding. + * There is no requirement that \a src must be aligned. +*/ +template inline T qFromBigEndian(const uchar *src) +{ + return qFromBigEndian(qFromUnaligned(src)); +} + +template <> inline quint8 qFromBigEndian(const uchar *src) +{ return static_cast(src[0]); } +template <> inline qint8 qFromBigEndian(const uchar *src) +{ return static_cast(src[0]); } + QT_END_NAMESPACE #endif // QENDIAN_H -- cgit v1.2.3