diff options
Diffstat (limited to 'tools/node_modules/expresso/deps/jscoverage/js/jsdtoa.cpp')
-rw-r--r-- | tools/node_modules/expresso/deps/jscoverage/js/jsdtoa.cpp | 572 |
1 files changed, 572 insertions, 0 deletions
diff --git a/tools/node_modules/expresso/deps/jscoverage/js/jsdtoa.cpp b/tools/node_modules/expresso/deps/jscoverage/js/jsdtoa.cpp new file mode 100644 index 0000000..ca9176d --- /dev/null +++ b/tools/node_modules/expresso/deps/jscoverage/js/jsdtoa.cpp @@ -0,0 +1,572 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * + * ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Mozilla Communicator client code, released + * March 31, 1998. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of the GNU General Public License Version 2 or later (the "GPL"), + * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +/* + * Portable double to alphanumeric string and back converters. + */ +#include "jsstddef.h" +#include "jslibmath.h" +#include "jstypes.h" +#include "jsdtoa.h" +#include "jsprf.h" +#include "jsutil.h" /* Added by JSIFY */ +#include "jspubtd.h" +#include "jsnum.h" +#include "jsbit.h" + +#ifdef JS_THREADSAFE +#include "jslock.h" +#endif + +#ifdef IS_LITTLE_ENDIAN +#define IEEE_8087 +#else +#define IEEE_MC68k +#endif + +#ifndef Long +#define Long int32 +#endif + +#ifndef ULong +#define ULong uint32 +#endif + +/* +#ifndef Llong +#define Llong JSInt64 +#endif + +#ifndef ULlong +#define ULlong JSUint64 +#endif +*/ + +#ifdef JS_THREADSAFE +static PRLock *dtoalock; +static JSBool _dtoainited = JS_FALSE; + +#define LOCK_DTOA() PR_Lock(dtoalock); +#define UNLOCK_DTOA() PR_Unlock(dtoalock) +#else +#define LOCK_DTOA() +#define UNLOCK_DTOA() +#endif +#include "dtoa.c" + +JS_FRIEND_API(JSBool) +js_InitDtoa() +{ +#ifdef JS_THREADSAFE + if (!_dtoainited) { + dtoalock = PR_NewLock(); + JS_ASSERT(dtoalock); + _dtoainited = JS_TRUE; + } + + return (dtoalock != 0); +#else + return JS_TRUE; +#endif +} + +JS_FRIEND_API(void) +js_FinishDtoa() +{ +#ifdef JS_THREADSAFE + if (_dtoainited) { + PR_DestroyLock(dtoalock); + dtoalock = NULL; + _dtoainited = JS_FALSE; + } +#endif +} + +/* Mapping of JSDToStrMode -> js_dtoa mode */ +static const uint8 dtoaModes[] = { + 0, /* DTOSTR_STANDARD */ + 0, /* DTOSTR_STANDARD_EXPONENTIAL, */ + 3, /* DTOSTR_FIXED, */ + 2, /* DTOSTR_EXPONENTIAL, */ + 2}; /* DTOSTR_PRECISION */ + +JS_FRIEND_API(double) +JS_strtod(const char *s00, char **se, int *err) +{ + double retval; + if (err) + *err = 0; + LOCK_DTOA(); + retval = _strtod(s00, se); + UNLOCK_DTOA(); + return retval; +} + +JS_FRIEND_API(char *) +JS_dtostr(char *buffer, size_t bufferSize, JSDToStrMode mode, int precision, double dinput) +{ + U d; + int decPt; /* Offset of decimal point from first digit */ + int sign; /* Nonzero if the sign bit was set in d */ + int nDigits; /* Number of significand digits returned by js_dtoa */ + char *numBegin; /* Pointer to the digits returned by js_dtoa */ + char *numEnd = 0; /* Pointer past the digits returned by js_dtoa */ + + JS_ASSERT(bufferSize >= (size_t)(mode <= DTOSTR_STANDARD_EXPONENTIAL + ? DTOSTR_STANDARD_BUFFER_SIZE + : DTOSTR_VARIABLE_BUFFER_SIZE(precision))); + + /* + * Change mode here rather than below because the buffer may not be large + * enough to hold a large integer. + */ + if (mode == DTOSTR_FIXED && (dinput >= 1e21 || dinput <= -1e21)) + mode = DTOSTR_STANDARD; + + LOCK_DTOA(); + dval(d) = dinput; + numBegin = dtoa(d, dtoaModes[mode], precision, &decPt, &sign, &numEnd); + if (!numBegin) { + UNLOCK_DTOA(); + return NULL; + } + + nDigits = numEnd - numBegin; + JS_ASSERT((size_t) nDigits <= bufferSize - 2); + if ((size_t) nDigits > bufferSize - 2) { + UNLOCK_DTOA(); + return NULL; + } + + memcpy(buffer + 2, numBegin, nDigits); + freedtoa(numBegin); + UNLOCK_DTOA(); + numBegin = buffer + 2; /* +2 leaves space for sign and/or decimal point */ + numEnd = numBegin + nDigits; + *numEnd = '\0'; + + /* If Infinity, -Infinity, or NaN, return the string regardless of mode. */ + if (decPt != 9999) { + JSBool exponentialNotation = JS_FALSE; + int minNDigits = 0; /* Min number of significant digits required */ + char *p; + char *q; + + switch (mode) { + case DTOSTR_STANDARD: + if (decPt < -5 || decPt > 21) + exponentialNotation = JS_TRUE; + else + minNDigits = decPt; + break; + + case DTOSTR_FIXED: + if (precision >= 0) + minNDigits = decPt + precision; + else + minNDigits = decPt; + break; + + case DTOSTR_EXPONENTIAL: + JS_ASSERT(precision > 0); + minNDigits = precision; + /* Fall through */ + case DTOSTR_STANDARD_EXPONENTIAL: + exponentialNotation = JS_TRUE; + break; + + case DTOSTR_PRECISION: + JS_ASSERT(precision > 0); + minNDigits = precision; + if (decPt < -5 || decPt > precision) + exponentialNotation = JS_TRUE; + break; + } + + /* If the number has fewer than minNDigits, end-pad it with zeros. */ + if (nDigits < minNDigits) { + p = numBegin + minNDigits; + nDigits = minNDigits; + do { + *numEnd++ = '0'; + } while (numEnd != p); + *numEnd = '\0'; + } + + if (exponentialNotation) { + /* Insert a decimal point if more than one significand digit */ + if (nDigits != 1) { + numBegin--; + numBegin[0] = numBegin[1]; + numBegin[1] = '.'; + } + JS_snprintf(numEnd, bufferSize - (numEnd - buffer), "e%+d", decPt-1); + } else if (decPt != nDigits) { + /* Some kind of a fraction in fixed notation */ + JS_ASSERT(decPt <= nDigits); + if (decPt > 0) { + /* dd...dd . dd...dd */ + p = --numBegin; + do { + *p = p[1]; + p++; + } while (--decPt); + *p = '.'; + } else { + /* 0 . 00...00dd...dd */ + p = numEnd; + numEnd += 1 - decPt; + q = numEnd; + JS_ASSERT(numEnd < buffer + bufferSize); + *numEnd = '\0'; + while (p != numBegin) + *--q = *--p; + for (p = numBegin + 1; p != q; p++) + *p = '0'; + *numBegin = '.'; + *--numBegin = '0'; + } + } + } + + /* If negative and neither -0.0 nor NaN, output a leading '-'. */ + if (sign && + !(word0(d) == Sign_bit && word1(d) == 0) && + !((word0(d) & Exp_mask) == Exp_mask && + (word1(d) || (word0(d) & Frac_mask)))) { + *--numBegin = '-'; + } + return numBegin; +} + + +/* Let b = floor(b / divisor), and return the remainder. b must be nonnegative. + * divisor must be between 1 and 65536. + * This function cannot run out of memory. */ +static uint32 +divrem(Bigint *b, uint32 divisor) +{ + int32 n = b->wds; + uint32 remainder = 0; + ULong *bx; + ULong *bp; + + JS_ASSERT(divisor > 0 && divisor <= 65536); + + if (!n) + return 0; /* b is zero */ + bx = b->x; + bp = bx + n; + do { + ULong a = *--bp; + ULong dividend = remainder << 16 | a >> 16; + ULong quotientHi = dividend / divisor; + ULong quotientLo; + + remainder = dividend - quotientHi*divisor; + JS_ASSERT(quotientHi <= 0xFFFF && remainder < divisor); + dividend = remainder << 16 | (a & 0xFFFF); + quotientLo = dividend / divisor; + remainder = dividend - quotientLo*divisor; + JS_ASSERT(quotientLo <= 0xFFFF && remainder < divisor); + *bp = quotientHi << 16 | quotientLo; + } while (bp != bx); + /* Decrease the size of the number if its most significant word is now zero. */ + if (bx[n-1] == 0) + b->wds--; + return remainder; +} + +/* Return floor(b/2^k) and set b to be the remainder. The returned quotient must be less than 2^32. */ +static uint32 quorem2(Bigint *b, int32 k) +{ + ULong mask; + ULong result; + ULong *bx, *bxe; + int32 w; + int32 n = k >> 5; + k &= 0x1F; + mask = (1<<k) - 1; + + w = b->wds - n; + if (w <= 0) + return 0; + JS_ASSERT(w <= 2); + bx = b->x; + bxe = bx + n; + result = *bxe >> k; + *bxe &= mask; + if (w == 2) { + JS_ASSERT(!(bxe[1] & ~mask)); + if (k) + result |= bxe[1] << (32 - k); + } + n++; + while (!*bxe && bxe != bx) { + n--; + bxe--; + } + b->wds = n; + return result; +} + + +/* "-0.0000...(1073 zeros after decimal point)...0001\0" is the longest string that we could produce, + * which occurs when printing -5e-324 in binary. We could compute a better estimate of the size of + * the output string and malloc fewer bytes depending on d and base, but why bother? */ +#define DTOBASESTR_BUFFER_SIZE 1078 +#define BASEDIGIT(digit) ((char)(((digit) >= 10) ? 'a' - 10 + (digit) : '0' + (digit))) + +JS_FRIEND_API(char *) +JS_dtobasestr(int base, double dinput) +{ + U d; + char *buffer; /* The output string */ + char *p; /* Pointer to current position in the buffer */ + char *pInt; /* Pointer to the beginning of the integer part of the string */ + char *q; + uint32 digit; + U di; /* d truncated to an integer */ + U df; /* The fractional part of d */ + + JS_ASSERT(base >= 2 && base <= 36); + + dval(d) = dinput; + buffer = (char*) malloc(DTOBASESTR_BUFFER_SIZE); + if (buffer) { + p = buffer; + if (dval(d) < 0.0 +#if defined(XP_WIN) || defined(XP_OS2) + && !((word0(d) & Exp_mask) == Exp_mask && ((word0(d) & Frac_mask) || word1(d))) /* Visual C++ doesn't know how to compare against NaN */ +#endif + ) { + *p++ = '-'; + dval(d) = -dval(d); + } + + /* Check for Infinity and NaN */ + if ((word0(d) & Exp_mask) == Exp_mask) { + strcpy(p, !word1(d) && !(word0(d) & Frac_mask) ? "Infinity" : "NaN"); + return buffer; + } + + LOCK_DTOA(); + /* Output the integer part of d with the digits in reverse order. */ + pInt = p; + dval(di) = floor(dval(d)); + if (dval(di) <= 4294967295.0) { + uint32 n = (uint32)dval(di); + if (n) + do { + uint32 m = n / base; + digit = n - m*base; + n = m; + JS_ASSERT(digit < (uint32)base); + *p++ = BASEDIGIT(digit); + } while (n); + else *p++ = '0'; + } else { + int e; + int bits; /* Number of significant bits in di; not used. */ + Bigint *b = d2b(di, &e, &bits); + if (!b) + goto nomem1; + b = lshift(b, e); + if (!b) { + nomem1: + Bfree(b); + UNLOCK_DTOA(); + free(buffer); + return NULL; + } + do { + digit = divrem(b, base); + JS_ASSERT(digit < (uint32)base); + *p++ = BASEDIGIT(digit); + } while (b->wds); + Bfree(b); + } + /* Reverse the digits of the integer part of d. */ + q = p-1; + while (q > pInt) { + char ch = *pInt; + *pInt++ = *q; + *q-- = ch; + } + + dval(df) = dval(d) - dval(di); + if (dval(df) != 0.0) { + /* We have a fraction. */ + int e, bbits; + int32 s2, done; + Bigint *b, *s, *mlo, *mhi; + + b = s = mlo = mhi = NULL; + + *p++ = '.'; + b = d2b(df, &e, &bbits); + if (!b) { + nomem2: + Bfree(b); + Bfree(s); + if (mlo != mhi) + Bfree(mlo); + Bfree(mhi); + UNLOCK_DTOA(); + free(buffer); + return NULL; + } + JS_ASSERT(e < 0); + /* At this point df = b * 2^e. e must be less than zero because 0 < df < 1. */ + + s2 = -(int32)(word0(d) >> Exp_shift1 & Exp_mask>>Exp_shift1); +#ifndef Sudden_Underflow + if (!s2) + s2 = -1; +#endif + s2 += Bias + P; + /* 1/2^s2 = (nextDouble(d) - d)/2 */ + JS_ASSERT(-s2 < e); + mlo = i2b(1); + if (!mlo) + goto nomem2; + mhi = mlo; + if (!word1(d) && !(word0(d) & Bndry_mask) +#ifndef Sudden_Underflow + && word0(d) & (Exp_mask & Exp_mask << 1) +#endif + ) { + /* The special case. Here we want to be within a quarter of the last input + significant digit instead of one half of it when the output string's value is less than d. */ + s2 += Log2P; + mhi = i2b(1<<Log2P); + if (!mhi) + goto nomem2; + } + b = lshift(b, e + s2); + if (!b) + goto nomem2; + s = i2b(1); + if (!s) + goto nomem2; + s = lshift(s, s2); + if (!s) + goto nomem2; + /* At this point we have the following: + * s = 2^s2; + * 1 > df = b/2^s2 > 0; + * (d - prevDouble(d))/2 = mlo/2^s2; + * (nextDouble(d) - d)/2 = mhi/2^s2. */ + + done = JS_FALSE; + do { + int32 j, j1; + Bigint *delta; + + b = multadd(b, base, 0); + if (!b) + goto nomem2; + digit = quorem2(b, s2); + if (mlo == mhi) { + mlo = mhi = multadd(mlo, base, 0); + if (!mhi) + goto nomem2; + } + else { + mlo = multadd(mlo, base, 0); + if (!mlo) + goto nomem2; + mhi = multadd(mhi, base, 0); + if (!mhi) + goto nomem2; + } + + /* Do we yet have the shortest string that will round to d? */ + j = cmp(b, mlo); + /* j is b/2^s2 compared with mlo/2^s2. */ + delta = diff(s, mhi); + if (!delta) + goto nomem2; + j1 = delta->sign ? 1 : cmp(b, delta); + Bfree(delta); + /* j1 is b/2^s2 compared with 1 - mhi/2^s2. */ + +#ifndef ROUND_BIASED + if (j1 == 0 && !(word1(d) & 1)) { + if (j > 0) + digit++; + done = JS_TRUE; + } else +#endif + if (j < 0 || (j == 0 +#ifndef ROUND_BIASED + && !(word1(d) & 1) +#endif + )) { + if (j1 > 0) { + /* Either dig or dig+1 would work here as the least significant digit. + Use whichever would produce an output value closer to d. */ + b = lshift(b, 1); + if (!b) + goto nomem2; + j1 = cmp(b, s); + if (j1 > 0) /* The even test (|| (j1 == 0 && (digit & 1))) is not here because it messes up odd base output + * such as 3.5 in base 3. */ + digit++; + } + done = JS_TRUE; + } else if (j1 > 0) { + digit++; + done = JS_TRUE; + } + JS_ASSERT(digit < (uint32)base); + *p++ = BASEDIGIT(digit); + } while (!done); + Bfree(b); + Bfree(s); + if (mlo != mhi) + Bfree(mlo); + Bfree(mhi); + } + JS_ASSERT(p < buffer + DTOBASESTR_BUFFER_SIZE); + *p = '\0'; + UNLOCK_DTOA(); + } + return buffer; +} |