|  | // Copyright (c) 2011, the Dart project authors.  Please see the AUTHORS file | 
|  | // for details. All rights reserved. Use of this source code is governed by a | 
|  | // BSD-style license that can be found in the LICENSE file. | 
|  |  | 
|  | #include "vm/double_conversion.h" | 
|  |  | 
|  | #include "third_party/double-conversion/src/double-conversion.h" | 
|  |  | 
|  | #include "vm/exceptions.h" | 
|  | #include "vm/globals.h" | 
|  | #include "vm/object.h" | 
|  |  | 
|  | namespace dart { | 
|  |  | 
|  | char const DoubleToStringConstants::kExponentChar = 'e'; | 
|  | const char* const DoubleToStringConstants::kInfinitySymbol = "Infinity"; | 
|  | const char* const DoubleToStringConstants::kNaNSymbol = "NaN"; | 
|  |  | 
|  | void DoubleToCString(double d, char* buffer, int buffer_size) { | 
|  | static const int kDecimalLow = -6; | 
|  | static const int kDecimalHigh = 21; | 
|  |  | 
|  | // The output contains the sign, at most kDecimalHigh - 1 digits, | 
|  | // the decimal point followed by a 0 plus the \0. | 
|  | ASSERT(buffer_size >= 1 + (kDecimalHigh - 1) + 1 + 1 + 1); | 
|  | // Or it contains the sign, a 0, the decimal point, kDecimalLow '0's, | 
|  | // 17 digits (the precision needed for doubles), plus the \0. | 
|  | ASSERT(buffer_size >= 1 + 1 + 1 + kDecimalLow + 17 + 1); | 
|  | // Alternatively it contains a sign, at most 17 digits (precision needed for | 
|  | // any double), the decimal point, the exponent character, the exponent's | 
|  | // sign, at most three exponent digits, plus the \0. | 
|  | ASSERT(buffer_size >= 1 + 17 + 1 + 1 + 1 + 3 + 1); | 
|  |  | 
|  | static const int kConversionFlags = | 
|  | double_conversion::DoubleToStringConverter::EMIT_POSITIVE_EXPONENT_SIGN | | 
|  | double_conversion::DoubleToStringConverter::EMIT_TRAILING_DECIMAL_POINT | | 
|  | double_conversion::DoubleToStringConverter:: | 
|  | EMIT_TRAILING_ZERO_AFTER_POINT; | 
|  |  | 
|  | const double_conversion::DoubleToStringConverter converter( | 
|  | kConversionFlags, DoubleToStringConstants::kInfinitySymbol, | 
|  | DoubleToStringConstants::kNaNSymbol, | 
|  | DoubleToStringConstants::kExponentChar, kDecimalLow, kDecimalHigh, 0, | 
|  | 0);  // Last two values are ignored in shortest mode. | 
|  |  | 
|  | double_conversion::StringBuilder builder(buffer, buffer_size); | 
|  | bool status = converter.ToShortest(d, &builder); | 
|  | ASSERT(status); | 
|  | char* result = builder.Finalize(); | 
|  | ASSERT(result == buffer); | 
|  | } | 
|  |  | 
|  | StringPtr DoubleToStringAsFixed(double d, int fraction_digits) { | 
|  | static const int kMinFractionDigits = 0; | 
|  | static const int kMaxFractionDigits = 20; | 
|  | static const int kMaxDigitsBeforePoint = 20; | 
|  | // The boundaries are exclusive. | 
|  | static const double kLowerBoundary = -1e21; | 
|  | static const double kUpperBoundary = 1e21; | 
|  | // TODO(floitsch): remove the UNIQUE_ZERO flag when the test is updated. | 
|  | static const int kConversionFlags = | 
|  | double_conversion::DoubleToStringConverter::NO_FLAGS; | 
|  | const int kBufferSize = 128; | 
|  |  | 
|  | USE(kMaxDigitsBeforePoint); | 
|  | USE(kMaxFractionDigits); | 
|  | USE(kLowerBoundary); | 
|  | USE(kUpperBoundary); | 
|  | USE(kMinFractionDigits); | 
|  | USE(kMaxFractionDigits); | 
|  | // The output contains the sign, at most kMaxDigitsBeforePoint digits, | 
|  | // the decimal point followed by at most fraction_digits digits plus the \0. | 
|  | ASSERT(kBufferSize >= 1 + kMaxDigitsBeforePoint + 1 + kMaxFractionDigits + 1); | 
|  |  | 
|  | ASSERT(kLowerBoundary < d && d < kUpperBoundary); | 
|  |  | 
|  | ASSERT(kMinFractionDigits <= fraction_digits && | 
|  | fraction_digits <= kMaxFractionDigits); | 
|  |  | 
|  | const double_conversion::DoubleToStringConverter converter( | 
|  | kConversionFlags, DoubleToStringConstants::kInfinitySymbol, | 
|  | DoubleToStringConstants::kNaNSymbol, | 
|  | DoubleToStringConstants::kExponentChar, 0, 0, 0, | 
|  | 0);  // Last four values are ignored in fixed mode. | 
|  |  | 
|  | char* buffer = Thread::Current()->zone()->Alloc<char>(kBufferSize); | 
|  | buffer[kBufferSize - 1] = '\0'; | 
|  | double_conversion::StringBuilder builder(buffer, kBufferSize); | 
|  | bool status = converter.ToFixed(d, fraction_digits, &builder); | 
|  | ASSERT(status); | 
|  | return String::New(builder.Finalize()); | 
|  | } | 
|  |  | 
|  | StringPtr DoubleToStringAsExponential(double d, int fraction_digits) { | 
|  | static const int kMinFractionDigits = -1;  // -1 represents shortest mode. | 
|  | static const int kMaxFractionDigits = 20; | 
|  | static const int kConversionFlags = | 
|  | double_conversion::DoubleToStringConverter::EMIT_POSITIVE_EXPONENT_SIGN; | 
|  | const int kBufferSize = 128; | 
|  |  | 
|  | USE(kMinFractionDigits); | 
|  | USE(kMaxFractionDigits); | 
|  | // The output contains the sign, at most 1 digits, the decimal point followed | 
|  | // by at most kMaxFractionDigits digits, the exponent-character, the | 
|  | // exponent-sign and three exponent digits plus \0. | 
|  | ASSERT(kBufferSize >= 1 + 1 + kMaxFractionDigits + 1 + 1 + 3 + 1); | 
|  |  | 
|  | ASSERT(kMinFractionDigits <= fraction_digits && | 
|  | fraction_digits <= kMaxFractionDigits); | 
|  |  | 
|  | const double_conversion::DoubleToStringConverter converter( | 
|  | kConversionFlags, DoubleToStringConstants::kInfinitySymbol, | 
|  | DoubleToStringConstants::kNaNSymbol, | 
|  | DoubleToStringConstants::kExponentChar, 0, 0, 0, | 
|  | 0);  // Last four values are ignored in exponential mode. | 
|  |  | 
|  | char* buffer = Thread::Current()->zone()->Alloc<char>(kBufferSize); | 
|  | buffer[kBufferSize - 1] = '\0'; | 
|  | double_conversion::StringBuilder builder(buffer, kBufferSize); | 
|  | bool status = converter.ToExponential(d, fraction_digits, &builder); | 
|  | ASSERT(status); | 
|  | return String::New(builder.Finalize()); | 
|  | } | 
|  |  | 
|  | StringPtr DoubleToStringAsPrecision(double d, int precision) { | 
|  | static const int kMinPrecisionDigits = 1; | 
|  | static const int kMaxPrecisionDigits = 21; | 
|  | static const int kMaxLeadingPaddingZeroes = 6; | 
|  | static const int kMaxTrailingPaddingZeroes = 0; | 
|  | static const int kConversionFlags = | 
|  | double_conversion::DoubleToStringConverter::EMIT_POSITIVE_EXPONENT_SIGN; | 
|  | const int kBufferSize = 128; | 
|  |  | 
|  | USE(kMinPrecisionDigits); | 
|  | USE(kMaxPrecisionDigits); | 
|  | // The output contains the sign, a potential leading 0, the decimal point, | 
|  | // at most kMax{Leading|Trailing} padding zeroes, precision digits, | 
|  | // the exponent-character, the exponent-sign, three exponent digits | 
|  | // plus the \0. | 
|  | // Note that padding and exponent are exclusive. We still add them up. | 
|  | ASSERT(kBufferSize >= 1 + 1 + 1 + kMaxLeadingPaddingZeroes + | 
|  | kMaxTrailingPaddingZeroes + kMaxPrecisionDigits + | 
|  | 1 + 1 + 3 + 1); | 
|  |  | 
|  | ASSERT(kMinPrecisionDigits <= precision && precision <= kMaxPrecisionDigits); | 
|  |  | 
|  | const double_conversion::DoubleToStringConverter converter( | 
|  | kConversionFlags, DoubleToStringConstants::kInfinitySymbol, | 
|  | DoubleToStringConstants::kNaNSymbol, | 
|  | DoubleToStringConstants::kExponentChar, 0, | 
|  | 0,  // Ignored in precision mode. | 
|  | kMaxLeadingPaddingZeroes, kMaxTrailingPaddingZeroes); | 
|  |  | 
|  | char* buffer = Thread::Current()->zone()->Alloc<char>(kBufferSize); | 
|  | buffer[kBufferSize - 1] = '\0'; | 
|  | double_conversion::StringBuilder builder(buffer, kBufferSize); | 
|  | bool status = converter.ToPrecision(d, precision, &builder); | 
|  | ASSERT(status); | 
|  | return String::New(builder.Finalize()); | 
|  | } | 
|  |  | 
|  | bool CStringToDouble(const char* str, intptr_t length, double* result) { | 
|  | if (length == 0) { | 
|  | return false; | 
|  | } | 
|  |  | 
|  | double_conversion::StringToDoubleConverter converter( | 
|  | double_conversion::StringToDoubleConverter::NO_FLAGS, 0.0, 0.0, | 
|  | DoubleToStringConstants::kInfinitySymbol, | 
|  | DoubleToStringConstants::kNaNSymbol); | 
|  |  | 
|  | int parsed_count = 0; | 
|  | *result = | 
|  | converter.StringToDouble(str, static_cast<int>(length), &parsed_count); | 
|  | return (parsed_count == length); | 
|  | } | 
|  |  | 
|  | }  // namespace dart |