Back to home page

EIC code displayed by LXR

 
 

    


Warning, file /include/QtCore/qnumeric.h was not indexed or was modified since last indexation (in which case cross-reference links may be missing, inaccurate or erroneous).

0001 // Copyright (C) 2021 The Qt Company Ltd.
0002 // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
0003 
0004 #ifndef QNUMERIC_H
0005 #define QNUMERIC_H
0006 
0007 #if 0
0008 #pragma qt_class(QtNumeric)
0009 #endif
0010 
0011 #include <QtCore/qtconfigmacros.h>
0012 #include <QtCore/qtcoreexports.h>
0013 #include <QtCore/qtypes.h>
0014 
0015 #include <cmath>
0016 #include <limits>
0017 #include <type_traits>
0018 
0019 // min() and max() may be #defined by windows.h if that is included before, but we need them
0020 // for std::numeric_limits below. You should not use the min() and max() macros, so we just #undef.
0021 #ifdef min
0022 #  undef min
0023 #  undef max
0024 #endif
0025 
0026 #if defined(Q_CC_MSVC)
0027 #  include <intrin.h>
0028 #  include <float.h>
0029 #  if defined(Q_PROCESSOR_X86_64) || defined(Q_PROCESSOR_ARM_64)
0030 #    define Q_INTRINSIC_MUL_OVERFLOW64
0031 #    define Q_UMULH(v1, v2) __umulh(v1, v2);
0032 #    define Q_SMULH(v1, v2) __mulh(v1, v2);
0033 #    pragma intrinsic(__umulh)
0034 #    pragma intrinsic(__mulh)
0035 #  endif
0036 #endif
0037 
0038 # if defined(Q_OS_INTEGRITY) && defined(Q_PROCESSOR_ARM_64)
0039 #  include <arm64_ghs.h>
0040 #  define Q_INTRINSIC_MUL_OVERFLOW64
0041 #  define Q_UMULH(v1, v2) __MULUH64(v1, v2);
0042 #  define Q_SMULH(v1, v2) __MULSH64(v1, v2);
0043 #endif
0044 
0045 QT_BEGIN_NAMESPACE
0046 
0047 // To match std::is{inf,nan,finite} functions:
0048 template <typename T>
0049 constexpr typename std::enable_if<std::is_integral<T>::value, bool>::type
0050 qIsInf(T) { return false; }
0051 template <typename T>
0052 constexpr typename std::enable_if<std::is_integral<T>::value, bool>::type
0053 qIsNaN(T) { return false; }
0054 template <typename T>
0055 constexpr typename std::enable_if<std::is_integral<T>::value, bool>::type
0056 qIsFinite(T) { return true; }
0057 
0058 // Floating-point types (see qfloat16.h for its overloads).
0059 Q_CORE_EXPORT Q_DECL_CONST_FUNCTION bool qIsInf(double d);
0060 Q_CORE_EXPORT Q_DECL_CONST_FUNCTION bool qIsNaN(double d);
0061 Q_CORE_EXPORT Q_DECL_CONST_FUNCTION bool qIsFinite(double d);
0062 Q_CORE_EXPORT Q_DECL_CONST_FUNCTION int qFpClassify(double val);
0063 Q_CORE_EXPORT Q_DECL_CONST_FUNCTION bool qIsInf(float f);
0064 Q_CORE_EXPORT Q_DECL_CONST_FUNCTION bool qIsNaN(float f);
0065 Q_CORE_EXPORT Q_DECL_CONST_FUNCTION bool qIsFinite(float f);
0066 Q_CORE_EXPORT Q_DECL_CONST_FUNCTION int qFpClassify(float val);
0067 
0068 #if QT_CONFIG(signaling_nan)
0069 Q_CORE_EXPORT Q_DECL_CONST_FUNCTION double qSNaN();
0070 #endif
0071 Q_CORE_EXPORT Q_DECL_CONST_FUNCTION double qQNaN();
0072 Q_CORE_EXPORT Q_DECL_CONST_FUNCTION double qInf();
0073 
0074 Q_CORE_EXPORT quint32 qFloatDistance(float a, float b);
0075 Q_CORE_EXPORT quint64 qFloatDistance(double a, double b);
0076 
0077 #define Q_INFINITY (QT_PREPEND_NAMESPACE(qInf)())
0078 #if QT_CONFIG(signaling_nan)
0079 #  define Q_SNAN (QT_PREPEND_NAMESPACE(qSNaN)())
0080 #endif
0081 #define Q_QNAN (QT_PREPEND_NAMESPACE(qQNaN)())
0082 
0083 // Overflow math.
0084 // This provides efficient implementations for int, unsigned, qsizetype and
0085 // size_t. Implementations for 8- and 16-bit types will work but may not be as
0086 // efficient. Implementations for 64-bit may be missing on 32-bit platforms.
0087 
0088 #if (Q_CC_GNU >= 500 || __has_builtin(__builtin_add_overflow)) \
0089     && !(QT_POINTER_SIZE == 4 && defined(Q_CC_CLANG))
0090 // GCC 5 and Clang 3.8 have builtins to detect overflows
0091 // 32 bit Clang has the builtins but tries to link a library which hasn't
0092 #define Q_INTRINSIC_MUL_OVERFLOW64
0093 
0094 template <typename T> inline
0095 typename std::enable_if_t<std::is_unsigned_v<T> || std::is_signed_v<T>, bool>
0096 qAddOverflow(T v1, T v2, T *r)
0097 { return __builtin_add_overflow(v1, v2, r); }
0098 
0099 template <typename T> inline
0100 typename std::enable_if_t<std::is_unsigned_v<T> || std::is_signed_v<T>, bool>
0101 qSubOverflow(T v1, T v2, T *r)
0102 { return __builtin_sub_overflow(v1, v2, r); }
0103 
0104 template <typename T> inline
0105 typename std::enable_if_t<std::is_unsigned_v<T> || std::is_signed_v<T>, bool>
0106 qMulOverflow(T v1, T v2, T *r)
0107 { return __builtin_mul_overflow(v1, v2, r); }
0108 
0109 #else
0110 // Generic implementations
0111 
0112 template <typename T> inline typename std::enable_if_t<std::is_unsigned_v<T>, bool>
0113 qAddOverflow(T v1, T v2, T *r)
0114 {
0115     // unsigned additions are well-defined
0116     *r = v1 + v2;
0117     return v1 > T(v1 + v2);
0118 }
0119 
0120 template <typename T> inline typename std::enable_if_t<std::is_signed_v<T>, bool>
0121 qAddOverflow(T v1, T v2, T *r)
0122 {
0123     // Here's how we calculate the overflow:
0124     // 1) unsigned addition is well-defined, so we can always execute it
0125     // 2) conversion from unsigned back to signed is implementation-
0126     //    defined and in the implementations we use, it's a no-op.
0127     // 3) signed integer overflow happens if the sign of the two input operands
0128     //    is the same but the sign of the result is different. In other words,
0129     //    the sign of the result must be the same as the sign of either
0130     //    operand.
0131 
0132     using U = typename std::make_unsigned_t<T>;
0133     *r = T(U(v1) + U(v2));
0134 
0135     // If int is two's complement, assume all integer types are too.
0136     if (std::is_same_v<int32_t, int>) {
0137         // Two's complement equivalent (generates slightly shorter code):
0138         //  x ^ y             is negative if x and y have different signs
0139         //  x & y             is negative if x and y are negative
0140         // (x ^ z) & (y ^ z)  is negative if x and z have different signs
0141         //                    AND y and z have different signs
0142         return ((v1 ^ *r) & (v2 ^ *r)) < 0;
0143     }
0144 
0145     bool s1 = (v1 < 0);
0146     bool s2 = (v2 < 0);
0147     bool sr = (*r < 0);
0148     return s1 != sr && s2 != sr;
0149     // also: return s1 == s2 && s1 != sr;
0150 }
0151 
0152 template <typename T> inline typename std::enable_if_t<std::is_unsigned_v<T>, bool>
0153 qSubOverflow(T v1, T v2, T *r)
0154 {
0155     // unsigned subtractions are well-defined
0156     *r = v1 - v2;
0157     return v1 < v2;
0158 }
0159 
0160 template <typename T> inline typename std::enable_if_t<std::is_signed_v<T>, bool>
0161 qSubOverflow(T v1, T v2, T *r)
0162 {
0163     // See above for explanation. This is the same with some signs reversed.
0164     // We can't use qAddOverflow(v1, -v2, r) because it would be UB if
0165     // v2 == std::numeric_limits<T>::min().
0166 
0167     using U = typename std::make_unsigned_t<T>;
0168     *r = T(U(v1) - U(v2));
0169 
0170     if (std::is_same_v<int32_t, int>)
0171         return ((v1 ^ *r) & (~v2 ^ *r)) < 0;
0172 
0173     bool s1 = (v1 < 0);
0174     bool s2 = !(v2 < 0);
0175     bool sr = (*r < 0);
0176     return s1 != sr && s2 != sr;
0177     // also: return s1 == s2 && s1 != sr;
0178 }
0179 
0180 template <typename T> inline
0181 typename std::enable_if_t<std::is_unsigned_v<T> || std::is_signed_v<T>, bool>
0182 qMulOverflow(T v1, T v2, T *r)
0183 {
0184     // use the next biggest type
0185     // Note: for 64-bit systems where __int128 isn't supported, this will cause an error.
0186     using LargerInt = QIntegerForSize<sizeof(T) * 2>;
0187     using Larger = typename std::conditional_t<std::is_signed_v<T>,
0188             typename LargerInt::Signed, typename LargerInt::Unsigned>;
0189     Larger lr = Larger(v1) * Larger(v2);
0190     *r = T(lr);
0191     return lr > (std::numeric_limits<T>::max)() || lr < (std::numeric_limits<T>::min)();
0192 }
0193 
0194 # if defined(Q_INTRINSIC_MUL_OVERFLOW64)
0195 template <> inline bool qMulOverflow(quint64 v1, quint64 v2, quint64 *r)
0196 {
0197     *r = v1 * v2;
0198     return Q_UMULH(v1, v2);
0199 }
0200 template <> inline bool qMulOverflow(qint64 v1, qint64 v2, qint64 *r)
0201 {
0202     // This is slightly more complex than the unsigned case above: the sign bit
0203     // of 'low' must be replicated as the entire 'high', so the only valid
0204     // values for 'high' are 0 and -1. Use unsigned multiply since it's the same
0205     // as signed for the low bits and use a signed right shift to verify that
0206     // 'high' is nothing but sign bits that match the sign of 'low'.
0207 
0208     qint64 high = Q_SMULH(v1, v2);
0209     *r = qint64(quint64(v1) * quint64(v2));
0210     return (*r >> 63) != high;
0211 }
0212 
0213 #   if defined(Q_OS_INTEGRITY) && defined(Q_PROCESSOR_ARM_64)
0214 template <> inline bool qMulOverflow(uint64_t v1, uint64_t v2, uint64_t *r)
0215 {
0216     return qMulOverflow<quint64>(v1,v2,reinterpret_cast<quint64*>(r));
0217 }
0218 
0219 template <> inline bool qMulOverflow(int64_t v1, int64_t v2, int64_t *r)
0220 {
0221     return qMulOverflow<qint64>(v1,v2,reinterpret_cast<qint64*>(r));
0222 }
0223 #    endif // OS_INTEGRITY ARM64
0224 #  endif // Q_INTRINSIC_MUL_OVERFLOW64
0225 
0226 #  if defined(Q_CC_MSVC) && defined(Q_PROCESSOR_X86)
0227 // We can use intrinsics for the unsigned operations with MSVC
0228 template <> inline bool qAddOverflow(unsigned v1, unsigned v2, unsigned *r)
0229 { return _addcarry_u32(0, v1, v2, r); }
0230 
0231 // 32-bit qMulOverflow is fine with the generic code above
0232 
0233 template <> inline bool qAddOverflow(quint64 v1, quint64 v2, quint64 *r)
0234 {
0235 #    if defined(Q_PROCESSOR_X86_64)
0236     return _addcarry_u64(0, v1, v2, reinterpret_cast<unsigned __int64 *>(r));
0237 #    else
0238     uint low, high;
0239     uchar carry = _addcarry_u32(0, unsigned(v1), unsigned(v2), &low);
0240     carry = _addcarry_u32(carry, v1 >> 32, v2 >> 32, &high);
0241     *r = (quint64(high) << 32) | low;
0242     return carry;
0243 #    endif // !x86-64
0244 }
0245 #  endif // MSVC X86
0246 #endif // !GCC
0247 
0248 // Implementations for addition, subtraction or multiplication by a
0249 // compile-time constant. For addition and subtraction, we simply call the code
0250 // that detects overflow at runtime. For multiplication, we compare to the
0251 // maximum possible values before multiplying to ensure no overflow happens.
0252 
0253 template <typename T, T V2> bool qAddOverflow(T v1, std::integral_constant<T, V2>, T *r)
0254 {
0255     return qAddOverflow(v1, V2, r);
0256 }
0257 
0258 template <auto V2, typename T> bool qAddOverflow(T v1, T *r)
0259 {
0260     return qAddOverflow(v1, std::integral_constant<T, V2>{}, r);
0261 }
0262 
0263 template <typename T, T V2> bool qSubOverflow(T v1, std::integral_constant<T, V2>, T *r)
0264 {
0265     return qSubOverflow(v1, V2, r);
0266 }
0267 
0268 template <auto V2, typename T> bool qSubOverflow(T v1, T *r)
0269 {
0270     return qSubOverflow(v1, std::integral_constant<T, V2>{}, r);
0271 }
0272 
0273 template <typename T, T V2> bool qMulOverflow(T v1, std::integral_constant<T, V2>, T *r)
0274 {
0275     // Runtime detection for anything smaller than or equal to a register
0276     // width, as most architectures' multiplication instructions actually
0277     // produce a result twice as wide as the input registers, allowing us to
0278     // efficiently detect the overflow.
0279     if constexpr (sizeof(T) <= sizeof(qregisteruint)) {
0280         return qMulOverflow(v1, V2, r);
0281 
0282 #ifdef Q_INTRINSIC_MUL_OVERFLOW64
0283     } else if constexpr (sizeof(T) <= sizeof(quint64)) {
0284         // If we have intrinsics detecting overflow of 64-bit multiplications,
0285         // then detect overflows through them up to 64 bits.
0286         return qMulOverflow(v1, V2, r);
0287 #endif
0288 
0289     } else if constexpr (V2 == 0 || V2 == 1) {
0290         // trivial cases (and simplify logic below due to division by zero)
0291         *r = v1 * V2;
0292         return false;
0293     } else if constexpr (V2 == -1) {
0294         // multiplication by -1 is valid *except* for signed minimum values
0295         // (necessary to avoid diving min() by -1, which is an overflow)
0296         if (v1 < 0 && v1 == (std::numeric_limits<T>::min)())
0297             return true;
0298         *r = -v1;
0299         return false;
0300     } else {
0301         // For 64-bit multiplications on 32-bit platforms, let's instead compare v1
0302         // against the bounds that would overflow.
0303         constexpr T Highest = (std::numeric_limits<T>::max)() / V2;
0304         constexpr T Lowest = (std::numeric_limits<T>::min)() / V2;
0305         if constexpr (Highest > Lowest) {
0306             if (v1 > Highest || v1 < Lowest)
0307                 return true;
0308         } else {
0309             // this can only happen if V2 < 0
0310             static_assert(V2 < 0);
0311             if (v1 > Lowest || v1 < Highest)
0312                 return true;
0313         }
0314 
0315         *r = v1 * V2;
0316         return false;
0317     }
0318 }
0319 
0320 template <auto V2, typename T> bool qMulOverflow(T v1, T *r)
0321 {
0322     if constexpr (V2 == 2)
0323         return qAddOverflow(v1, v1, r);
0324     return qMulOverflow(v1, std::integral_constant<T, V2>{}, r);
0325 }
0326 
0327 template <typename T>
0328 constexpr inline T qAbs(const T &t) { return t >= 0 ? t : -t; }
0329 
0330 // gcc < 10 doesn't have __has_builtin
0331 #if defined(Q_PROCESSOR_ARM_64) && (__has_builtin(__builtin_round) || defined(Q_CC_GNU)) && !defined(Q_CC_CLANG)
0332 // ARM64 has a single instruction that can do C++ rounding with conversion to integer.
0333 // Note current clang versions have non-constexpr __builtin_round, ### allow clang this path when they fix it.
0334 constexpr inline int qRound(double d)
0335 { return int(__builtin_round(d)); }
0336 constexpr inline int qRound(float f)
0337 { return int(__builtin_roundf(f)); }
0338 constexpr inline qint64 qRound64(double d)
0339 { return qint64(__builtin_round(d)); }
0340 constexpr inline qint64 qRound64(float f)
0341 { return qint64(__builtin_roundf(f)); }
0342 #elif defined(__SSE2__) && (__has_builtin(__builtin_copysign) || defined(Q_CC_GNU))
0343 // SSE has binary operations directly on floating point making copysign fast
0344 constexpr inline int qRound(double d)
0345 { return int(d + __builtin_copysign(0.5, d)); }
0346 constexpr inline int qRound(float f)
0347 { return int(f + __builtin_copysignf(0.5f, f)); }
0348 constexpr inline qint64 qRound64(double d)
0349 { return qint64(d + __builtin_copysign(0.5, d)); }
0350 constexpr inline qint64 qRound64(float f)
0351 { return qint64(f + __builtin_copysignf(0.5f, f)); }
0352 #else
0353 constexpr inline int qRound(double d)
0354 { return d >= 0.0 ? int(d + 0.5) : int(d - 0.5); }
0355 constexpr inline int qRound(float d)
0356 { return d >= 0.0f ? int(d + 0.5f) : int(d - 0.5f); }
0357 
0358 constexpr inline qint64 qRound64(double d)
0359 { return d >= 0.0 ? qint64(d + 0.5) : qint64(d - 0.5); }
0360 constexpr inline qint64 qRound64(float d)
0361 { return d >= 0.0f ? qint64(d + 0.5f) : qint64(d - 0.5f); }
0362 #endif
0363 
0364 namespace QtPrivate {
0365 template <typename T>
0366 constexpr inline const T &min(const T &a, const T &b) { return (a < b) ? a : b; }
0367 }
0368 
0369 [[nodiscard]] constexpr bool qFuzzyCompare(double p1, double p2)
0370 {
0371     return (qAbs(p1 - p2) * 1000000000000. <= QtPrivate::min(qAbs(p1), qAbs(p2)));
0372 }
0373 
0374 [[nodiscard]] constexpr bool qFuzzyCompare(float p1, float p2)
0375 {
0376     return (qAbs(p1 - p2) * 100000.f <= QtPrivate::min(qAbs(p1), qAbs(p2)));
0377 }
0378 
0379 [[nodiscard]] constexpr bool qFuzzyIsNull(double d)
0380 {
0381     return qAbs(d) <= 0.000000000001;
0382 }
0383 
0384 [[nodiscard]] constexpr bool qFuzzyIsNull(float f)
0385 {
0386     return qAbs(f) <= 0.00001f;
0387 }
0388 
0389 QT_WARNING_PUSH
0390 QT_WARNING_DISABLE_FLOAT_COMPARE
0391 
0392 [[nodiscard]] constexpr bool qIsNull(double d) noexcept
0393 {
0394     return d == 0.0;
0395 }
0396 
0397 [[nodiscard]] constexpr bool qIsNull(float f) noexcept
0398 {
0399     return f == 0.0f;
0400 }
0401 
0402 QT_WARNING_POP
0403 
0404 inline int qIntCast(double f) { return int(f); }
0405 inline int qIntCast(float f) { return int(f); }
0406 
0407 QT_END_NAMESPACE
0408 
0409 #endif // QNUMERIC_H