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.

Change-Id: I1483f3af2ccec6038e1c780649f9ffe413bb59ef
Reviewed-by: Thiago Macieira <thiago.macieira@intel.com>
(cherry picked from commit 104a0a9ecdb18d65e4d9075d87e8860c6c9d8335)
(cherry picked from commit 09bf722590ca6d1482b6605e1dffaaadd863e125)
Reviewed-by: Qt Cherry-pick Bot <cherrypick_bot@qt-project.org>
Reviewed-by: Volker Hilsheimer <volker.hilsheimer@qt.io>
This commit is contained in:
Marc Mutz 2023-09-12 23:54:00 +02:00 committed by Qt Cherry-pick Bot
parent 5866056a97
commit a1a5e12ef9
4 changed files with 135 additions and 5 deletions

View File

@ -152,7 +152,7 @@ QT_BEGIN_NAMESPACE
Typedef for \c{__int128} on platforms that support it (Qt defines the macro Typedef for \c{__int128} on platforms that support it (Qt defines the macro
\l QT_SUPPORTS_INT128 if this is the case). \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 Typedef for \c{unsigned __int128} on platforms that support it (Qt defines
the macro \l QT_SUPPORTS_INT128 if this is the case). 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 Qt defines this macro as well as the \l qint128 and \l quint128 types if
the platform has support for 128-bit integer types. 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() \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 // Statically check assumptions about the environment we're running
// in. The idea here is to error or warn if otherwise implicit Qt // in. The idea here is to error or warn if otherwise implicit Qt
// assumptions are not fulfilled on new hardware or compilers // 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 #ifdef QT_SUPPORTS_INT128
// check that numeric_limits works: // check that numeric_limits works:
// This fails here for GCC 9, but succeeds on Clang and GCC >= 11 // 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: // so just suppress the check for older GCC:
# if !defined(Q_CC_GNU_ONLY) || Q_CC_GNU >= 1100 # if !defined(Q_CC_GNU_ONLY) || Q_CC_GNU >= 1100
static_assert(std::numeric_limits<quint128>::max() == quint128(-1)); static_assert(std::numeric_limits<quint128>::max() == Q_UINT128_MAX);
# endif # endif
#endif #endif

View File

@ -67,7 +67,20 @@ typedef quint64 qulonglong;
#if defined(QT_SUPPORTS_INT128) #if defined(QT_SUPPORTS_INT128)
__extension__ typedef __int128_t qint128; __extension__ typedef __int128_t qint128;
__extension__ typedef __uint128_t quint128; __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 #ifndef __cplusplus
// In C++ mode, we define below using QIntegerForSize template // In C++ mode, we define below using QIntegerForSize template

View File

@ -53,6 +53,12 @@ void tst_GlobalTypes()
#endif /* QT_SUPPORTS_INT128 */ #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 */ /* Qt version */
int tst_QtVersion() int tst_QtVersion()
{ {

View File

@ -10,8 +10,49 @@
#include <QString> #include <QString>
#include <QtVersion> #include <QtVersion>
#include <array>
#include <cmath> #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 class tst_QGlobal: public QObject
{ {
Q_OBJECT Q_OBJECT
@ -28,6 +69,7 @@ private slots:
void qCoreAppStartupFunction(); void qCoreAppStartupFunction();
void qCoreAppStartupFunctionRestart(); void qCoreAppStartupFunctionRestart();
void integerForSize(); void integerForSize();
void int128Literals();
void buildAbiEndianness(); void buildAbiEndianness();
void testqOverload(); void testqOverload();
void testqMinMax(); void testqMinMax();
@ -44,6 +86,12 @@ extern "C" { // functions in qglobal.c
void tst_GlobalTypes(); void tst_GlobalTypes();
int tst_QtVersion(); int tst_QtVersion();
const char *tst_qVersion(); 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() void tst_QGlobal::cMode()
@ -435,6 +483,26 @@ void tst_QGlobal::integerForSize()
#endif #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; typedef QPair<const char *, const char *> stringpair;
Q_DECLARE_METATYPE(stringpair) Q_DECLARE_METATYPE(stringpair)