From 7cb5b324f05b3d9e530856bd0eb2ddf4e34b2f55 Mon Sep 17 00:00:00 2001 From: Thiago Macieira Date: Sat, 14 Jul 2018 16:42:08 -0700 Subject: QCborValue: move the toDiagnosticNotation() function to its own file MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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 Reviewed-by: Edward Welbourne --- src/corelib/global/qnumeric_p.h | 52 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 52 insertions(+) (limited to 'src/corelib/global/qnumeric_p.h') 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 static inline bool convertDoubleTo(double v, T *value) +{ + Q_STATIC_ASSERT(std::numeric_limits::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::is_signed) { + supremum = -1.0 * std::numeric_limits::min(); // -1 * (-2^63) = 2^63, exact (for T = qint64) + *value = std::numeric_limits::min(); + if (v < std::numeric_limits::min()) + return false; + } else { + using ST = typename std::make_signed::type; + supremum = -2.0 * std::numeric_limits::min(); // -2 * (-2^63) = 2^64, exact (for T = quint64) + v = fabs(v); + } + + *value = std::numeric_limits::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 -- cgit v1.2.3