• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /**
2  * Copyright (c) 2021-2022 Huawei Device Co., Ltd.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  * http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 
16 #ifndef ECMASCRIPT_BASE_MATH_HELPER_H
17 #define ECMASCRIPT_BASE_MATH_HELPER_H
18 
19 #include <cstdint>
20 #include <cmath>
21 
22 #include "ecmascript/base/bit_helper.h"
23 
24 #define panda_bit_utils_ctz __builtin_ctz      // NOLINT(cppcoreguidelines-macro-usage)
25 #define panda_bit_utils_ctzll __builtin_ctzll  // NOLINT(cppcoreguidelines-macro-usage)
26 
27 namespace panda::ecmascript::base {
28 class MathHelper {
29 public:
GetIntLog2(const uint32_t X)30     static constexpr uint32_t GetIntLog2(const uint32_t X)
31     {
32         return static_cast<uint32_t>(panda_bit_utils_ctz(X));
33     }
34 
GetIntLog2(const uint64_t X)35     static constexpr uint64_t GetIntLog2(const uint64_t X)
36     {
37         return static_cast<uint64_t>(panda_bit_utils_ctzll(X));
38     }
39 
Asinh(double input)40     static double Asinh(double input)
41     {
42 #if defined(PANDA_TARGET_WINDOWS)
43         if (input == 0 && !std::signbit(input)) {
44             // +0.0(double) is the special case for std::asinh() function compiled in linux for windows.
45             return +0.0;
46         }
47 #endif
48         return std::asinh(input);
49     }
50 
Atanh(double input)51     static inline double Atanh(double input)
52     {
53 #if defined(PANDA_TARGET_WINDOWS)
54         if (input == 0 && std::signbit(input)) {
55             // -0.0(double) is the special case for std::atanh() function compiled in linux for windows.
56             return -0.0;
57         }
58 #endif
59         return std::atanh(input);
60     }
61 };
62 
63 template <typename T, typename = typename std::enable_if<std::is_integral<T>::value>::type>
WhichPowerOfTwo(T value)64 inline constexpr int WhichPowerOfTwo(T value)
65 {
66     // Ensure the size of the integer is no more than 8 bytes (64 bits).
67     static_assert(sizeof(T) <= 8);
68     // Use __builtin_ctzll for 8 bytes (64 bits) and __builtin_ctz for 32-bit integers.
69     return sizeof(T) == 8 ? __builtin_ctzll(static_cast<uint64_t>(value)) : __builtin_ctz(static_cast<uint32_t>(value));
70 }
71 
72 
SignedDiv32(int32_t lhs,int32_t rhs)73 inline int32_t SignedDiv32(int32_t lhs, int32_t rhs)
74 {
75     if (rhs == 0) {
76         return 0;
77     }
78     if (rhs == -1) {
79         return lhs == std::numeric_limits<int32_t>::min() ? lhs : -lhs;
80     }
81     return lhs / rhs;
82 }
83 
SignedDiv64(int64_t lhs,int64_t rhs)84 inline int64_t SignedDiv64(int64_t lhs, int64_t rhs)
85 {
86     if (rhs == 0) {
87         return 0;
88     }
89     if (rhs == -1) {
90         return lhs == std::numeric_limits<int64_t>::min() ? lhs : -lhs;
91     }
92     return lhs / rhs;
93 }
94 
SignedMod32(int32_t lhs,int32_t rhs)95 inline int32_t SignedMod32(int32_t lhs, int32_t rhs)
96 {
97     if (rhs == 0 || rhs == -1) {
98         return 0;
99     }
100     return lhs % rhs;
101 }
102 
103 
SignedAddOverflow32(int32_t lhs,int32_t rhs,int32_t * val)104 inline bool SignedAddOverflow32(int32_t lhs, int32_t rhs, int32_t *val)
105 {
106     uint32_t res = static_cast<uint32_t>(lhs) + static_cast<uint32_t>(rhs);
107     *val = base::bit_cast<int32_t>(res);
108     // Check for overflow by examining the sign bit.(bit 31 in a 32-bit integer)
109     return ((res ^ static_cast<uint32_t>(lhs)) & (res ^ static_cast<uint32_t>(rhs)) & (1U << 31)) != 0;
110 }
111 
112 
SignedSubOverflow32(int32_t lhs,int32_t rhs,int32_t * val)113 inline bool SignedSubOverflow32(int32_t lhs, int32_t rhs, int32_t *val)
114 {
115     uint32_t res = static_cast<uint32_t>(lhs) - static_cast<uint32_t>(rhs);
116     *val = base::bit_cast<int32_t>(res);
117     // Check for overflow by examining the sign bit.(bit 31 in a 32-bit integer)
118     return ((res ^ static_cast<uint32_t>(lhs)) & (res ^ ~static_cast<uint32_t>(rhs)) & (1U << 31)) != 0;
119 }
120 
SignedMulOverflow32(int32_t lhs,int32_t rhs,int32_t * val)121 inline bool SignedMulOverflow32(int32_t lhs, int32_t rhs, int32_t *val)
122 {
123     int64_t result = int64_t{lhs} * int64_t{rhs};
124     *val = static_cast<int32_t>(result);
125     using limits = std::numeric_limits<int32_t>;
126     return result < limits::min() || result > limits::max();
127 }
128 
129 
130 // Returns the quotient x/y, avoiding C++ undefined behavior if y == 0.
131 template <typename T>
Divide(T x,T y)132 inline T Divide(T x, T y)
133 {
134     if (y != 0) {
135         return x / y;
136     }
137     if (x == 0 || x != x) {
138         return std::numeric_limits<T>::quiet_NaN();
139     }
140     if ((x >= 0) == (std::signbit(y) == 0)) {
141         return std::numeric_limits<T>::infinity();
142     }
143     return -std::numeric_limits<T>::infinity();
144 }
145 
146 
147 template <typename SignedType>
AddWithWraparound(SignedType a,SignedType b)148 inline SignedType AddWithWraparound(SignedType a, SignedType b)
149 {
150     static_assert(std::is_integral<SignedType>::value && std::is_signed<SignedType>::value,
151         "use this for signed integer types");
152     using UnsignedType = typename std::make_unsigned<SignedType>::type;
153     UnsignedType aUnsigned = static_cast<UnsignedType>(a);
154     UnsignedType bUnsigned = static_cast<UnsignedType>(b);
155     UnsignedType result = aUnsigned + bUnsigned;
156     return static_cast<SignedType>(result);
157 }
158 
159 template <typename SignedType>
SubWithWraparound(SignedType a,SignedType b)160 inline SignedType SubWithWraparound(SignedType a, SignedType b)
161 {
162     static_assert(std::is_integral<SignedType>::value && std::is_signed<SignedType>::value,
163         "use this for signed integer types");
164     using UnsignedType = typename std::make_unsigned<SignedType>::type;
165     UnsignedType aUnsigned = static_cast<UnsignedType>(a);
166     UnsignedType bUnsigned = static_cast<UnsignedType>(b);
167     UnsignedType result = aUnsigned - bUnsigned;
168     return static_cast<SignedType>(result);
169 }
170 
171 template <typename SignedType>
MulWithWraparound(SignedType a,SignedType b)172 inline SignedType MulWithWraparound(SignedType a, SignedType b)
173 {
174     static_assert(std::is_integral<SignedType>::value && std::is_signed<SignedType>::value,
175         "use this for signed integer types");
176     using UnsignedType = typename std::make_unsigned<SignedType>::type;
177     UnsignedType aUnsigned = static_cast<UnsignedType>(a);
178     UnsignedType bUnsigned = static_cast<UnsignedType>(b);
179     UnsignedType result = aUnsigned * bUnsigned;
180     return static_cast<SignedType>(result);
181 }
182 
183 template <typename SignedType>
ShlWithWraparound(SignedType a,SignedType b)184 inline SignedType ShlWithWraparound(SignedType a, SignedType b)
185 {
186     using UnsignedType = typename std::make_unsigned<SignedType>::type;
187     const UnsignedType kMask = (sizeof(a) * 8) - 1;
188     return static_cast<SignedType>(static_cast<UnsignedType>(a) << (static_cast<UnsignedType>(b) & kMask));
189 }
190 
191 template <typename SignedType>
NegateWithWraparound(SignedType a)192 inline SignedType NegateWithWraparound(SignedType a)
193 {
194     static_assert(std::is_integral<SignedType>::value && std::is_signed<SignedType>::value,
195         "use this for signed integer types");
196     if (a == std::numeric_limits<SignedType>::min()) {
197         return a;
198     }
199     return -a;
200 }
201 }  // panda::ecmascript::base
202 
203 #endif  // ECMASCRIPT_BASE_MATH_HELPER_H
204