Allow qMin, qMax and qBound for types that can be losslessly converted
Add overloads for qMin and friends where the arguments are of different type, but one can be easily promoted to the other. Return the promoted type. Promotions are only allowed if both types are either signed, unsigned or floating point numbers. This should simplify writing code in many case (as for example qMin(myint64, 1)) and also help reduce source incompatibilities between Qt 5 and Qt 6, where the return types for sizes of our containers changes from int to qsizetype. Change-Id: Ia6bcf16bef0469ea568063e7c32f532da610d1cd Reviewed-by: Volker Hilsheimer <volker.hilsheimer@qt.io> Reviewed-by: Thiago Macieira <thiago.macieira@intel.com>bb10
parent
0dbd2dd863
commit
95e84c0ea9
|
|
@ -617,6 +617,24 @@ Q_DECL_CONSTEXPR inline qint64 qRound64(double d)
|
|||
Q_DECL_CONSTEXPR inline qint64 qRound64(float d)
|
||||
{ return d >= 0.0f ? qint64(d + 0.5f) : qint64(d - float(qint64(d-1)) + 0.5f) + qint64(d-1); }
|
||||
|
||||
namespace QTypeTraits {
|
||||
|
||||
namespace detail {
|
||||
template<typename T, typename U,
|
||||
typename = std::enable_if_t<std::is_arithmetic_v<T> && std::is_arithmetic_v<U> &&
|
||||
std::is_floating_point_v<T> == std::is_floating_point_v<U> &&
|
||||
std::is_signed_v<T> == std::is_signed_v<U>> >
|
||||
struct Promoted
|
||||
{
|
||||
using type = decltype(T() + U());
|
||||
};
|
||||
}
|
||||
|
||||
template <typename T, typename U>
|
||||
using Promoted = typename detail::Promoted<T, U>::type;
|
||||
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
constexpr inline const T &qMin(const T &a, const T &b) { return (a < b) ? a : b; }
|
||||
template <typename T>
|
||||
|
|
@ -624,6 +642,31 @@ constexpr inline const T &qMax(const T &a, const T &b) { return (a < b) ? b : a;
|
|||
template <typename T>
|
||||
constexpr inline const T &qBound(const T &min, const T &val, const T &max)
|
||||
{ return qMax(min, qMin(max, val)); }
|
||||
template <typename T, typename U>
|
||||
constexpr inline QTypeTraits::Promoted<T, U> qMin(const T &a, const U &b)
|
||||
{
|
||||
using P = QTypeTraits::Promoted<T, U>;
|
||||
P _a = a;
|
||||
P _b = b;
|
||||
return (_a < _b) ? _a : _b;
|
||||
}
|
||||
template <typename T, typename U>
|
||||
constexpr inline QTypeTraits::Promoted<T, U> qMax(const T &a, const U &b)
|
||||
{
|
||||
using P = QTypeTraits::Promoted<T, U>;
|
||||
P _a = a;
|
||||
P _b = b;
|
||||
return (_a < _b) ? _b : _a;
|
||||
}
|
||||
template <typename T, typename U>
|
||||
constexpr inline QTypeTraits::Promoted<T, U> qBound(const T &min, const U &val, const T &max)
|
||||
{ return qMax(min, qMin(max, val)); }
|
||||
template <typename T, typename U>
|
||||
constexpr inline QTypeTraits::Promoted<T, U> qBound(const T &min, const T &val, const U &max)
|
||||
{ return qMax(min, qMin(max, val)); }
|
||||
template <typename T, typename U>
|
||||
constexpr inline QTypeTraits::Promoted<T, U> qBound(const U &min, const T &val, const T &max)
|
||||
{ return qMax(min, qMin(max, val)); }
|
||||
|
||||
#ifndef Q_FORWARD_DECLARE_OBJC_CLASS
|
||||
# ifdef __OBJC__
|
||||
|
|
|
|||
|
|
@ -51,6 +51,7 @@ private slots:
|
|||
void integerForSize();
|
||||
void buildAbiEndianness();
|
||||
void testqOverload();
|
||||
void testqMinMax();
|
||||
};
|
||||
|
||||
extern "C" { // functions in qglobal.c
|
||||
|
|
@ -575,6 +576,32 @@ void tst_QGlobal::testqOverload()
|
|||
#endif
|
||||
}
|
||||
|
||||
// enforce that types are identical when comparing
|
||||
template<typename T>
|
||||
void compare(T a, T b)
|
||||
{ QCOMPARE(a, b); }
|
||||
|
||||
void tst_QGlobal::testqMinMax()
|
||||
{
|
||||
// signed types
|
||||
compare(qMin(float(1), double(-1)), double(-1));
|
||||
compare(qMin(double(1), float(-1)), double(-1));
|
||||
compare(qMin(short(1), int(-1)), int(-1));
|
||||
compare(qMin(short(1), long(-1)), long(-1));
|
||||
compare(qMin(qint64(1), short(-1)), qint64(-1));
|
||||
|
||||
compare(qMax(float(1), double(-1)), double(1));
|
||||
compare(qMax(short(1), long(-1)), long(1));
|
||||
compare(qMax(qint64(1), short(-1)), qint64(1));
|
||||
|
||||
// unsigned types
|
||||
compare(qMin(ushort(1), ulong(2)), ulong(1));
|
||||
compare(qMin(quint64(1), ushort(2)), quint64(1));
|
||||
|
||||
compare(qMax(ushort(1), ulong(2)), ulong(2));
|
||||
compare(qMax(quint64(1), ushort(2)), quint64(2));
|
||||
}
|
||||
|
||||
|
||||
QTEST_APPLESS_MAIN(tst_QGlobal)
|
||||
#include "tst_qglobal.moc"
|
||||
|
|
|
|||
|
|
@ -26,6 +26,7 @@
|
|||
**
|
||||
****************************************************************************/
|
||||
|
||||
#include <QtCore/qglobal.h>
|
||||
|
||||
// SCENARIO 1
|
||||
// this is the "no harm done" version. Only operator% is active,
|
||||
|
|
|
|||
|
|
@ -26,6 +26,7 @@
|
|||
**
|
||||
****************************************************************************/
|
||||
|
||||
#include <QtCore/qglobal.h>
|
||||
|
||||
// SCENARIO 2
|
||||
// this is the "full" version. Operator+ is replaced by a QStringBuilder
|
||||
|
|
|
|||
|
|
@ -26,6 +26,7 @@
|
|||
**
|
||||
****************************************************************************/
|
||||
|
||||
#include <QtCore/qglobal.h>
|
||||
|
||||
// SCENARIO 3
|
||||
// this is the "no harm done" version. Only operator% is active,
|
||||
|
|
|
|||
|
|
@ -26,6 +26,7 @@
|
|||
**
|
||||
****************************************************************************/
|
||||
|
||||
#include <QtCore/qglobal.h>
|
||||
|
||||
// SCENARIO 4
|
||||
// this is the "full" version. Operator+ is replaced by a QStringBuilder
|
||||
|
|
|
|||
Loading…
Reference in New Issue