summaryrefslogtreecommitdiffstats
path: root/src/corelib/global/qendian.h
diff options
context:
space:
mode:
Diffstat (limited to 'src/corelib/global/qendian.h')
-rw-r--r--src/corelib/global/qendian.h235
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