Bug 608915 - part 2 - use MFBT's double-conversion code in nsString::AppendFloat; r=bz,gps

This commit is contained in:
Nathan Froyd 2013-09-24 13:36:55 -04:00
parent a3fdb565b6
commit 0cdfeef8f7
3 changed files with 79 additions and 86 deletions

View File

@ -445,12 +445,8 @@ class nsTSubstring_CharT
/**
* Append the given float to this string
*/
void AppendFloat( float aFloat )
{ DoAppendFloat(aFloat, 6); }
void AppendFloat( double aFloat )
{ DoAppendFloat(aFloat, 15); }
private:
void NS_FASTCALL DoAppendFloat( double aFloat, int digits );
void NS_FASTCALL AppendFloat( float aFloat );
void NS_FASTCALL AppendFloat( double aFloat );
public:
// AppendLiteral must ONLY be applied to an actual literal string.

View File

@ -25,6 +25,10 @@ if CONFIG['INTEL_ARCHITECTURE']:
'nsUTF8UtilsSSE2.cpp',
]
LOCAL_INCLUDES += [
'/mfbt/double-conversion',
]
LIBRARY_NAME = 'string_s'
MSVC_ENABLE_PGO = True

View File

@ -4,7 +4,9 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "mozilla/MemoryReporting.h"
#include "prdtoa.h"
#include "double-conversion.h"
using double_conversion::DoubleToStringConverter;
#ifdef XPCOM_STRING_CONSTRUCTOR_OUT_OF_LINE
nsTSubstring_CharT::nsTSubstring_CharT( char_type *data, size_type length,
@ -790,103 +792,94 @@ void nsTSubstring_CharT::AppendPrintf( const char* format, va_list ap )
NS_RUNTIMEABORT("Allocation or other failure in PR_vsxprintf");
}
/* hack to make sure we define Modified_cnvtf only once */
/* hack to make sure we define FormatWithoutTrailingZeros only once */
#ifdef CharT_is_PRUnichar
/**
* This is a copy of |PR_cnvtf| with a bug fixed. (The second argument
* of PR_dtoa is 2 rather than 1.)
*
* XXX(darin): if this is the right thing, then why wasn't it fixed in NSPR?!?
*/
static void
Modified_cnvtf(char (& buf)[40], int prcsn, double fval)
// Returns the length of the formatted aDouble in buf.
static int
FormatWithoutTrailingZeros(char (& buf)[40], double aDouble,
int precision)
{
int decpt, sign, numdigits;
char num[40];
char *nump;
char *bufp = buf;
char *endnum;
static const DoubleToStringConverter converter(DoubleToStringConverter::UNIQUE_ZERO |
DoubleToStringConverter::EMIT_POSITIVE_EXPONENT_SIGN,
"Infinity",
"NaN",
'e',
-6, 21,
6, 1);
double_conversion::StringBuilder builder(buf, sizeof(buf));
bool exponential_notation = false;
converter.ToPrecision(aDouble, precision, &exponential_notation, &builder);
int length = builder.position();
char* formattedDouble = builder.Finalize();
if (PR_dtoa(fval, 2, prcsn, &decpt, &sign, &endnum, num, sizeof(num))
== PR_FAILURE) {
buf[0] = '\0';
return;
}
numdigits = endnum - num;
nump = num;
/*
* The NSPR code had a fancy way of checking that we weren't dealing
* with -0.0 or -NaN, but I'll just use < instead.
* XXX Should we check !isnan(fval) as well? Is it portable? We
* probably don't need to bother since NAN isn't portable.
*/
if (sign && fval < 0.0f) {
*bufp++ = '-';
// If we have a shorter string than precision, it means we have a special
// value (NaN or Infinity). All other numbers will be formatted with at
// least precision digits.
if (length <= precision) {
return length;
}
if (decpt == 9999) {
while ((*bufp++ = *nump++) != 0) {} /* nothing to execute */
return;
char* end = formattedDouble + length;
char* decimalPoint = strchr(buf, '.');
// No trailing zeros to remove.
if (decimalPoint == nullptr) {
return length;
}
if (decpt > (prcsn+1) || decpt < -(prcsn-1) || decpt < -5) {
*bufp++ = *nump++;
if (numdigits != 1) {
*bufp++ = '.';
if (MOZ_UNLIKELY(exponential_notation)) {
// We need to check for cases like 1.00000e-10 (yes, this is
// disgusting).
char* exponent = end - 1;
for ( ; ; --exponent) {
if (*exponent == 'e') {
break;
}
}
char* zerosBeforeExponent = exponent - 1;
for ( ; zerosBeforeExponent != decimalPoint; --zerosBeforeExponent) {
if (*zerosBeforeExponent != '0') {
break;
}
}
if (zerosBeforeExponent == decimalPoint) {
--zerosBeforeExponent;
}
// Slide the exponent to the left over the trailing zeros. Don't
// worry about copying the trailing NUL character.
size_t exponentSize = end - exponent;
memmove(zerosBeforeExponent + 1, exponent, exponentSize);
length -= exponent - (zerosBeforeExponent + 1);
} else {
char* trailingZeros = end - 1;
for ( ; trailingZeros != decimalPoint; --trailingZeros) {
if (*trailingZeros != '0') {
break;
}
}
if (trailingZeros == decimalPoint) {
--trailingZeros;
}
length -= end - (trailingZeros + 1);
}
while (*nump != '\0') {
*bufp++ = *nump++;
}
*bufp++ = 'e';
PR_snprintf(bufp, sizeof(num) - (bufp - buf), "%+d", decpt-1);
}
else if (decpt >= 0) {
if (decpt == 0) {
*bufp++ = '0';
}
else {
while (decpt--) {
if (*nump != '\0') {
*bufp++ = *nump++;
}
else {
*bufp++ = '0';
}
}
}
if (*nump != '\0') {
*bufp++ = '.';
while (*nump != '\0') {
*bufp++ = *nump++;
}
}
*bufp++ = '\0';
}
else if (decpt < 0) {
*bufp++ = '0';
*bufp++ = '.';
while (decpt++) {
*bufp++ = '0';
}
while (*nump != '\0') {
*bufp++ = *nump++;
}
*bufp++ = '\0';
}
return length;
}
#endif /* CharT_is_PRUnichar */
void
nsTSubstring_CharT::DoAppendFloat( double aFloat, int digits )
nsTSubstring_CharT::AppendFloat( float aFloat )
{
char buf[40];
// Use Modified_cnvtf, which is locale-insensitive, instead of the
// locale-sensitive PR_snprintf or sprintf(3)
Modified_cnvtf(buf, digits, aFloat);
AppendASCII(buf);
int length = FormatWithoutTrailingZeros(buf, aFloat, 6);
AppendASCII(buf, length);
}
void
nsTSubstring_CharT::AppendFloat( double aFloat )
{
char buf[40];
int length = FormatWithoutTrailingZeros(buf, aFloat, 15);
AppendASCII(buf, length);
}
size_t