/js/lib/Socket.IO-node/support/expresso/deps/jscoverage/js/jsdtoa.cpp
http://github.com/onedayitwillmake/RealtimeMultiplayerNodeJs · C++ · 572 lines · 433 code · 49 blank · 90 comment · 113 complexity · 904d503b58acd9cbb384d6c6dd923168 MD5 · raw file
- /* -*- 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;
- }