diff options
author | Thiago Macieira <thiago.macieira@intel.com> | 2018-07-14 16:42:08 -0700 |
---|---|---|
committer | Thiago Macieira <thiago.macieira@intel.com> | 2018-07-30 16:21:12 +0000 |
commit | 7cb5b324f05b3d9e530856bd0eb2ddf4e34b2f55 (patch) | |
tree | a96c2af38e7a2ef58b4acf3a4cd77cdfc60d53f8 /src/corelib/global/qnumeric_p.h | |
parent | 3cd9d6d19bc61f0b4e5228196e058bac5fd37ba3 (diff) |
QCborValue: move the toDiagnosticNotation() function to its own file
If we ever need to add QCborValue to the bootstrap library, it's
unlikely that we'll need this part. And by splitting it, I can make the
code handle more cases, that hadn't been properly handled before.
Change-Id: I2f630efbbce54f14bfa9fffd154160c0ad893695
Reviewed-by: MÃ¥rten Nordheim <marten.nordheim@qt.io>
Reviewed-by: Edward Welbourne <edward.welbourne@qt.io>
Diffstat (limited to 'src/corelib/global/qnumeric_p.h')
-rw-r--r-- | src/corelib/global/qnumeric_p.h | 52 |
1 files changed, 52 insertions, 0 deletions
diff --git a/src/corelib/global/qnumeric_p.h b/src/corelib/global/qnumeric_p.h index 5f8a124bcc..9c8514f5a3 100644 --- a/src/corelib/global/qnumeric_p.h +++ b/src/corelib/global/qnumeric_p.h @@ -163,6 +163,58 @@ Q_DECL_CONST_FUNCTION static inline bool qt_is_finite(float f) #ifndef Q_CLANG_QDOC namespace { +/*! + Returns true if the double \a v can be converted to type \c T, false if + it's out of range. If the conversion is successful, the converted value is + stored in \a value; if it was not successful, \a value will contain the + minimum or maximum of T, depending on the sign of \a d. If \c T is + unsigned, then \a value contains the absolute value of \a v. + + This function works for v containing infinities, but not NaN. It's the + caller's responsibility to exclude that possibility before calling it. +*/ +template <typename T> static inline bool convertDoubleTo(double v, T *value) +{ + Q_STATIC_ASSERT(std::numeric_limits<T>::is_integer); + + // The [conv.fpint] (7.10 Floating-integral conversions) section of the C++ + // standard says only exact conversions are guaranteed. Converting + // integrals to floating-point with loss of precision has implementation- + // defined behavior whether the next higher or next lower is returned; + // converting FP to integral is UB if it can't be represented. + // + // That means we can't write UINT64_MAX+1. Writing ldexp(1, 64) would be + // correct, but Clang, ICC and MSVC don't realize that it's a constant and + // the math call stays in the compiled code. + + double supremum; + if (std::numeric_limits<T>::is_signed) { + supremum = -1.0 * std::numeric_limits<T>::min(); // -1 * (-2^63) = 2^63, exact (for T = qint64) + *value = std::numeric_limits<T>::min(); + if (v < std::numeric_limits<T>::min()) + return false; + } else { + using ST = typename std::make_signed<T>::type; + supremum = -2.0 * std::numeric_limits<ST>::min(); // -2 * (-2^63) = 2^64, exact (for T = quint64) + v = fabs(v); + } + + *value = std::numeric_limits<T>::max(); + if (v >= supremum) + return false; + + // Now we can convert, these two conversions cannot be UB + *value = T(v); + +QT_WARNING_PUSH +QT_WARNING_DISABLE_GCC("-Wfloat-equal") +QT_WARNING_DISABLE_CLANG("-Wfloat-equal") + + return *value == v; + +QT_WARNING_POP +} + // Overflow math. // This provides efficient implementations for int, unsigned, qsizetype and // size_t. Implementations for 8- and 16-bit types will work but may not be as |