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/. */
10 #include "mozilla/FloatingPoint.h"
11 #include "mozilla/Range.h"
12 #include "mozilla/Utf8.h"
16 #include "NamespaceImports.h"
18 #include "js/Conversions.h"
19 #include "js/friend/ErrorMessages.h" // JSMSG_*
21 #include "vm/StringType.h"
26 class ParserAtomsTable
;
27 class TaggedParserAtomIndex
;
28 } // namespace frontend
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
,
60 extern JSLinearString
* Int32ToStringPure(JSContext
* cx
, int32_t i
);
62 extern JSString
* Int32ToStringWithBase(JSContext
* cx
, int32_t i
, int32_t base
);
64 extern JSAtom
* Int32ToAtom(JSContext
* cx
, int32_t si
);
66 frontend::TaggedParserAtomIndex
Int32ToParserAtom(
67 FrontendContext
* fc
, frontend::ParserAtomsTable
& parserAtoms
, int32_t si
);
70 extern bool IsInteger(double d
);
73 * Convert an integer or double (contained in the given value) to a string and
74 * append to the given buffer.
76 [[nodiscard
]] extern bool NumberValueToStringBuffer(const Value
& v
,
79 extern JSLinearString
* IndexToString(JSContext
* cx
, uint32_t index
);
82 char sbuf
[JS::MaximumNumberToStringLength
] = {};
85 struct Int32ToCStringBuf
{
86 // The amount of space large enough to store the null-terminated result of
87 // |ToString| on any int32.
89 // We use the same amount for uint32 (base 10 and base 16), even though uint32
90 // only need 11 characters (base 10) resp. 9 characters (base 16) instead of
91 // 12 characters for int32 in base 10.
92 static constexpr size_t MaximumInt32ToStringLength
=
93 std::numeric_limits
<int32_t>::digits10
+
94 1 + // account for the largest possible int32 value
95 1 + // sign for negative numbers
99 char sbuf
[MaximumInt32ToStringLength
] = {};
102 // Convert a number to a C string. This function implements ToString() as
103 // specified by ECMA-262-5 section 9.8.1. It handles integral values cheaply.
104 // Infallible: always returns a non-nullptr string.
105 // The optional `length` out-param is set to the string length of the result.
106 extern char* NumberToCString(ToCStringBuf
* cbuf
, double d
,
107 size_t* length
= nullptr);
109 extern char* Int32ToCString(Int32ToCStringBuf
* cbuf
, int32_t value
,
110 size_t* length
= nullptr);
112 extern char* Uint32ToCString(Int32ToCStringBuf
* cbuf
, uint32_t value
,
113 size_t* length
= nullptr);
115 // Like NumberToCString, but accepts only unsigned integers and uses base 16.
116 // Infallible: always returns a non-nullptr string.
117 // The optional `length` out-param is set to the string length of the result.
118 extern char* Uint32ToHexCString(Int32ToCStringBuf
* cbuf
, uint32_t value
,
119 size_t* length
= nullptr);
122 * The largest positive integer such that all positive integers less than it
123 * may be precisely represented using the IEEE-754 double-precision format.
125 constexpr double DOUBLE_INTEGRAL_PRECISION_LIMIT
= uint64_t(1) << 53;
128 * The smallest positive double such that all positive doubles larger or equal
129 * than it have an exact decimal representation without exponential form.
131 constexpr double DOUBLE_DECIMAL_IN_SHORTEST_LOW
= 1.0e-6;
134 * The largest positive double such that all positive doubles less than it
135 * have an exact decimal representation without exponential form.
137 constexpr double DOUBLE_DECIMAL_IN_SHORTEST_HIGH
= 1.0e21
;
140 * Parse a decimal number encoded in |chars|. The decimal number must be
141 * sufficiently small that it will not overflow the integrally-precise range of
142 * the double type -- that is, the number will be smaller than
143 * DOUBLE_INTEGRAL_PRECISION_LIMIT
145 template <typename CharT
>
146 extern double ParseDecimalNumber(const mozilla::Range
<const CharT
> chars
);
148 enum class IntegerSeparatorHandling
: bool { None
, SkipUnderscore
};
151 * Compute the positive integer of the given base described immediately at the
152 * start of the range [start, end) -- no whitespace-skipping, no magical
153 * leading-"0" octal or leading-"0x" hex behavior, no "+"/"-" parsing, just
154 * reading the digits of the integer. Return the index one past the end of the
155 * digits of the integer in *endp, and return the integer itself in *dp. If
156 * base is 10 or a power of two the returned integer is the closest possible
157 * double; otherwise extremely large integers may be slightly inaccurate.
159 * The |separatorHandling| controls whether or not numeric separators can be
160 * part of integer string. If the option is enabled, all '_' characters in the
161 * string are ignored. Underscore characters must not appear directly next to
162 * each other, e.g. '1__2' will lead to an assertion.
164 * If [start, end) does not begin with a number with the specified base,
165 * *dp == 0 and *endp == start upon return.
167 template <typename CharT
>
168 [[nodiscard
]] extern bool GetPrefixInteger(
169 const CharT
* start
, const CharT
* end
, int base
,
170 IntegerSeparatorHandling separatorHandling
, const CharT
** endp
, double* dp
);
172 inline const char16_t
* ToRawChars(const char16_t
* units
) { return units
; }
174 inline const unsigned char* ToRawChars(const unsigned char* units
) {
178 inline const unsigned char* ToRawChars(const mozilla::Utf8Unit
* units
) {
179 return mozilla::Utf8AsUnsignedChars(units
);
183 * Like GetPrefixInteger, but [start, end) must all be digits in the given
184 * base (and so this function doesn't take a useless outparam).
186 template <typename CharT
>
187 [[nodiscard
]] extern bool GetFullInteger(
188 const CharT
* start
, const CharT
* end
, int base
,
189 IntegerSeparatorHandling separatorHandling
, double* dp
) {
190 decltype(ToRawChars(start
)) realEnd
;
191 if (GetPrefixInteger(ToRawChars(start
), ToRawChars(end
), base
,
192 separatorHandling
, &realEnd
, dp
)) {
193 MOZ_ASSERT(end
== static_cast<const void*>(realEnd
));
200 * This is like GetPrefixInteger, but only deals with base 10, always ignores
201 * '_', and doesn't have an |endp| outparam. It should only be used when the
202 * characters are known to match |DecimalIntegerLiteral|, cf. ES2020, 11.8.3
205 template <typename CharT
>
206 [[nodiscard
]] extern bool GetDecimalInteger(const CharT
* start
,
207 const CharT
* end
, double* dp
);
210 * This is like GetDecimalInteger, but also allows non-integer numbers. It
211 * should only be used when the characters are known to match |DecimalLiteral|,
212 * cf. ES2020, 11.8.3 Numeric Literals.
214 template <typename CharT
>
215 [[nodiscard
]] extern bool GetDecimal(const CharT
* start
, const CharT
* end
,
218 template <typename CharT
>
219 double CharsToNumber(const CharT
* chars
, size_t length
);
221 [[nodiscard
]] extern bool StringToNumber(JSContext
* cx
, JSString
* str
,
224 [[nodiscard
]] extern bool StringToNumberPure(JSContext
* cx
, JSString
* str
,
227 // Infallible version of StringToNumber for linear strings.
228 extern double LinearStringToNumber(JSLinearString
* str
);
230 // Parse the input string as if Number.parseInt had been called.
231 extern bool NumberParseInt(JSContext
* cx
, JS::HandleString str
, int32_t radix
,
232 JS::MutableHandleValue result
);
234 /* ES5 9.3 ToNumber, overwriting *vp with the appropriate number value. */
235 [[nodiscard
]] MOZ_ALWAYS_INLINE
bool ToNumber(JSContext
* cx
,
236 JS::MutableHandleValue vp
) {
241 extern JS_PUBLIC_API
bool ToNumberSlow(JSContext
* cx
, HandleValue v
,
243 if (!ToNumberSlow(cx
, vp
, &d
)) {
251 bool ToNumericSlow(JSContext
* cx
, JS::MutableHandleValue vp
);
253 // BigInt proposal section 3.1.6
254 [[nodiscard
]] MOZ_ALWAYS_INLINE
bool ToNumeric(JSContext
* cx
,
255 JS::MutableHandleValue vp
) {
256 if (vp
.isNumeric()) {
259 return ToNumericSlow(cx
, vp
);
262 bool ToInt32OrBigIntSlow(JSContext
* cx
, JS::MutableHandleValue vp
);
264 [[nodiscard
]] MOZ_ALWAYS_INLINE
bool ToInt32OrBigInt(
265 JSContext
* cx
, JS::MutableHandleValue vp
) {
269 return ToInt32OrBigIntSlow(cx
, vp
);
275 * Similar to strtod except that it replaces overflows with infinities of the
276 * correct sign, and underflows with zeros of the correct sign. Guaranteed to
277 * return the closest double number to the given input.
279 * Also allows inputs of the form [+|-]Infinity, which produce an infinity of
280 * the appropriate sign. The case of the "Infinity" string must match exactly.
281 * If the string does not contain a number, set *dEnd to begin and return 0.0.
283 template <typename CharT
>
284 [[nodiscard
]] extern double js_strtod(const CharT
* begin
, const CharT
* end
,
290 * Like js_strtod, but for when the number always constitutes the entire range
291 * (and so |dEnd| would be a value already known).
293 template <typename CharT
>
294 [[nodiscard
]] extern double FullStringToDouble(const CharT
* begin
,
296 decltype(ToRawChars(begin
)) realEnd
;
297 double d
= js_strtod(ToRawChars(begin
), ToRawChars(end
), &realEnd
);
298 MOZ_ASSERT(end
== static_cast<const void*>(realEnd
));
302 [[nodiscard
]] extern bool ThisNumberValueForToLocaleString(JSContext
* cx
,
306 [[nodiscard
]] extern bool num_valueOf(JSContext
* cx
, unsigned argc
, Value
* vp
);
309 * Returns true if the given value is definitely an index: that is, the value
310 * is a number that's an unsigned 32-bit integer.
312 * This method prioritizes common-case speed over accuracy in every case. It
313 * can produce false negatives (but not false positives): some values which are
314 * indexes will be reported not to be indexes by this method. Users must
315 * consider this possibility when using this method.
317 static MOZ_ALWAYS_INLINE
bool IsDefinitelyIndex(const Value
& v
,
319 if (v
.isInt32() && v
.toInt32() >= 0) {
320 *indexp
= v
.toInt32();
325 if (v
.isDouble() && mozilla::NumberEqualsInt32(v
.toDouble(), &i
) && i
>= 0) {
326 *indexp
= uint32_t(i
);
330 if (v
.isString() && v
.toString()->hasIndexValue()) {
331 *indexp
= v
.toString()->getIndexValue();
338 // ES2020 draft rev 6b05bc56ba4e3c7a2b9922c4282d9eb844426d9b
339 // 7.1.5 ToInteger ( argument )
340 [[nodiscard
]] static inline bool ToInteger(JSContext
* cx
, HandleValue v
,
348 } else if (v
.isString() && v
.toString()->hasIndexValue()) {
349 *dp
= v
.toString()->getIndexValue();
352 extern JS_PUBLIC_API
bool ToNumberSlow(JSContext
* cx
, HandleValue v
,
354 if (!ToNumberSlow(cx
, v
, dp
)) {
358 *dp
= JS::ToInteger(*dp
);
362 /* ES2017 draft 7.1.17 ToIndex
364 * Return true and set |*index| to the integer value if |v| is a valid
365 * integer index value. Otherwise report a RangeError and return false.
367 * The returned index will always be in the range 0 <= *index <= 2^53-1.
369 [[nodiscard
]] extern bool ToIndexSlow(JSContext
* cx
, JS::HandleValue v
,
370 const unsigned errorNumber
,
373 [[nodiscard
]] static inline bool ToIndex(JSContext
* cx
, JS::HandleValue v
,
374 const unsigned errorNumber
,
377 int32_t i
= v
.toInt32();
379 *index
= uint64_t(i
);
383 return ToIndexSlow(cx
, v
, errorNumber
, index
);
386 [[nodiscard
]] static inline bool ToIndex(JSContext
* cx
, JS::HandleValue v
,
388 return ToIndex(cx
, v
, JSMSG_BAD_INDEX
, index
);