Skip to content

Commit

Permalink
qendian: Fix float conversions
Browse files Browse the repository at this point in the history
Since Qt 5.10, qTo/FromBig/LittleEndian<float/double> stopped working.
It may be confusing, but big endian floats do exist, so not to break old
code, we should support them.

Change-Id: I21cdbc7f48ec030ce3d82f1cd1aad212f0fe5dd0
Reviewed-by: Thiago Macieira <[email protected]>
  • Loading branch information
ABBAPOH committed Oct 28, 2018
1 parent 2691720 commit 95476bf
Showing 2 changed files with 63 additions and 3 deletions.
26 changes: 26 additions & 0 deletions src/corelib/global/qendian.h
Original file line number Diff line number Diff line change
@@ -41,6 +41,7 @@
#ifndef QENDIAN_H
#define QENDIAN_H

#include <QtCore/qfloat16.h>
#include <QtCore/qglobal.h>

// include stdlib.h and hope that it defines __GLIBC__ for glibc-based systems
@@ -151,6 +152,31 @@ template <> inline Q_DECL_CONSTEXPR qint8 qbswap<qint8>(qint8 source)
return source;
}

// floating specializations
template<typename Float>
Float qbswapFloatHelper(Float source)
{
// memcpy call in qFromUnaligned is recognized by optimizer as a correct way of type prunning
auto temp = qFromUnaligned<typename QIntegerForSizeof<Float>::Unsigned>(&source);
temp = qbswap(temp);
return qFromUnaligned<Float>(&temp);
}

template <> inline qfloat16 qbswap<qfloat16>(qfloat16 source)
{
return qbswapFloatHelper(source);
}

template <> inline float qbswap<float>(float source)
{
return qbswapFloatHelper(source);
}

template <> inline double qbswap<double>(double source)
{
return qbswapFloatHelper(source);
}

/*
* qbswap(const T src, const void *dest);
* Changes the byte order of \a src from big endian to little endian or vice versa
40 changes: 37 additions & 3 deletions tests/auto/corelib/global/qtendian/tst_qtendian.cpp
Original file line number Diff line number Diff line change
@@ -64,6 +64,9 @@ struct TestData
quint16 data16;
quint8 data8;

float dataFloat;
double dataDouble;

quint8 reserved;
};

@@ -72,16 +75,47 @@ template <> quint8 getData(const TestData &d) { return d.data8; }
template <> quint16 getData(const TestData &d) { return d.data16; }
template <> quint32 getData(const TestData &d) { return d.data32; }
template <> quint64 getData(const TestData &d) { return d.data64; }
template <> float getData(const TestData &d) { return d.dataFloat; }

union RawTestData
{
uchar rawData[sizeof(TestData)];
TestData data;
};

static const TestData inNativeEndian = { Q_UINT64_C(0x0123456789abcdef), 0x00c0ffee, 0xcafe, 0xcf, '\0' };
static const RawTestData inBigEndian = { "\x01\x23\x45\x67\x89\xab\xcd\xef" "\x00\xc0\xff\xee" "\xca\xfe" "\xcf" };
static const RawTestData inLittleEndian = { "\xef\xcd\xab\x89\x67\x45\x23\x01" "\xee\xff\xc0\x00" "\xfe\xca" "\xcf" };
template <typename Float>
Float int2Float(typename QIntegerForSizeof<Float>::Unsigned i)
{
Float result = 0;
memcpy(reinterpret_cast<char *>(&result), reinterpret_cast<const char *>(&i), sizeof (Float));
return result;
}

static const TestData inNativeEndian = {
Q_UINT64_C(0x0123456789abcdef),
0x00c0ffee,
0xcafe,
0xcf,
int2Float<float>(0x00c0ffeeU),
int2Float<double>(Q_UINT64_C(0x0123456789abcdef)),
'\0'
};
static const RawTestData inBigEndian = {
"\x01\x23\x45\x67\x89\xab\xcd\xef"
"\x00\xc0\xff\xee"
"\xca\xfe"
"\xcf"
"\x00\xc0\xff\xee"
"\x01\x23\x45\x67\x89\xab\xcd\xef"
};
static const RawTestData inLittleEndian = {
"\xef\xcd\xab\x89\x67\x45\x23\x01"
"\xee\xff\xc0\x00"
"\xfe\xca"
"\xcf"
"\xee\xff\xc0\x00"
"\xef\xcd\xab\x89\x67\x45\x23\x01"
};

#define EXPAND_ENDIAN_TEST(endian) \
do { \

0 comments on commit 95476bf

Please sign in to comment.