From a99d73c53af665250f6c41f140dd36e1ea158519 Mon Sep 17 00:00:00 2001 From: Giuseppe D'Angelo Date: Thu, 3 Apr 2025 12:14:54 +0200 Subject: [PATCH] qCheckedFPConversionToInteger: streamline the checks Use the same algorithm as convertToDouble. We don't really need convertToDouble, as we plan to truncate anyhow (convertToDouble returns `false` if truncation caused loss of precision, so we can't use it to distinguish an out-of-bounds value), and these are debug-only checks. Change-Id: I70d70c05ce3f4996bd74361e6f78c02064232a57 Reviewed-by: Thiago Macieira --- src/corelib/global/qnumeric.h | 30 +++++++++++++++++++----------- 1 file changed, 19 insertions(+), 11 deletions(-) diff --git a/src/corelib/global/qnumeric.h b/src/corelib/global/qnumeric.h index b1d5f291306..836a2ac0082 100644 --- a/src/corelib/global/qnumeric.h +++ b/src/corelib/global/qnumeric.h @@ -494,19 +494,27 @@ template , bool> = true> constexpr inline Result qCheckedFPConversionToInteger(FP value) { - // GCC always has constexpr cmath -#if !defined(__cpp_lib_constexpr_cmath) && !defined(Q_CC_GNU_ONLY) -# ifdef QT_SUPPORTS_IS_CONSTANT_EVALUATED +#ifdef QT_SUPPORTS_IS_CONSTANT_EVALUATED if (!q20::is_constant_evaluated()) -# else - if (false) -# endif + Q_ASSERT(!std::isnan(value)); #endif - { - const FP truncatedValue = std::trunc(value); - Q_ASSERT(truncatedValue >= FP((std::numeric_limits::min)())); - Q_ASSERT(truncatedValue <= FP((std::numeric_limits::max)())); - } + + constexpr Result minimal = (std::numeric_limits::min)(); + constexpr Result maximal = (std::numeric_limits::max)(); + + // We want to check that `value > minimal-1`. `minimal` is + // precisely representable as FP (it's -2^N), but `minimal-1` + // may not be. Just rearrange the terms: + Q_ASSERT(value - FP(minimal) > FP(-1)); + + // Symmetrically, `maximal` may not have a precise + // representation, but `maximal+1` has, so calculate that: + constexpr FP maximalPlusOne = FP(2) * (maximal / 2 + 1); + // And check that we're below that: + Q_ASSERT(value < maximalPlusOne); + + // If both checks passed, the result of truncation is representable + // as `Result`: return Result(value); }