1// Copyright (C) 2020 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3
4#ifndef QJSNUMBERCOERCION_H
5#define QJSNUMBERCOERCION_H
6
7#include <QtCore/qglobal.h>
8#include <cstring>
9
10QT_BEGIN_NAMESPACE
11
12class QJSNumberCoercion
13{
14public:
15
16#if QT_DEPRECATED_SINCE(6, 7)
17
18 QT_DEPRECATED_VERSION_6_7
19 static constexpr bool isInteger(double d)
20 {
21 // Comparing d with itself checks for NaN and comparing d with the min and max values
22 // for int also covers infinities.
23 if (!equals(lhs: d, rhs: d) || d < std::numeric_limits<int>::min()
24 || d > std::numeric_limits<int>::max()) {
25 return false;
26 }
27
28 return equals(lhs: static_cast<int>(d), rhs: d);
29 }
30
31#endif
32
33 static constexpr bool isArrayIndex(double d)
34 {
35 if (d < 0 || !equals(lhs: d, rhs: d) || d > std::numeric_limits<int>::max()) {
36 return false;
37 }
38
39 return equals(lhs: static_cast<int>(d), rhs: d);
40 }
41
42 static constexpr int toInteger(double d) {
43 // Check for NaN
44 if (!equals(lhs: d, rhs: d))
45 return 0;
46
47 if (d >= std::numeric_limits<int>::min() && d <= std::numeric_limits<int>::max()) {
48 const int i = static_cast<int>(d);
49 if (equals(lhs: i, rhs: d))
50 return i;
51 }
52
53 return QJSNumberCoercion(d).toInteger();
54 }
55
56 static constexpr bool equals(double lhs, double rhs)
57 {
58 QT_WARNING_PUSH
59 QT_WARNING_DISABLE_FLOAT_COMPARE
60 return lhs == rhs;
61 QT_WARNING_POP
62 }
63
64private:
65 constexpr QJSNumberCoercion(double dbl)
66 {
67 // the dbl == 0 path is guaranteed constexpr. The other one may or may not be, depending
68 // on whether and how the compiler inlines the memcpy.
69 // In order to declare the ctor constexpr we need one guaranteed constexpr path.
70 if (!equals(lhs: dbl, rhs: 0))
71 memcpy(dest: &d, src: &dbl, n: sizeof(double));
72 }
73
74 constexpr int sign() const
75 {
76 return (d >> 63) ? -1 : 1;
77 }
78
79 constexpr bool isDenormal() const
80 {
81 return static_cast<int>((d << 1) >> 53) == 0;
82 }
83
84 constexpr int exponent() const
85 {
86 return static_cast<int>((d << 1) >> 53) - 1023;
87 }
88
89 constexpr quint64 significant() const
90 {
91 quint64 m = (d << 12) >> 12;
92 if (!isDenormal())
93 m |= (static_cast<quint64>(1) << 52);
94 return m;
95 }
96
97 constexpr int toInteger()
98 {
99 int e = exponent() - 52;
100 if (e < 0) {
101 if (e <= -53)
102 return 0;
103 return sign() * static_cast<int>(significant() >> -e);
104 } else {
105 if (e > 31)
106 return 0;
107 return sign() * (static_cast<int>(significant()) << e);
108 }
109 }
110
111 quint64 d = 0;
112};
113
114QT_END_NAMESPACE
115
116#endif // QJSNUMBERCOERCION_H
117

source code of qtdeclarative/src/qml/common/qjsnumbercoercion.h