|
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- |
|
2 * vim: set ts=8 sts=4 et sw=4 tw=99: |
|
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/. */ |
|
6 |
|
7 #ifndef jsnum_h |
|
8 #define jsnum_h |
|
9 |
|
10 #include "mozilla/FloatingPoint.h" |
|
11 |
|
12 #include "NamespaceImports.h" |
|
13 |
|
14 #include "vm/NumericConversions.h" |
|
15 |
|
16 namespace js { |
|
17 |
|
18 class StringBuffer; |
|
19 |
|
20 extern bool |
|
21 InitRuntimeNumberState(JSRuntime *rt); |
|
22 |
|
23 #if !EXPOSE_INTL_API |
|
24 extern void |
|
25 FinishRuntimeNumberState(JSRuntime *rt); |
|
26 #endif |
|
27 |
|
28 } /* namespace js */ |
|
29 |
|
30 /* Initialize the Number class, returning its prototype object. */ |
|
31 extern JSObject * |
|
32 js_InitNumberClass(JSContext *cx, js::HandleObject obj); |
|
33 |
|
34 /* |
|
35 * String constants for global function names, used in jsapi.c and jsnum.c. |
|
36 */ |
|
37 extern const char js_isNaN_str[]; |
|
38 extern const char js_isFinite_str[]; |
|
39 extern const char js_parseFloat_str[]; |
|
40 extern const char js_parseInt_str[]; |
|
41 |
|
42 class JSAtom; |
|
43 |
|
44 namespace js { |
|
45 |
|
46 /* |
|
47 * When base == 10, this function implements ToString() as specified by |
|
48 * ECMA-262-5 section 9.8.1; but note that it handles integers specially for |
|
49 * performance. See also js::NumberToCString(). |
|
50 */ |
|
51 template <js::AllowGC allowGC> |
|
52 extern JSString * |
|
53 NumberToString(js::ThreadSafeContext *cx, double d); |
|
54 |
|
55 extern JSAtom * |
|
56 NumberToAtom(js::ExclusiveContext *cx, double d); |
|
57 |
|
58 template <AllowGC allowGC> |
|
59 extern JSFlatString * |
|
60 Int32ToString(ThreadSafeContext *cx, int32_t i); |
|
61 |
|
62 extern JSAtom * |
|
63 Int32ToAtom(ExclusiveContext *cx, int32_t si); |
|
64 |
|
65 /* |
|
66 * Convert an integer or double (contained in the given value) to a string and |
|
67 * append to the given buffer. |
|
68 */ |
|
69 extern bool JS_FASTCALL |
|
70 NumberValueToStringBuffer(JSContext *cx, const Value &v, StringBuffer &sb); |
|
71 |
|
72 /* Same as js_NumberToString, different signature. */ |
|
73 extern JSFlatString * |
|
74 NumberToString(JSContext *cx, double d); |
|
75 |
|
76 extern JSFlatString * |
|
77 IndexToString(JSContext *cx, uint32_t index); |
|
78 |
|
79 /* |
|
80 * Usually a small amount of static storage is enough, but sometimes we need |
|
81 * to dynamically allocate much more. This struct encapsulates that. |
|
82 * Dynamically allocated memory will be freed when the object is destroyed. |
|
83 */ |
|
84 struct ToCStringBuf |
|
85 { |
|
86 /* |
|
87 * The longest possible result that would need to fit in sbuf is |
|
88 * (-0x80000000).toString(2), which has length 33. Longer cases are |
|
89 * possible, but they'll go in dbuf. |
|
90 */ |
|
91 static const size_t sbufSize = 34; |
|
92 char sbuf[sbufSize]; |
|
93 char *dbuf; |
|
94 |
|
95 ToCStringBuf(); |
|
96 ~ToCStringBuf(); |
|
97 }; |
|
98 |
|
99 /* |
|
100 * Convert a number to a C string. When base==10, this function implements |
|
101 * ToString() as specified by ECMA-262-5 section 9.8.1. It handles integral |
|
102 * values cheaply. Return nullptr if we ran out of memory. See also |
|
103 * js_NumberToCString(). |
|
104 */ |
|
105 extern char * |
|
106 NumberToCString(JSContext *cx, ToCStringBuf *cbuf, double d, int base = 10); |
|
107 |
|
108 /* |
|
109 * The largest positive integer such that all positive integers less than it |
|
110 * may be precisely represented using the IEEE-754 double-precision format. |
|
111 */ |
|
112 const double DOUBLE_INTEGRAL_PRECISION_LIMIT = uint64_t(1) << 53; |
|
113 |
|
114 /* |
|
115 * Parse a decimal number encoded in |chars|. The decimal number must be |
|
116 * sufficiently small that it will not overflow the integrally-precise range of |
|
117 * the double type -- that is, the number will be smaller than |
|
118 * DOUBLE_INTEGRAL_PRECISION_LIMIT |
|
119 */ |
|
120 extern double |
|
121 ParseDecimalNumber(const JS::TwoByteChars chars); |
|
122 |
|
123 /* |
|
124 * Compute the positive integer of the given base described immediately at the |
|
125 * start of the range [start, end) -- no whitespace-skipping, no magical |
|
126 * leading-"0" octal or leading-"0x" hex behavior, no "+"/"-" parsing, just |
|
127 * reading the digits of the integer. Return the index one past the end of the |
|
128 * digits of the integer in *endp, and return the integer itself in *dp. If |
|
129 * base is 10 or a power of two the returned integer is the closest possible |
|
130 * double; otherwise extremely large integers may be slightly inaccurate. |
|
131 * |
|
132 * If [start, end) does not begin with a number with the specified base, |
|
133 * *dp == 0 and *endp == start upon return. |
|
134 */ |
|
135 extern bool |
|
136 GetPrefixInteger(ThreadSafeContext *cx, const jschar *start, const jschar *end, int base, |
|
137 const jschar **endp, double *dp); |
|
138 |
|
139 /* |
|
140 * This is like GetPrefixInteger, but only deals with base 10, and doesn't have |
|
141 * and |endp| outparam. It should only be used when the jschars are known to |
|
142 * only contain digits. |
|
143 */ |
|
144 extern bool |
|
145 GetDecimalInteger(ExclusiveContext *cx, const jschar *start, const jschar *end, double *dp); |
|
146 |
|
147 extern bool |
|
148 StringToNumber(ThreadSafeContext *cx, JSString *str, double *result); |
|
149 |
|
150 /* ES5 9.3 ToNumber, overwriting *vp with the appropriate number value. */ |
|
151 MOZ_ALWAYS_INLINE bool |
|
152 ToNumber(JSContext *cx, JS::MutableHandleValue vp) |
|
153 { |
|
154 if (vp.isNumber()) |
|
155 return true; |
|
156 double d; |
|
157 extern JS_PUBLIC_API(bool) ToNumberSlow(JSContext *cx, Value v, double *dp); |
|
158 if (!ToNumberSlow(cx, vp, &d)) |
|
159 return false; |
|
160 |
|
161 vp.setNumber(d); |
|
162 return true; |
|
163 } |
|
164 |
|
165 bool |
|
166 num_parseInt(JSContext *cx, unsigned argc, Value *vp); |
|
167 |
|
168 } /* namespace js */ |
|
169 |
|
170 /* |
|
171 * Similar to strtod except that it replaces overflows with infinities of the |
|
172 * correct sign, and underflows with zeros of the correct sign. Guaranteed to |
|
173 * return the closest double number to the given input in dp. |
|
174 * |
|
175 * Also allows inputs of the form [+|-]Infinity, which produce an infinity of |
|
176 * the appropriate sign. The case of the "Infinity" string must match exactly. |
|
177 * If the string does not contain a number, set *ep to s and return 0.0 in dp. |
|
178 * Return false if out of memory. |
|
179 */ |
|
180 extern bool |
|
181 js_strtod(js::ThreadSafeContext *cx, const jschar *s, const jschar *send, |
|
182 const jschar **ep, double *dp); |
|
183 |
|
184 extern bool |
|
185 js_num_toString(JSContext *cx, unsigned argc, js::Value *vp); |
|
186 |
|
187 extern bool |
|
188 js_num_valueOf(JSContext *cx, unsigned argc, js::Value *vp); |
|
189 |
|
190 namespace js { |
|
191 |
|
192 static MOZ_ALWAYS_INLINE bool |
|
193 ValueFitsInInt32(const Value &v, int32_t *pi) |
|
194 { |
|
195 if (v.isInt32()) { |
|
196 *pi = v.toInt32(); |
|
197 return true; |
|
198 } |
|
199 return v.isDouble() && mozilla::NumberIsInt32(v.toDouble(), pi); |
|
200 } |
|
201 |
|
202 /* |
|
203 * Returns true if the given value is definitely an index: that is, the value |
|
204 * is a number that's an unsigned 32-bit integer. |
|
205 * |
|
206 * This method prioritizes common-case speed over accuracy in every case. It |
|
207 * can produce false negatives (but not false positives): some values which are |
|
208 * indexes will be reported not to be indexes by this method. Users must |
|
209 * consider this possibility when using this method. |
|
210 */ |
|
211 static MOZ_ALWAYS_INLINE bool |
|
212 IsDefinitelyIndex(const Value &v, uint32_t *indexp) |
|
213 { |
|
214 if (v.isInt32() && v.toInt32() >= 0) { |
|
215 *indexp = v.toInt32(); |
|
216 return true; |
|
217 } |
|
218 |
|
219 int32_t i; |
|
220 if (v.isDouble() && mozilla::NumberIsInt32(v.toDouble(), &i) && i >= 0) { |
|
221 *indexp = uint32_t(i); |
|
222 return true; |
|
223 } |
|
224 |
|
225 return false; |
|
226 } |
|
227 |
|
228 /* ES5 9.4 ToInteger. */ |
|
229 static inline bool |
|
230 ToInteger(JSContext *cx, HandleValue v, double *dp) |
|
231 { |
|
232 if (v.isInt32()) { |
|
233 *dp = v.toInt32(); |
|
234 return true; |
|
235 } |
|
236 if (v.isDouble()) { |
|
237 *dp = v.toDouble(); |
|
238 } else { |
|
239 extern JS_PUBLIC_API(bool) ToNumberSlow(JSContext *cx, Value v, double *dp); |
|
240 if (!ToNumberSlow(cx, v, dp)) |
|
241 return false; |
|
242 } |
|
243 *dp = ToInteger(*dp); |
|
244 return true; |
|
245 } |
|
246 |
|
247 inline bool |
|
248 SafeAdd(int32_t one, int32_t two, int32_t *res) |
|
249 { |
|
250 // Use unsigned for the 32-bit operation since signed overflow gets |
|
251 // undefined behavior. |
|
252 *res = uint32_t(one) + uint32_t(two); |
|
253 int64_t ores = (int64_t)one + (int64_t)two; |
|
254 return ores == (int64_t)*res; |
|
255 } |
|
256 |
|
257 inline bool |
|
258 SafeSub(int32_t one, int32_t two, int32_t *res) |
|
259 { |
|
260 *res = uint32_t(one) - uint32_t(two); |
|
261 int64_t ores = (int64_t)one - (int64_t)two; |
|
262 return ores == (int64_t)*res; |
|
263 } |
|
264 |
|
265 inline bool |
|
266 SafeMul(int32_t one, int32_t two, int32_t *res) |
|
267 { |
|
268 *res = uint32_t(one) * uint32_t(two); |
|
269 int64_t ores = (int64_t)one * (int64_t)two; |
|
270 return ores == (int64_t)*res; |
|
271 } |
|
272 |
|
273 extern bool |
|
274 ToNumberSlow(ExclusiveContext *cx, Value v, double *dp); |
|
275 |
|
276 // Variant of ToNumber which takes an ExclusiveContext instead of a JSContext. |
|
277 // ToNumber is part of the API and can't use ExclusiveContext directly. |
|
278 MOZ_ALWAYS_INLINE bool |
|
279 ToNumber(ExclusiveContext *cx, const Value &v, double *out) |
|
280 { |
|
281 if (v.isNumber()) { |
|
282 *out = v.toNumber(); |
|
283 return true; |
|
284 } |
|
285 return ToNumberSlow(cx, v, out); |
|
286 } |
|
287 |
|
288 /* |
|
289 * Thread safe variants of number conversion functions. |
|
290 */ |
|
291 |
|
292 bool |
|
293 NonObjectToNumberSlow(ThreadSafeContext *cx, Value v, double *out); |
|
294 |
|
295 inline bool |
|
296 NonObjectToNumber(ThreadSafeContext *cx, const Value &v, double *out) |
|
297 { |
|
298 if (v.isNumber()) { |
|
299 *out = v.toNumber(); |
|
300 return true; |
|
301 } |
|
302 return NonObjectToNumberSlow(cx, v, out); |
|
303 } |
|
304 |
|
305 bool |
|
306 NonObjectToInt32Slow(ThreadSafeContext *cx, const Value &v, int32_t *out); |
|
307 |
|
308 inline bool |
|
309 NonObjectToInt32(ThreadSafeContext *cx, const Value &v, int32_t *out) |
|
310 { |
|
311 if (v.isInt32()) { |
|
312 *out = v.toInt32(); |
|
313 return true; |
|
314 } |
|
315 return NonObjectToInt32Slow(cx, v, out); |
|
316 } |
|
317 |
|
318 bool |
|
319 NonObjectToUint32Slow(ThreadSafeContext *cx, const Value &v, uint32_t *out); |
|
320 |
|
321 MOZ_ALWAYS_INLINE bool |
|
322 NonObjectToUint32(ThreadSafeContext *cx, const Value &v, uint32_t *out) |
|
323 { |
|
324 if (v.isInt32()) { |
|
325 *out = uint32_t(v.toInt32()); |
|
326 return true; |
|
327 } |
|
328 return NonObjectToUint32Slow(cx, v, out); |
|
329 } |
|
330 |
|
331 } /* namespace js */ |
|
332 |
|
333 #endif /* jsnum_h */ |