diff options
Diffstat (limited to 'src/corelib/global/qnumeric_p.h')
-rw-r--r-- | src/corelib/global/qnumeric_p.h | 35 |
1 files changed, 35 insertions, 0 deletions
diff --git a/src/corelib/global/qnumeric_p.h b/src/corelib/global/qnumeric_p.h index 7c65b67b7a..f5beb4d38d 100644 --- a/src/corelib/global/qnumeric_p.h +++ b/src/corelib/global/qnumeric_p.h @@ -314,6 +314,41 @@ template <auto V2, typename T> bool mul_overflow(T v1, T *r) } #endif // Q_CLANG_QDOC +/* + Safely narrows \a x to \c{To}. Let \c L be + \c{std::numeric_limit<To>::min()} and \c H be \c{std::numeric_limit<To>::max()}. + + If \a x is less than L, returns L. If \a x is greater than H, + returns H. Otherwise, returns \c{To(x)}. +*/ +template <typename To, typename From> +static constexpr auto qt_saturate(From x) +{ + static_assert(std::is_integral_v<To>); + static_assert(std::is_integral_v<From>); + + [[maybe_unused]] + constexpr auto Lo = (std::numeric_limits<To>::min)(); + constexpr auto Hi = (std::numeric_limits<To>::max)(); + + if constexpr (std::is_signed_v<From> == std::is_signed_v<To>) { + // same signedness, we can accept regular integer conversion rules + return x < Lo ? Lo : + x > Hi ? Hi : + /*else*/ To(x); + } else { + if constexpr (std::is_signed_v<From>) { // ie. !is_signed_v<To> + if (x < From{0}) + return To{0}; + } + + // from here on, x >= 0 + using FromU = std::make_unsigned_t<From>; + using ToU = std::make_unsigned_t<To>; + return FromU(x) > ToU(Hi) ? Hi : To(x); // assumes Hi >= 0 + } +} + QT_END_NAMESPACE #endif // QNUMERIC_P_H |