Bug 1877642 - Disable browser_fullscreen-tab-close-race.js on apple_silicon !debug...
[gecko.git] / js / src / jsnum.h
blob095bec08a75494be828532ffd45a2b9a3b1d0a68
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
2 * vim: set ts=8 sts=2 et sw=2 tw=80:
3 * This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
7 #ifndef jsnum_h
8 #define jsnum_h
10 #include "mozilla/FloatingPoint.h"
11 #include "mozilla/Range.h"
12 #include "mozilla/Utf8.h"
14 #include <limits>
16 #include "NamespaceImports.h"
18 #include "js/Conversions.h"
19 #include "js/friend/ErrorMessages.h" // JSMSG_*
21 #include "vm/StringType.h"
23 namespace js {
25 namespace frontend {
26 class ParserAtomsTable;
27 class TaggedParserAtomIndex;
28 } // namespace frontend
30 class GlobalObject;
31 class StringBuffer;
33 [[nodiscard]] extern bool InitRuntimeNumberState(JSRuntime* rt);
35 // This is a no-op if built with JS_HAS_INTL_API.
36 extern void FinishRuntimeNumberState(JSRuntime* rt);
39 * This function implements ToString() as specified by ECMA-262-5 section 9.8.1;
40 * but note that it handles integers specially for performance.
41 * See also js::NumberToCString().
43 template <AllowGC allowGC>
44 extern JSString* NumberToString(JSContext* cx, double d);
46 extern JSString* NumberToStringPure(JSContext* cx, double d);
48 extern JSAtom* NumberToAtom(JSContext* cx, double d);
50 frontend::TaggedParserAtomIndex NumberToParserAtom(
51 FrontendContext* fc, frontend::ParserAtomsTable& parserAtoms, double d);
53 template <AllowGC allowGC>
54 extern JSLinearString* Int32ToString(JSContext* cx, int32_t i);
56 template <AllowGC allowGC>
57 extern JSLinearString* Int32ToStringWithHeap(JSContext* cx, int32_t i,
58 gc::Heap heap);
60 extern JSLinearString* Int32ToStringPure(JSContext* cx, int32_t i);
62 extern JSString* Int32ToStringWithBase(JSContext* cx, int32_t i, int32_t base,
63 bool lowerCase);
65 extern JSAtom* Int32ToAtom(JSContext* cx, int32_t si);
67 frontend::TaggedParserAtomIndex Int32ToParserAtom(
68 FrontendContext* fc, frontend::ParserAtomsTable& parserAtoms, int32_t si);
70 // ES6 15.7.3.12
71 extern bool IsInteger(double d);
74 * Convert an integer or double (contained in the given value) to a string and
75 * append to the given buffer.
77 [[nodiscard]] extern bool NumberValueToStringBuffer(const Value& v,
78 StringBuffer& sb);
80 extern JSLinearString* IndexToString(JSContext* cx, uint32_t index);
82 struct ToCStringBuf {
83 char sbuf[JS::MaximumNumberToStringLength] = {};
86 struct Int32ToCStringBuf {
87 // The amount of space large enough to store the null-terminated result of
88 // |ToString| on any int32.
90 // We use the same amount for uint32 (base 10 and base 16), even though uint32
91 // only need 11 characters (base 10) resp. 9 characters (base 16) instead of
92 // 12 characters for int32 in base 10.
93 static constexpr size_t MaximumInt32ToStringLength =
94 std::numeric_limits<int32_t>::digits10 +
95 1 + // account for the largest possible int32 value
96 1 + // sign for negative numbers
97 1 // null character
100 char sbuf[MaximumInt32ToStringLength] = {};
103 // Convert a number to a C string. This function implements ToString() as
104 // specified by ECMA-262-5 section 9.8.1. It handles integral values cheaply.
105 // Infallible: always returns a non-nullptr string.
106 // The optional `length` out-param is set to the string length of the result.
107 extern char* NumberToCString(ToCStringBuf* cbuf, double d,
108 size_t* length = nullptr);
110 extern char* Int32ToCString(Int32ToCStringBuf* cbuf, int32_t value,
111 size_t* length = nullptr);
113 extern char* Uint32ToCString(Int32ToCStringBuf* cbuf, uint32_t value,
114 size_t* length = nullptr);
116 // Like NumberToCString, but accepts only unsigned integers and uses base 16.
117 // Infallible: always returns a non-nullptr string.
118 // The optional `length` out-param is set to the string length of the result.
119 extern char* Uint32ToHexCString(Int32ToCStringBuf* cbuf, uint32_t value,
120 size_t* length = nullptr);
123 * The largest positive integer such that all positive integers less than it
124 * may be precisely represented using the IEEE-754 double-precision format.
126 constexpr double DOUBLE_INTEGRAL_PRECISION_LIMIT = uint64_t(1) << 53;
129 * The smallest positive double such that all positive doubles larger or equal
130 * than it have an exact decimal representation without exponential form.
132 constexpr double DOUBLE_DECIMAL_IN_SHORTEST_LOW = 1.0e-6;
135 * The largest positive double such that all positive doubles less than it
136 * have an exact decimal representation without exponential form.
138 constexpr double DOUBLE_DECIMAL_IN_SHORTEST_HIGH = 1.0e21;
141 * Parse a decimal number encoded in |chars|. The decimal number must be
142 * sufficiently small that it will not overflow the integrally-precise range of
143 * the double type -- that is, the number will be smaller than
144 * DOUBLE_INTEGRAL_PRECISION_LIMIT
146 template <typename CharT>
147 extern double ParseDecimalNumber(const mozilla::Range<const CharT> chars);
149 enum class IntegerSeparatorHandling : bool { None, SkipUnderscore };
152 * Compute the positive integer of the given base described immediately at the
153 * start of the range [start, end) -- no whitespace-skipping, no magical
154 * leading-"0" octal or leading-"0x" hex behavior, no "+"/"-" parsing, just
155 * reading the digits of the integer. Return the index one past the end of the
156 * digits of the integer in *endp, and return the integer itself in *dp. If
157 * base is 10 or a power of two the returned integer is the closest possible
158 * double; otherwise extremely large integers may be slightly inaccurate.
160 * The |separatorHandling| controls whether or not numeric separators can be
161 * part of integer string. If the option is enabled, all '_' characters in the
162 * string are ignored. Underscore characters must not appear directly next to
163 * each other, e.g. '1__2' will lead to an assertion.
165 * If [start, end) does not begin with a number with the specified base,
166 * *dp == 0 and *endp == start upon return.
168 template <typename CharT>
169 [[nodiscard]] extern bool GetPrefixInteger(
170 const CharT* start, const CharT* end, int base,
171 IntegerSeparatorHandling separatorHandling, const CharT** endp, double* dp);
173 inline const char16_t* ToRawChars(const char16_t* units) { return units; }
175 inline const unsigned char* ToRawChars(const unsigned char* units) {
176 return units;
179 inline const unsigned char* ToRawChars(const mozilla::Utf8Unit* units) {
180 return mozilla::Utf8AsUnsignedChars(units);
184 * Like GetPrefixInteger, but [start, end) must all be digits in the given
185 * base (and so this function doesn't take a useless outparam).
187 template <typename CharT>
188 [[nodiscard]] extern bool GetFullInteger(
189 const CharT* start, const CharT* end, int base,
190 IntegerSeparatorHandling separatorHandling, double* dp) {
191 decltype(ToRawChars(start)) realEnd;
192 if (GetPrefixInteger(ToRawChars(start), ToRawChars(end), base,
193 separatorHandling, &realEnd, dp)) {
194 MOZ_ASSERT(end == static_cast<const void*>(realEnd));
195 return true;
197 return false;
201 * This is like GetPrefixInteger, but only deals with base 10, always ignores
202 * '_', and doesn't have an |endp| outparam. It should only be used when the
203 * characters are known to match |DecimalIntegerLiteral|, cf. ES2020, 11.8.3
204 * Numeric Literals.
206 template <typename CharT>
207 [[nodiscard]] extern bool GetDecimalInteger(const CharT* start,
208 const CharT* end, double* dp);
211 * This is like GetDecimalInteger, but also allows non-integer numbers. It
212 * should only be used when the characters are known to match |DecimalLiteral|,
213 * cf. ES2020, 11.8.3 Numeric Literals.
215 template <typename CharT>
216 [[nodiscard]] extern bool GetDecimal(const CharT* start, const CharT* end,
217 double* dp);
219 template <typename CharT>
220 double CharsToNumber(const CharT* chars, size_t length);
222 [[nodiscard]] extern bool StringToNumber(JSContext* cx, JSString* str,
223 double* result);
225 [[nodiscard]] extern bool StringToNumberPure(JSContext* cx, JSString* str,
226 double* result);
228 // Infallible version of StringToNumber for linear strings.
229 extern double LinearStringToNumber(JSLinearString* str);
231 // Parse the input string as if Number.parseInt had been called.
232 extern bool NumberParseInt(JSContext* cx, JS::HandleString str, int32_t radix,
233 JS::MutableHandleValue result);
235 /* ES5 9.3 ToNumber, overwriting *vp with the appropriate number value. */
236 [[nodiscard]] MOZ_ALWAYS_INLINE bool ToNumber(JSContext* cx,
237 JS::MutableHandleValue vp) {
238 if (vp.isNumber()) {
239 return true;
241 double d;
242 extern JS_PUBLIC_API bool ToNumberSlow(JSContext * cx, HandleValue v,
243 double* dp);
244 if (!ToNumberSlow(cx, vp, &d)) {
245 return false;
248 vp.setNumber(d);
249 return true;
252 bool ToNumericSlow(JSContext* cx, JS::MutableHandleValue vp);
254 // BigInt proposal section 3.1.6
255 [[nodiscard]] MOZ_ALWAYS_INLINE bool ToNumeric(JSContext* cx,
256 JS::MutableHandleValue vp) {
257 if (vp.isNumeric()) {
258 return true;
260 return ToNumericSlow(cx, vp);
263 bool ToInt32OrBigIntSlow(JSContext* cx, JS::MutableHandleValue vp);
265 [[nodiscard]] MOZ_ALWAYS_INLINE bool ToInt32OrBigInt(
266 JSContext* cx, JS::MutableHandleValue vp) {
267 if (vp.isInt32()) {
268 return true;
270 return ToInt32OrBigIntSlow(cx, vp);
273 } /* namespace js */
276 * Similar to strtod except that it replaces overflows with infinities of the
277 * correct sign, and underflows with zeros of the correct sign. Guaranteed to
278 * return the closest double number to the given input.
280 * Also allows inputs of the form [+|-]Infinity, which produce an infinity of
281 * the appropriate sign. The case of the "Infinity" string must match exactly.
282 * If the string does not contain a number, set *dEnd to begin and return 0.0.
284 template <typename CharT>
285 [[nodiscard]] extern double js_strtod(const CharT* begin, const CharT* end,
286 const CharT** dEnd);
288 namespace js {
291 * Like js_strtod, but for when the number always constitutes the entire range
292 * (and so |dEnd| would be a value already known).
294 template <typename CharT>
295 [[nodiscard]] extern double FullStringToDouble(const CharT* begin,
296 const CharT* end) {
297 decltype(ToRawChars(begin)) realEnd;
298 double d = js_strtod(ToRawChars(begin), ToRawChars(end), &realEnd);
299 MOZ_ASSERT(end == static_cast<const void*>(realEnd));
300 return d;
303 [[nodiscard]] extern bool ThisNumberValueForToLocaleString(JSContext* cx,
304 unsigned argc,
305 Value* vp);
307 [[nodiscard]] extern bool num_valueOf(JSContext* cx, unsigned argc, Value* vp);
310 * Returns true if the given value is definitely an index: that is, the value
311 * is a number that's an unsigned 32-bit integer.
313 * This method prioritizes common-case speed over accuracy in every case. It
314 * can produce false negatives (but not false positives): some values which are
315 * indexes will be reported not to be indexes by this method. Users must
316 * consider this possibility when using this method.
318 static MOZ_ALWAYS_INLINE bool IsDefinitelyIndex(const Value& v,
319 uint32_t* indexp) {
320 if (v.isInt32() && v.toInt32() >= 0) {
321 *indexp = v.toInt32();
322 return true;
325 int32_t i;
326 if (v.isDouble() && mozilla::NumberEqualsInt32(v.toDouble(), &i) && i >= 0) {
327 *indexp = uint32_t(i);
328 return true;
331 if (v.isString() && v.toString()->hasIndexValue()) {
332 *indexp = v.toString()->getIndexValue();
333 return true;
336 return false;
339 // ES2020 draft rev 6b05bc56ba4e3c7a2b9922c4282d9eb844426d9b
340 // 7.1.5 ToInteger ( argument )
341 [[nodiscard]] static inline bool ToInteger(JSContext* cx, HandleValue v,
342 double* dp) {
343 if (v.isInt32()) {
344 *dp = v.toInt32();
345 return true;
347 if (v.isDouble()) {
348 *dp = v.toDouble();
349 } else if (v.isString() && v.toString()->hasIndexValue()) {
350 *dp = v.toString()->getIndexValue();
351 return true;
352 } else {
353 extern JS_PUBLIC_API bool ToNumberSlow(JSContext * cx, HandleValue v,
354 double* dp);
355 if (!ToNumberSlow(cx, v, dp)) {
356 return false;
359 *dp = JS::ToInteger(*dp);
360 return true;
363 /* ES2017 draft 7.1.17 ToIndex
365 * Return true and set |*index| to the integer value if |v| is a valid
366 * integer index value. Otherwise report a RangeError and return false.
368 * The returned index will always be in the range 0 <= *index <= 2^53-1.
370 [[nodiscard]] extern bool ToIndexSlow(JSContext* cx, JS::HandleValue v,
371 const unsigned errorNumber,
372 uint64_t* index);
374 [[nodiscard]] static inline bool ToIndex(JSContext* cx, JS::HandleValue v,
375 const unsigned errorNumber,
376 uint64_t* index) {
377 if (v.isInt32()) {
378 int32_t i = v.toInt32();
379 if (i >= 0) {
380 *index = uint64_t(i);
381 return true;
384 return ToIndexSlow(cx, v, errorNumber, index);
387 [[nodiscard]] static inline bool ToIndex(JSContext* cx, JS::HandleValue v,
388 uint64_t* index) {
389 return ToIndex(cx, v, JSMSG_BAD_INDEX, index);
392 } /* namespace js */
394 #endif /* jsnum_h */