Long live Q_(U)INT128_MIN/MAX!
Since compilers don't provide such macros, do it ourselves. In order to test these macros, add ad-hoc specializations of QTest::toString() for qint128 and quint128 locally to the test. Turns out it's not too hard to write them, so we might move them to a public header, yet. Pick-to: 6.6 Change-Id: I1483f3af2ccec6038e1c780649f9ffe413bb59ef Reviewed-by: Thiago Macieira <thiago.macieira@intel.com>
This commit is contained in:
parent
454636afec
commit
104a0a9ecd
@ -152,7 +152,7 @@ QT_BEGIN_NAMESPACE
|
||||
Typedef for \c{__int128} on platforms that support it (Qt defines the macro
|
||||
\l QT_SUPPORTS_INT128 if this is the case).
|
||||
|
||||
\sa quint128, QT_SUPPORTS_INT128
|
||||
\sa Q_INT128_MIN, Q_INT128_MAX, quint128, QT_SUPPORTS_INT128
|
||||
*/
|
||||
|
||||
/*!
|
||||
@ -163,7 +163,7 @@ QT_BEGIN_NAMESPACE
|
||||
Typedef for \c{unsigned __int128} on platforms that support it (Qt defines
|
||||
the macro \l QT_SUPPORTS_INT128 if this is the case).
|
||||
|
||||
\sa qint128, QT_SUPPORTS_INT128
|
||||
\sa Q_UINT128_MAX, qint128, QT_SUPPORTS_INT128
|
||||
*/
|
||||
|
||||
/*!
|
||||
@ -174,7 +174,7 @@ QT_BEGIN_NAMESPACE
|
||||
Qt defines this macro as well as the \l qint128 and \l quint128 types if
|
||||
the platform has support for 128-bit integer types.
|
||||
|
||||
\sa qint128, quint128
|
||||
\sa qint128, quint128, Q_INT128_MIN, Q_INT128_MAX, Q_UINT128_MAX
|
||||
*/
|
||||
|
||||
/*!
|
||||
@ -376,6 +376,48 @@ QT_BEGIN_NAMESPACE
|
||||
\sa quint64, Q_INT64_C()
|
||||
*/
|
||||
|
||||
/*!
|
||||
\macro Q_UINT128_MAX
|
||||
\relates <QtTypes>
|
||||
\since 6.6
|
||||
|
||||
This macro expands to a compile-time constant representing the
|
||||
maximum value representable in a \l quint128.
|
||||
|
||||
This macro is available in both C++ and C modes.
|
||||
|
||||
The minimum of \l quint128 is 0 (zero), so a \c{Q_UINT128_MIN} is neither
|
||||
needed nor provided.
|
||||
|
||||
\sa Q_INT128_MAX, quint128, QT_SUPPORTS_INT128
|
||||
*/
|
||||
|
||||
/*!
|
||||
\macro Q_INT128_MIN
|
||||
\relates <QtTypes>
|
||||
\since 6.6
|
||||
|
||||
This macro expands to a compile-time constant representing the
|
||||
minimum value representable in a \l qint128.
|
||||
|
||||
This macro is available in both C++ and C modes.
|
||||
|
||||
\sa Q_INT128_MAX, qint128, QT_SUPPORTS_INT128
|
||||
*/
|
||||
|
||||
/*!
|
||||
\macro Q_INT128_MAX
|
||||
\relates <QtTypes>
|
||||
\since 6.6
|
||||
|
||||
This macro expands to a compile-time constant representing the
|
||||
maximum value representable in a \l qint128.
|
||||
|
||||
This macro is available in both C++ and C modes.
|
||||
|
||||
\sa Q_INT128_MIN, Q_UINT128_MAX, qint128, QT_SUPPORTS_INT128
|
||||
*/
|
||||
|
||||
// Statically check assumptions about the environment we're running
|
||||
// in. The idea here is to error or warn if otherwise implicit Qt
|
||||
// assumptions are not fulfilled on new hardware or compilers
|
||||
@ -439,9 +481,10 @@ static_assert(sizeof(qint128) == 16, "Internal error, qint128 is misdefined");
|
||||
#ifdef QT_SUPPORTS_INT128
|
||||
// check that numeric_limits works:
|
||||
// This fails here for GCC 9, but succeeds on Clang and GCC >= 11
|
||||
// However, all tests in tst_qglobal::int128Literals() pass for GCC 9, too,
|
||||
// so just suppress the check for older GCC:
|
||||
# if !defined(Q_CC_GNU_ONLY) || Q_CC_GNU >= 1100
|
||||
static_assert(std::numeric_limits<quint128>::max() == qint128(-1));
|
||||
static_assert(std::numeric_limits<quint128>::max() == Q_UINT128_MAX);
|
||||
# endif
|
||||
#endif
|
||||
|
||||
|
@ -67,7 +67,20 @@ typedef quint64 qulonglong;
|
||||
#if defined(QT_SUPPORTS_INT128)
|
||||
__extension__ typedef __int128_t qint128;
|
||||
__extension__ typedef __uint128_t quint128;
|
||||
#endif
|
||||
|
||||
// limits:
|
||||
# ifdef __cplusplus /* need to avoid c-style-casts in C++ mode */
|
||||
# define QT_C_STYLE_CAST(type, x) static_cast<type>(x)
|
||||
# else /* but C doesn't have constructor-style casts */
|
||||
# define QT_C_STYLE_CAST(type, x) ((type)x)
|
||||
# endif
|
||||
# ifndef Q_UINT128_MAX /* allow qcompilerdetection.h/user override */
|
||||
# define Q_UINT128_MAX QT_C_STYLE_CAST(quint128, -1)
|
||||
# endif
|
||||
# define Q_INT128_MAX QT_C_STYLE_CAST(qint128, (Q_UINT128_MAX / 2))
|
||||
# define Q_INT128_MIN (-Q_INT128_MAX - 1)
|
||||
|
||||
#endif // QT_SUPPORTS_INT128
|
||||
|
||||
#ifndef __cplusplus
|
||||
// In C++ mode, we define below using QIntegerForSize template
|
||||
|
@ -59,6 +59,12 @@ void tst_GlobalTypes()
|
||||
#endif /* QT_SUPPORTS_INT128 */
|
||||
}
|
||||
|
||||
#if QT_SUPPORTS_INT128
|
||||
qint128 tst_qint128_min() { return Q_INT128_MIN + 0; }
|
||||
qint128 tst_qint128_max() { return 0 + Q_INT128_MAX; }
|
||||
quint128 tst_quint128_max() { return Q_UINT128_MAX - 1 + 1; }
|
||||
#endif
|
||||
|
||||
/* Qt version */
|
||||
int tst_QtVersion()
|
||||
{
|
||||
|
@ -12,8 +12,49 @@
|
||||
#include <QString>
|
||||
#include <QtVersion>
|
||||
|
||||
#include <array>
|
||||
#include <cmath>
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
namespace QTest {
|
||||
#ifdef QT_SUPPORTS_INT128
|
||||
namespace detail {
|
||||
char *i128ToStringHelper(std::array<char, 64> &buffer, quint128 n)
|
||||
{
|
||||
auto dst = buffer.data() + buffer.size();
|
||||
*--dst = '\0'; // NUL-terminate
|
||||
if (n == 0) {
|
||||
*--dst = '0'; // and done
|
||||
} else {
|
||||
while (n != 0) {
|
||||
*--dst = "0123456789"[n % 10];
|
||||
n /= 10;
|
||||
}
|
||||
}
|
||||
return dst;
|
||||
}
|
||||
}
|
||||
template <>
|
||||
char *toString(const qint128 &i)
|
||||
{
|
||||
if (i == std::numeric_limits<qint128>::min()) // -i is not representable, hardcode:
|
||||
return qstrdup("-170141183460469231731687303715884105728");
|
||||
std::array<char, 64> buffer;
|
||||
auto dst = detail::i128ToStringHelper(buffer, i < 0 ? -i : i);
|
||||
if (i < 0)
|
||||
*--dst = '-';
|
||||
return qstrdup(dst);
|
||||
}
|
||||
template <>
|
||||
char *toString(const quint128 &i)
|
||||
{
|
||||
std::array<char, 64> buffer;
|
||||
return qstrdup(detail::i128ToStringHelper(buffer, i));
|
||||
}
|
||||
#endif // QT_SUPPORTS_INT128
|
||||
} // namespace QTest
|
||||
QT_END_NAMESPACE
|
||||
|
||||
class tst_QGlobal: public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
@ -30,6 +71,7 @@ private slots:
|
||||
void qCoreAppStartupFunction();
|
||||
void qCoreAppStartupFunctionRestart();
|
||||
void integerForSize();
|
||||
void int128Literals();
|
||||
void buildAbiEndianness();
|
||||
void testqOverload();
|
||||
void testqMinMax();
|
||||
@ -46,6 +88,12 @@ extern "C" { // functions in qglobal.c
|
||||
void tst_GlobalTypes();
|
||||
int tst_QtVersion();
|
||||
const char *tst_qVersion();
|
||||
#if QT_SUPPORTS_INT128
|
||||
qint128 tst_qint128_min();
|
||||
qint128 tst_qint128_max();
|
||||
quint128 tst_quint128_max();
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
void tst_QGlobal::cMode()
|
||||
@ -437,6 +485,26 @@ void tst_QGlobal::integerForSize()
|
||||
#endif
|
||||
}
|
||||
|
||||
void tst_QGlobal::int128Literals()
|
||||
{
|
||||
#ifdef QT_SUPPORTS_INT128
|
||||
#define COMPARE_EQ(lhs, rhs, Expected128) do { \
|
||||
constexpr auto lhs_ = lhs; \
|
||||
static_assert(std::is_same_v<std::remove_cv_t<decltype(lhs_)>, Expected128>); \
|
||||
QCOMPARE_EQ(lhs_, rhs); \
|
||||
} while (0)
|
||||
COMPARE_EQ(Q_INT128_MIN, std::numeric_limits<qint128>::min(), qint128);
|
||||
COMPARE_EQ(Q_INT128_MAX, std::numeric_limits<qint128>::max(), qint128);
|
||||
COMPARE_EQ(Q_UINT128_MAX, std::numeric_limits<quint128>::max(), quint128);
|
||||
QCOMPARE_EQ(tst_qint128_min(), Q_INT128_MIN);
|
||||
QCOMPARE_EQ(tst_qint128_max(), Q_INT128_MAX);
|
||||
QCOMPARE_EQ(tst_quint128_max(), Q_UINT128_MAX);
|
||||
#undef COMPARE_EQ
|
||||
#else
|
||||
QSKIP("This test requires 128-bit integer support enabled in the compiler.");
|
||||
#endif
|
||||
}
|
||||
|
||||
typedef QPair<const char *, const char *> stringpair;
|
||||
Q_DECLARE_METATYPE(stringpair)
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user