michael@0: /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- michael@0: * vim: set ts=8 sts=4 et sw=4 tw=99: michael@0: * This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this michael@0: * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: michael@0: #ifndef jsnum_h michael@0: #define jsnum_h michael@0: michael@0: #include "mozilla/FloatingPoint.h" michael@0: michael@0: #include "NamespaceImports.h" michael@0: michael@0: #include "vm/NumericConversions.h" michael@0: michael@0: namespace js { michael@0: michael@0: class StringBuffer; michael@0: michael@0: extern bool michael@0: InitRuntimeNumberState(JSRuntime *rt); michael@0: michael@0: #if !EXPOSE_INTL_API michael@0: extern void michael@0: FinishRuntimeNumberState(JSRuntime *rt); michael@0: #endif michael@0: michael@0: } /* namespace js */ michael@0: michael@0: /* Initialize the Number class, returning its prototype object. */ michael@0: extern JSObject * michael@0: js_InitNumberClass(JSContext *cx, js::HandleObject obj); michael@0: michael@0: /* michael@0: * String constants for global function names, used in jsapi.c and jsnum.c. michael@0: */ michael@0: extern const char js_isNaN_str[]; michael@0: extern const char js_isFinite_str[]; michael@0: extern const char js_parseFloat_str[]; michael@0: extern const char js_parseInt_str[]; michael@0: michael@0: class JSAtom; michael@0: michael@0: namespace js { michael@0: michael@0: /* michael@0: * When base == 10, this function implements ToString() as specified by michael@0: * ECMA-262-5 section 9.8.1; but note that it handles integers specially for michael@0: * performance. See also js::NumberToCString(). michael@0: */ michael@0: template michael@0: extern JSString * michael@0: NumberToString(js::ThreadSafeContext *cx, double d); michael@0: michael@0: extern JSAtom * michael@0: NumberToAtom(js::ExclusiveContext *cx, double d); michael@0: michael@0: template michael@0: extern JSFlatString * michael@0: Int32ToString(ThreadSafeContext *cx, int32_t i); michael@0: michael@0: extern JSAtom * michael@0: Int32ToAtom(ExclusiveContext *cx, int32_t si); michael@0: michael@0: /* michael@0: * Convert an integer or double (contained in the given value) to a string and michael@0: * append to the given buffer. michael@0: */ michael@0: extern bool JS_FASTCALL michael@0: NumberValueToStringBuffer(JSContext *cx, const Value &v, StringBuffer &sb); michael@0: michael@0: /* Same as js_NumberToString, different signature. */ michael@0: extern JSFlatString * michael@0: NumberToString(JSContext *cx, double d); michael@0: michael@0: extern JSFlatString * michael@0: IndexToString(JSContext *cx, uint32_t index); michael@0: michael@0: /* michael@0: * Usually a small amount of static storage is enough, but sometimes we need michael@0: * to dynamically allocate much more. This struct encapsulates that. michael@0: * Dynamically allocated memory will be freed when the object is destroyed. michael@0: */ michael@0: struct ToCStringBuf michael@0: { michael@0: /* michael@0: * The longest possible result that would need to fit in sbuf is michael@0: * (-0x80000000).toString(2), which has length 33. Longer cases are michael@0: * possible, but they'll go in dbuf. michael@0: */ michael@0: static const size_t sbufSize = 34; michael@0: char sbuf[sbufSize]; michael@0: char *dbuf; michael@0: michael@0: ToCStringBuf(); michael@0: ~ToCStringBuf(); michael@0: }; michael@0: michael@0: /* michael@0: * Convert a number to a C string. When base==10, this function implements michael@0: * ToString() as specified by ECMA-262-5 section 9.8.1. It handles integral michael@0: * values cheaply. Return nullptr if we ran out of memory. See also michael@0: * js_NumberToCString(). michael@0: */ michael@0: extern char * michael@0: NumberToCString(JSContext *cx, ToCStringBuf *cbuf, double d, int base = 10); michael@0: michael@0: /* michael@0: * The largest positive integer such that all positive integers less than it michael@0: * may be precisely represented using the IEEE-754 double-precision format. michael@0: */ michael@0: const double DOUBLE_INTEGRAL_PRECISION_LIMIT = uint64_t(1) << 53; michael@0: michael@0: /* michael@0: * Parse a decimal number encoded in |chars|. The decimal number must be michael@0: * sufficiently small that it will not overflow the integrally-precise range of michael@0: * the double type -- that is, the number will be smaller than michael@0: * DOUBLE_INTEGRAL_PRECISION_LIMIT michael@0: */ michael@0: extern double michael@0: ParseDecimalNumber(const JS::TwoByteChars chars); michael@0: michael@0: /* michael@0: * Compute the positive integer of the given base described immediately at the michael@0: * start of the range [start, end) -- no whitespace-skipping, no magical michael@0: * leading-"0" octal or leading-"0x" hex behavior, no "+"/"-" parsing, just michael@0: * reading the digits of the integer. Return the index one past the end of the michael@0: * digits of the integer in *endp, and return the integer itself in *dp. If michael@0: * base is 10 or a power of two the returned integer is the closest possible michael@0: * double; otherwise extremely large integers may be slightly inaccurate. michael@0: * michael@0: * If [start, end) does not begin with a number with the specified base, michael@0: * *dp == 0 and *endp == start upon return. michael@0: */ michael@0: extern bool michael@0: GetPrefixInteger(ThreadSafeContext *cx, const jschar *start, const jschar *end, int base, michael@0: const jschar **endp, double *dp); michael@0: michael@0: /* michael@0: * This is like GetPrefixInteger, but only deals with base 10, and doesn't have michael@0: * and |endp| outparam. It should only be used when the jschars are known to michael@0: * only contain digits. michael@0: */ michael@0: extern bool michael@0: GetDecimalInteger(ExclusiveContext *cx, const jschar *start, const jschar *end, double *dp); michael@0: michael@0: extern bool michael@0: StringToNumber(ThreadSafeContext *cx, JSString *str, double *result); michael@0: michael@0: /* ES5 9.3 ToNumber, overwriting *vp with the appropriate number value. */ michael@0: MOZ_ALWAYS_INLINE bool michael@0: ToNumber(JSContext *cx, JS::MutableHandleValue vp) michael@0: { michael@0: if (vp.isNumber()) michael@0: return true; michael@0: double d; michael@0: extern JS_PUBLIC_API(bool) ToNumberSlow(JSContext *cx, Value v, double *dp); michael@0: if (!ToNumberSlow(cx, vp, &d)) michael@0: return false; michael@0: michael@0: vp.setNumber(d); michael@0: return true; michael@0: } michael@0: michael@0: bool michael@0: num_parseInt(JSContext *cx, unsigned argc, Value *vp); michael@0: michael@0: } /* namespace js */ michael@0: michael@0: /* michael@0: * Similar to strtod except that it replaces overflows with infinities of the michael@0: * correct sign, and underflows with zeros of the correct sign. Guaranteed to michael@0: * return the closest double number to the given input in dp. michael@0: * michael@0: * Also allows inputs of the form [+|-]Infinity, which produce an infinity of michael@0: * the appropriate sign. The case of the "Infinity" string must match exactly. michael@0: * If the string does not contain a number, set *ep to s and return 0.0 in dp. michael@0: * Return false if out of memory. michael@0: */ michael@0: extern bool michael@0: js_strtod(js::ThreadSafeContext *cx, const jschar *s, const jschar *send, michael@0: const jschar **ep, double *dp); michael@0: michael@0: extern bool michael@0: js_num_toString(JSContext *cx, unsigned argc, js::Value *vp); michael@0: michael@0: extern bool michael@0: js_num_valueOf(JSContext *cx, unsigned argc, js::Value *vp); michael@0: michael@0: namespace js { michael@0: michael@0: static MOZ_ALWAYS_INLINE bool michael@0: ValueFitsInInt32(const Value &v, int32_t *pi) michael@0: { michael@0: if (v.isInt32()) { michael@0: *pi = v.toInt32(); michael@0: return true; michael@0: } michael@0: return v.isDouble() && mozilla::NumberIsInt32(v.toDouble(), pi); michael@0: } michael@0: michael@0: /* michael@0: * Returns true if the given value is definitely an index: that is, the value michael@0: * is a number that's an unsigned 32-bit integer. michael@0: * michael@0: * This method prioritizes common-case speed over accuracy in every case. It michael@0: * can produce false negatives (but not false positives): some values which are michael@0: * indexes will be reported not to be indexes by this method. Users must michael@0: * consider this possibility when using this method. michael@0: */ michael@0: static MOZ_ALWAYS_INLINE bool michael@0: IsDefinitelyIndex(const Value &v, uint32_t *indexp) michael@0: { michael@0: if (v.isInt32() && v.toInt32() >= 0) { michael@0: *indexp = v.toInt32(); michael@0: return true; michael@0: } michael@0: michael@0: int32_t i; michael@0: if (v.isDouble() && mozilla::NumberIsInt32(v.toDouble(), &i) && i >= 0) { michael@0: *indexp = uint32_t(i); michael@0: return true; michael@0: } michael@0: michael@0: return false; michael@0: } michael@0: michael@0: /* ES5 9.4 ToInteger. */ michael@0: static inline bool michael@0: ToInteger(JSContext *cx, HandleValue v, double *dp) michael@0: { michael@0: if (v.isInt32()) { michael@0: *dp = v.toInt32(); michael@0: return true; michael@0: } michael@0: if (v.isDouble()) { michael@0: *dp = v.toDouble(); michael@0: } else { michael@0: extern JS_PUBLIC_API(bool) ToNumberSlow(JSContext *cx, Value v, double *dp); michael@0: if (!ToNumberSlow(cx, v, dp)) michael@0: return false; michael@0: } michael@0: *dp = ToInteger(*dp); michael@0: return true; michael@0: } michael@0: michael@0: inline bool michael@0: SafeAdd(int32_t one, int32_t two, int32_t *res) michael@0: { michael@0: // Use unsigned for the 32-bit operation since signed overflow gets michael@0: // undefined behavior. michael@0: *res = uint32_t(one) + uint32_t(two); michael@0: int64_t ores = (int64_t)one + (int64_t)two; michael@0: return ores == (int64_t)*res; michael@0: } michael@0: michael@0: inline bool michael@0: SafeSub(int32_t one, int32_t two, int32_t *res) michael@0: { michael@0: *res = uint32_t(one) - uint32_t(two); michael@0: int64_t ores = (int64_t)one - (int64_t)two; michael@0: return ores == (int64_t)*res; michael@0: } michael@0: michael@0: inline bool michael@0: SafeMul(int32_t one, int32_t two, int32_t *res) michael@0: { michael@0: *res = uint32_t(one) * uint32_t(two); michael@0: int64_t ores = (int64_t)one * (int64_t)two; michael@0: return ores == (int64_t)*res; michael@0: } michael@0: michael@0: extern bool michael@0: ToNumberSlow(ExclusiveContext *cx, Value v, double *dp); michael@0: michael@0: // Variant of ToNumber which takes an ExclusiveContext instead of a JSContext. michael@0: // ToNumber is part of the API and can't use ExclusiveContext directly. michael@0: MOZ_ALWAYS_INLINE bool michael@0: ToNumber(ExclusiveContext *cx, const Value &v, double *out) michael@0: { michael@0: if (v.isNumber()) { michael@0: *out = v.toNumber(); michael@0: return true; michael@0: } michael@0: return ToNumberSlow(cx, v, out); michael@0: } michael@0: michael@0: /* michael@0: * Thread safe variants of number conversion functions. michael@0: */ michael@0: michael@0: bool michael@0: NonObjectToNumberSlow(ThreadSafeContext *cx, Value v, double *out); michael@0: michael@0: inline bool michael@0: NonObjectToNumber(ThreadSafeContext *cx, const Value &v, double *out) michael@0: { michael@0: if (v.isNumber()) { michael@0: *out = v.toNumber(); michael@0: return true; michael@0: } michael@0: return NonObjectToNumberSlow(cx, v, out); michael@0: } michael@0: michael@0: bool michael@0: NonObjectToInt32Slow(ThreadSafeContext *cx, const Value &v, int32_t *out); michael@0: michael@0: inline bool michael@0: NonObjectToInt32(ThreadSafeContext *cx, const Value &v, int32_t *out) michael@0: { michael@0: if (v.isInt32()) { michael@0: *out = v.toInt32(); michael@0: return true; michael@0: } michael@0: return NonObjectToInt32Slow(cx, v, out); michael@0: } michael@0: michael@0: bool michael@0: NonObjectToUint32Slow(ThreadSafeContext *cx, const Value &v, uint32_t *out); michael@0: michael@0: MOZ_ALWAYS_INLINE bool michael@0: NonObjectToUint32(ThreadSafeContext *cx, const Value &v, uint32_t *out) michael@0: { michael@0: if (v.isInt32()) { michael@0: *out = uint32_t(v.toInt32()); michael@0: return true; michael@0: } michael@0: return NonObjectToUint32Slow(cx, v, out); michael@0: } michael@0: michael@0: } /* namespace js */ michael@0: michael@0: #endif /* jsnum_h */