1/****************************************************************************
2**
3** Copyright (C) 2020 The Qt Company Ltd.
4** Copyright (C) 2020 Intel Corporation.
5** Contact: https://www.qt.io/licensing/
6**
7** This file is part of the QtCore module of the Qt Toolkit.
8**
9** $QT_BEGIN_LICENSE:LGPL$
10** Commercial License Usage
11** Licensees holding valid commercial Qt licenses may use this file in
12** accordance with the commercial license agreement provided with the
13** Software or, alternatively, in accordance with the terms contained in
14** a written agreement between you and The Qt Company. For licensing terms
15** and conditions see https://www.qt.io/terms-conditions. For further
16** information use the contact form at https://www.qt.io/contact-us.
17**
18** GNU Lesser General Public License Usage
19** Alternatively, this file may be used under the terms of the GNU Lesser
20** General Public License version 3 as published by the Free Software
21** Foundation and appearing in the file LICENSE.LGPL3 included in the
22** packaging of this file. Please review the following information to
23** ensure the GNU Lesser General Public License version 3 requirements
24** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
25**
26** GNU General Public License Usage
27** Alternatively, this file may be used under the terms of the GNU
28** General Public License version 2.0 or (at your option) the GNU General
29** Public license version 3 or any later version approved by the KDE Free
30** Qt Foundation. The licenses are as published by the Free Software
31** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
32** included in the packaging of this file. Please review the following
33** information to ensure the GNU General Public License requirements will
34** be met: https://www.gnu.org/licenses/gpl-2.0.html and
35** https://www.gnu.org/licenses/gpl-3.0.html.
36**
37** $QT_END_LICENSE$
38**
39****************************************************************************/
40
41#ifndef QNUMERIC_P_H
42#define QNUMERIC_P_H
43
44//
45// W A R N I N G
46// -------------
47//
48// This file is not part of the Qt API. It exists purely as an
49// implementation detail. This header file may change from version to
50// version without notice, or even be removed.
51//
52// We mean it.
53//
54
55#include "QtCore/private/qglobal_p.h"
56#include "QtCore/qnumeric.h"
57#include <cmath>
58#include <limits>
59#include <type_traits>
60
61#if !defined(Q_CC_MSVC) && (defined(Q_OS_QNX) || defined(Q_CC_INTEL))
62# include <math.h>
63# ifdef isnan
64# define QT_MATH_H_DEFINES_MACROS
65QT_BEGIN_NAMESPACE
66namespace qnumeric_std_wrapper {
67// the 'using namespace std' below is cases where the stdlib already put the math.h functions in the std namespace and undefined the macros.
68Q_DECL_CONST_FUNCTION static inline bool math_h_isnan(double d) { using namespace std; return isnan(d); }
69Q_DECL_CONST_FUNCTION static inline bool math_h_isinf(double d) { using namespace std; return isinf(d); }
70Q_DECL_CONST_FUNCTION static inline bool math_h_isfinite(double d) { using namespace std; return isfinite(d); }
71Q_DECL_CONST_FUNCTION static inline int math_h_fpclassify(double d) { using namespace std; return fpclassify(d); }
72Q_DECL_CONST_FUNCTION static inline bool math_h_isnan(float f) { using namespace std; return isnan(f); }
73Q_DECL_CONST_FUNCTION static inline bool math_h_isinf(float f) { using namespace std; return isinf(f); }
74Q_DECL_CONST_FUNCTION static inline bool math_h_isfinite(float f) { using namespace std; return isfinite(f); }
75Q_DECL_CONST_FUNCTION static inline int math_h_fpclassify(float f) { using namespace std; return fpclassify(f); }
76}
77QT_END_NAMESPACE
78// These macros from math.h conflict with the real functions in the std namespace.
79# undef signbit
80# undef isnan
81# undef isinf
82# undef isfinite
83# undef fpclassify
84# endif // defined(isnan)
85#endif
86
87QT_BEGIN_NAMESPACE
88
89namespace qnumeric_std_wrapper {
90#if defined(QT_MATH_H_DEFINES_MACROS)
91# undef QT_MATH_H_DEFINES_MACROS
92Q_DECL_CONST_FUNCTION static inline bool isnan(double d) { return math_h_isnan(d); }
93Q_DECL_CONST_FUNCTION static inline bool isinf(double d) { return math_h_isinf(d); }
94Q_DECL_CONST_FUNCTION static inline bool isfinite(double d) { return math_h_isfinite(d); }
95Q_DECL_CONST_FUNCTION static inline int fpclassify(double d) { return math_h_fpclassify(d); }
96Q_DECL_CONST_FUNCTION static inline bool isnan(float f) { return math_h_isnan(f); }
97Q_DECL_CONST_FUNCTION static inline bool isinf(float f) { return math_h_isinf(f); }
98Q_DECL_CONST_FUNCTION static inline bool isfinite(float f) { return math_h_isfinite(f); }
99Q_DECL_CONST_FUNCTION static inline int fpclassify(float f) { return math_h_fpclassify(f); }
100#else
101Q_DECL_CONST_FUNCTION static inline bool isnan(double d) { return std::isnan(d); }
102Q_DECL_CONST_FUNCTION static inline bool isinf(double d) { return std::isinf(d); }
103Q_DECL_CONST_FUNCTION static inline bool isfinite(double d) { return std::isfinite(d); }
104Q_DECL_CONST_FUNCTION static inline int fpclassify(double d) { return std::fpclassify(d); }
105Q_DECL_CONST_FUNCTION static inline bool isnan(float f) { return std::isnan(f); }
106Q_DECL_CONST_FUNCTION static inline bool isinf(float f) { return std::isinf(f); }
107Q_DECL_CONST_FUNCTION static inline bool isfinite(float f) { return std::isfinite(f); }
108Q_DECL_CONST_FUNCTION static inline int fpclassify(float f) { return std::fpclassify(f); }
109#endif
110}
111
112constexpr Q_DECL_CONST_FUNCTION static inline double qt_inf() noexcept
113{
114 static_assert(std::numeric_limits<double>::has_infinity,
115 "platform has no definition for infinity for type double");
116 return std::numeric_limits<double>::infinity();
117}
118
119#if QT_CONFIG(signaling_nan)
120constexpr Q_DECL_CONST_FUNCTION static inline double qt_snan() noexcept
121{
122 static_assert(std::numeric_limits<double>::has_signaling_NaN,
123 "platform has no definition for signaling NaN for type double");
124 return std::numeric_limits<double>::signaling_NaN();
125}
126#endif
127
128// Quiet NaN
129constexpr Q_DECL_CONST_FUNCTION static inline double qt_qnan() noexcept
130{
131 static_assert(std::numeric_limits<double>::has_quiet_NaN,
132 "platform has no definition for quiet NaN for type double");
133 return std::numeric_limits<double>::quiet_NaN();
134}
135
136Q_DECL_CONST_FUNCTION static inline bool qt_is_inf(double d)
137{
138 return qnumeric_std_wrapper::isinf(d);
139}
140
141Q_DECL_CONST_FUNCTION static inline bool qt_is_nan(double d)
142{
143 return qnumeric_std_wrapper::isnan(d);
144}
145
146Q_DECL_CONST_FUNCTION static inline bool qt_is_finite(double d)
147{
148 return qnumeric_std_wrapper::isfinite(d);
149}
150
151Q_DECL_CONST_FUNCTION static inline int qt_fpclassify(double d)
152{
153 return qnumeric_std_wrapper::fpclassify(d);
154}
155
156Q_DECL_CONST_FUNCTION static inline bool qt_is_inf(float f)
157{
158 return qnumeric_std_wrapper::isinf(f);
159}
160
161Q_DECL_CONST_FUNCTION static inline bool qt_is_nan(float f)
162{
163 return qnumeric_std_wrapper::isnan(f);
164}
165
166Q_DECL_CONST_FUNCTION static inline bool qt_is_finite(float f)
167{
168 return qnumeric_std_wrapper::isfinite(f);
169}
170
171Q_DECL_CONST_FUNCTION static inline int qt_fpclassify(float f)
172{
173 return qnumeric_std_wrapper::fpclassify(f);
174}
175
176#ifndef Q_CLANG_QDOC
177namespace {
178/*!
179 Returns true if the double \a v can be converted to type \c T, false if
180 it's out of range. If the conversion is successful, the converted value is
181 stored in \a value; if it was not successful, \a value will contain the
182 minimum or maximum of T, depending on the sign of \a d. If \c T is
183 unsigned, then \a value contains the absolute value of \a v.
184
185 This function works for v containing infinities, but not NaN. It's the
186 caller's responsibility to exclude that possibility before calling it.
187*/
188template<typename T>
189static inline bool convertDoubleTo(double v, T *value, bool allow_precision_upgrade = true)
190{
191 static_assert(std::numeric_limits<T>::is_integer);
192
193 // The [conv.fpint] (7.10 Floating-integral conversions) section of the C++
194 // standard says only exact conversions are guaranteed. Converting
195 // integrals to floating-point with loss of precision has implementation-
196 // defined behavior whether the next higher or next lower is returned;
197 // converting FP to integral is UB if it can't be represented.
198 //
199 // That means we can't write UINT64_MAX+1. Writing ldexp(1, 64) would be
200 // correct, but Clang, ICC and MSVC don't realize that it's a constant and
201 // the math call stays in the compiled code.
202
203 double supremum;
204 if (std::numeric_limits<T>::is_signed) {
205 supremum = -1.0 * std::numeric_limits<T>::min(); // -1 * (-2^63) = 2^63, exact (for T = qint64)
206 *value = std::numeric_limits<T>::min();
207 if (v < std::numeric_limits<T>::min())
208 return false;
209 } else {
210 using ST = typename std::make_signed<T>::type;
211 supremum = -2.0 * std::numeric_limits<ST>::min(); // -2 * (-2^63) = 2^64, exact (for T = quint64)
212 v = fabs(v);
213 }
214 if (std::is_integral<T>::value && sizeof(T) > 4 && !allow_precision_upgrade) {
215 if (v > double(Q_INT64_C(1)<<53) || v < double(-((Q_INT64_C(1)<<53) + 1)))
216 return false;
217 }
218
219 *value = std::numeric_limits<T>::max();
220 if (v >= supremum)
221 return false;
222
223 // Now we can convert, these two conversions cannot be UB
224 *value = T(v);
225
226QT_WARNING_PUSH
227QT_WARNING_DISABLE_FLOAT_COMPARE
228
229 return *value == v;
230
231QT_WARNING_POP
232}
233
234template <typename T> inline bool add_overflow(T v1, T v2, T *r) { return qAddOverflow(v1, v2, r); }
235template <typename T> inline bool sub_overflow(T v1, T v2, T *r) { return qSubOverflow(v1, v2, r); }
236template <typename T> inline bool mul_overflow(T v1, T v2, T *r) { return qMulOverflow(v1, v2, r); }
237
238template <typename T, T V2> bool add_overflow(T v1, std::integral_constant<T, V2>, T *r)
239{
240 return qAddOverflow<T, V2>(v1, std::integral_constant<T, V2>{}, r);
241}
242
243template <auto V2, typename T> bool add_overflow(T v1, T *r)
244{
245 return qAddOverflow<V2, T>(v1, r);
246}
247
248template <typename T, T V2> bool sub_overflow(T v1, std::integral_constant<T, V2>, T *r)
249{
250 return qSubOverflow<T, V2>(v1, std::integral_constant<T, V2>{}, r);
251}
252
253template <auto V2, typename T> bool sub_overflow(T v1, T *r)
254{
255 return qSubOverflow<V2, T>(v1, r);
256}
257
258template <typename T, T V2> bool mul_overflow(T v1, std::integral_constant<T, V2>, T *r)
259{
260 return qMulOverflow<T, V2>(v1, std::integral_constant<T, V2>{}, r);
261}
262
263template <auto V2, typename T> bool mul_overflow(T v1, T *r)
264{
265 return qMulOverflow<V2, T>(v1, r);
266}
267}
268#endif // Q_CLANG_QDOC
269
270QT_END_NAMESPACE
271
272#endif // QNUMERIC_P_H
273

source code of qtbase/src/corelib/global/qnumeric_p.h