| OLD | NEW |
| 1 // Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file |
| 2 // for details. All rights reserved. Use of this source code is governed by a | 2 // for details. All rights reserved. Use of this source code is governed by a |
| 3 // BSD-style license that can be found in the LICENSE file. | 3 // BSD-style license that can be found in the LICENSE file. |
| 4 | 4 |
| 5 #include "vm/double_conversion.h" | 5 #include "vm/double_conversion.h" |
| 6 | 6 |
| 7 #include "third_party/double-conversion/src/double-conversion.h" | 7 #include "third_party/double-conversion/src/double-conversion.h" |
| 8 | 8 |
| 9 #include "vm/exceptions.h" | 9 #include "vm/exceptions.h" |
| 10 #include "vm/globals.h" | 10 #include "vm/globals.h" |
| 11 #include "vm/object.h" | 11 #include "vm/object.h" |
| 12 | 12 |
| 13 namespace dart { | 13 namespace dart { |
| 14 | 14 |
| 15 static const char kDoubleToStringCommonExponentChar = 'e'; | 15 static const char kDoubleToStringCommonExponentChar = 'e'; |
| 16 static const char* kDoubleToStringCommonInfinitySymbol = "Infinity"; | 16 static const char* kDoubleToStringCommonInfinitySymbol = "Infinity"; |
| 17 static const char* kDoubleToStringCommonNaNSymbol = "NaN"; | 17 static const char* kDoubleToStringCommonNaNSymbol = "NaN"; |
| 18 | 18 |
| 19 bool DoubleToString(double d, String& result) { | 19 void DoubleToCString(double d, char* buffer, int buffer_size) { |
| 20 static const int kDecimalLow = -6; | 20 static const int kDecimalLow = -6; |
| 21 static const int kDecimalHigh = 21; | 21 static const int kDecimalHigh = 21; |
| 22 |
| 23 // The output contains the sign, at most kDecimalHigh - 1 digits, |
| 24 // the decimal point followed by a 0 plus the \0. |
| 25 ASSERT(buffer_size >= 1 + (kDecimalHigh - 1) + 1 + 1 + 1); |
| 26 // Or it contains the sign, a 0, the decimal point, kDecimalLow '0's, |
| 27 // 17 digits (the precision needed for doubles), plus the \0. |
| 28 ASSERT(buffer_size >= 1 + 1 + 1 + kDecimalLow + 17 + 1); |
| 29 // Alternatively it contains a sign, at most 17 digits (precision needed for |
| 30 // any double), the decimal point, the exponent character, the exponent's |
| 31 // sign, at most three exponent digits, plus the \0. |
| 32 ASSERT(buffer_size >= 1 + 17 + 1 + 1 + 1 + 3 + 1); |
| 33 |
| 22 static const int kConversionFlags = | 34 static const int kConversionFlags = |
| 23 double_conversion::DoubleToStringConverter::EMIT_POSITIVE_EXPONENT_SIGN | | 35 double_conversion::DoubleToStringConverter::EMIT_POSITIVE_EXPONENT_SIGN | |
| 24 double_conversion::DoubleToStringConverter::EMIT_TRAILING_DECIMAL_POINT | | 36 double_conversion::DoubleToStringConverter::EMIT_TRAILING_DECIMAL_POINT | |
| 25 double_conversion::DoubleToStringConverter::EMIT_TRAILING_ZERO_AFTER_POINT; | 37 double_conversion::DoubleToStringConverter::EMIT_TRAILING_ZERO_AFTER_POINT; |
| 26 const int kBufferSize = 128; | |
| 27 // The output contains the sign, at most kDecimalHigh - 1 digits, | |
| 28 // the decimal point followed by a 0 plus the \0. | |
| 29 ASSERT(kBufferSize >= 1 + (kDecimalHigh - 1) + 1 + 1 + 1); | |
| 30 // Or it contains the sign, a 0, the decimal point, kDecimalLow '0's, | |
| 31 // 17 digits (the precision needed for doubles), plus the \0. | |
| 32 ASSERT(kBufferSize >= 1 + 1 + 1 + kDecimalLow + 17 + 1); | |
| 33 // Alternatively it contains a sign, at most 17 digits (precision needed for | |
| 34 // any double), the decimal point, the exponent character, the exponent's | |
| 35 // sign, at most three exponent digits, plus the \0. | |
| 36 ASSERT(kBufferSize >= 1 + 17 + 1 + 1 + 1 + 3 + 1); | |
| 37 | 38 |
| 38 const double_conversion::DoubleToStringConverter converter( | 39 const double_conversion::DoubleToStringConverter converter( |
| 39 kConversionFlags, | 40 kConversionFlags, |
| 40 kDoubleToStringCommonInfinitySymbol, | 41 kDoubleToStringCommonInfinitySymbol, |
| 41 kDoubleToStringCommonNaNSymbol, | 42 kDoubleToStringCommonNaNSymbol, |
| 42 kDoubleToStringCommonExponentChar, | 43 kDoubleToStringCommonExponentChar, |
| 43 kDecimalLow, | 44 kDecimalLow, |
| 44 kDecimalHigh, | 45 kDecimalHigh, |
| 45 0, 0); // Last two values are ignored in shortest mode. | 46 0, 0); // Last two values are ignored in shortest mode. |
| 46 | 47 |
| 47 UNIMPLEMENTED(); | 48 double_conversion::StringBuilder builder(buffer, buffer_size); |
| 48 return false; | 49 bool status = converter.ToShortest(d, &builder); |
| 50 ASSERT(status); |
| 51 char* result = builder.Finalize(); |
| 52 ASSERT(result == buffer); |
| 49 } | 53 } |
| 50 | 54 |
| 51 bool DoubleToStringAsFixed(double d, int fraction_digits, String& result) { | 55 RawString* DoubleToStringAsFixed(double d, int fraction_digits) { |
| 52 static const int kMinFractionDigits = 0; | 56 static const int kMinFractionDigits = 0; |
| 53 static const int kMaxFractionDigits = 20; | 57 static const int kMaxFractionDigits = 20; |
| 54 static const int kMaxDigitsBeforePoint = 20; | 58 static const int kMaxDigitsBeforePoint = 20; |
| 55 // The boundaries are exclusive. | 59 // The boundaries are exclusive. |
| 56 static const double kLowerBoundary = -1e21; | 60 static const double kLowerBoundary = -1e21; |
| 57 static const double kUpperBoundary = 1e21; | 61 static const double kUpperBoundary = 1e21; |
| 58 // TODO(floitsch): remove the UNIQUE_ZERO flag when the test is updated. | 62 // TODO(floitsch): remove the UNIQUE_ZERO flag when the test is updated. |
| 59 static const int kConversionFlags = | 63 static const int kConversionFlags = |
| 60 double_conversion::DoubleToStringConverter::UNIQUE_ZERO; | 64 double_conversion::DoubleToStringConverter::NO_FLAGS; |
| 61 const int kBufferSize = 128; | 65 const int kBufferSize = 128; |
| 66 |
| 67 USE(kMaxDigitsBeforePoint); |
| 68 USE(kMaxFractionDigits); |
| 69 USE(kLowerBoundary); |
| 70 USE(kUpperBoundary); |
| 71 USE(kMinFractionDigits); |
| 72 USE(kMaxFractionDigits); |
| 62 // The output contains the sign, at most kMaxDigitsBeforePoint digits, | 73 // The output contains the sign, at most kMaxDigitsBeforePoint digits, |
| 63 // the decimal point followed by at most fraction_digits digits plus the \0. | 74 // the decimal point followed by at most fraction_digits digits plus the \0. |
| 64 ASSERT(kBufferSize >= 1 + kMaxDigitsBeforePoint + 1 + kMaxFractionDigits + 1); | 75 ASSERT(kBufferSize >= 1 + kMaxDigitsBeforePoint + 1 + kMaxFractionDigits + 1); |
| 65 | 76 |
| 66 if (d <= kLowerBoundary || d >= kUpperBoundary) { | 77 ASSERT(kLowerBoundary < d && d < kUpperBoundary); |
| 67 return false; | 78 |
| 68 } | 79 ASSERT(kMinFractionDigits <= fraction_digits && |
| 69 if (fraction_digits < kMinFractionDigits || | 80 fraction_digits <= kMaxFractionDigits); |
| 70 fraction_digits > kMaxFractionDigits) { | |
| 71 return false; | |
| 72 } | |
| 73 | 81 |
| 74 const double_conversion::DoubleToStringConverter converter( | 82 const double_conversion::DoubleToStringConverter converter( |
| 75 kConversionFlags, | 83 kConversionFlags, |
| 76 kDoubleToStringCommonInfinitySymbol, | 84 kDoubleToStringCommonInfinitySymbol, |
| 77 kDoubleToStringCommonNaNSymbol, | 85 kDoubleToStringCommonNaNSymbol, |
| 78 kDoubleToStringCommonExponentChar, | 86 kDoubleToStringCommonExponentChar, |
| 79 0, 0, 0, 0); // Last four values are ignored in fixed mode. | 87 0, 0, 0, 0); // Last four values are ignored in fixed mode. |
| 80 | 88 |
| 81 char buffer[kBufferSize]; | 89 char* buffer = reinterpret_cast<char*>( |
| 90 Isolate::Current()->current_zone()->Allocate(kBufferSize)); |
| 91 buffer[kBufferSize - 1] = '\0'; |
| 82 double_conversion::StringBuilder builder(buffer, kBufferSize); | 92 double_conversion::StringBuilder builder(buffer, kBufferSize); |
| 83 bool status = converter.ToFixed(d, fraction_digits, &builder); | 93 bool status = converter.ToFixed(d, fraction_digits, &builder); |
| 84 if (!status) return false; | 94 ASSERT(status); |
| 85 int length = builder.position(); | 95 int length = builder.position(); |
| 86 result ^= String::New(reinterpret_cast<uint8_t*>(builder.Finalize()), length); | 96 return String::New(reinterpret_cast<uint8_t*>(builder.Finalize()), length); |
| 87 return true; | |
| 88 } | 97 } |
| 89 | 98 |
| 90 | 99 |
| 91 bool DoubleToStringAsExponential(double d, | 100 RawString* DoubleToStringAsExponential(double d, int fraction_digits) { |
| 92 int fraction_digits, | 101 static const int kMinFractionDigits = -1; // -1 represents shortest mode. |
| 93 String& result) { | |
| 94 static const int kMinFractionDigits = 0; | |
| 95 static const int kMaxFractionDigits = 20; | 102 static const int kMaxFractionDigits = 20; |
| 96 static const int kConversionFlags = | 103 static const int kConversionFlags = |
| 97 double_conversion::DoubleToStringConverter::EMIT_POSITIVE_EXPONENT_SIGN; | 104 double_conversion::DoubleToStringConverter::EMIT_POSITIVE_EXPONENT_SIGN; |
| 98 const int kBufferSize = 128; | 105 const int kBufferSize = 128; |
| 106 |
| 107 USE(kMinFractionDigits); |
| 108 USE(kMaxFractionDigits); |
| 99 // The output contains the sign, at most 1 digits, the decimal point followed | 109 // The output contains the sign, at most 1 digits, the decimal point followed |
| 100 // by at most kMaxFractionDigits digits, the exponent-character, the | 110 // by at most kMaxFractionDigits digits, the exponent-character, the |
| 101 // exponent-sign and three exponent digits plus \0. | 111 // exponent-sign and three exponent digits plus \0. |
| 102 ASSERT(kBufferSize >= 1 + 1 + kMaxFractionDigits + 1 + 1 + 3 + 1); | 112 ASSERT(kBufferSize >= 1 + 1 + kMaxFractionDigits + 1 + 1 + 3 + 1); |
| 103 | 113 |
| 104 if (!(kMinFractionDigits <= fraction_digits && | 114 ASSERT(kMinFractionDigits <= fraction_digits && |
| 105 fraction_digits <= kMaxFractionDigits)) { | 115 fraction_digits <= kMaxFractionDigits); |
| 106 return false; | |
| 107 } | |
| 108 | 116 |
| 109 const double_conversion::DoubleToStringConverter converter( | 117 const double_conversion::DoubleToStringConverter converter( |
| 110 kConversionFlags, | 118 kConversionFlags, |
| 111 kDoubleToStringCommonInfinitySymbol, | 119 kDoubleToStringCommonInfinitySymbol, |
| 112 kDoubleToStringCommonNaNSymbol, | 120 kDoubleToStringCommonNaNSymbol, |
| 113 kDoubleToStringCommonExponentChar, | 121 kDoubleToStringCommonExponentChar, |
| 114 0, 0, 0, 0); // Last four values are ignored in exponential mode. | 122 0, 0, 0, 0); // Last four values are ignored in exponential mode. |
| 115 | 123 |
| 116 UNIMPLEMENTED(); | 124 char* buffer = reinterpret_cast<char*>( |
| 117 return false; | 125 Isolate::Current()->current_zone()->Allocate(kBufferSize)); |
| 126 buffer[kBufferSize - 1] = '\0'; |
| 127 double_conversion::StringBuilder builder(buffer, kBufferSize); |
| 128 bool status = converter.ToExponential(d, fraction_digits, &builder); |
| 129 ASSERT(status); |
| 130 int length = builder.position(); |
| 131 return String::New(reinterpret_cast<uint8_t*>(builder.Finalize()), length); |
| 118 } | 132 } |
| 119 | 133 |
| 120 | 134 |
| 121 bool DoubleToStringAsPrecision(double d, int precision, String& result) { | 135 RawString* DoubleToStringAsPrecision(double d, int precision) { |
| 122 static const int kMinPrecisionDigits = 1; | 136 static const int kMinPrecisionDigits = 1; |
| 123 static const int kMaxPrecisionDigits = 21; | 137 static const int kMaxPrecisionDigits = 21; |
| 124 static const int kMaxLeadingPaddingZeroes = 6; | 138 static const int kMaxLeadingPaddingZeroes = 6; |
| 125 static const int kMaxTrailingPaddingZeroes = 0; | 139 static const int kMaxTrailingPaddingZeroes = 0; |
| 126 static const int kConversionFlags = | 140 static const int kConversionFlags = |
| 127 double_conversion::DoubleToStringConverter::EMIT_POSITIVE_EXPONENT_SIGN; | 141 double_conversion::DoubleToStringConverter::EMIT_POSITIVE_EXPONENT_SIGN; |
| 128 const int kBufferSize = 128; | 142 const int kBufferSize = 128; |
| 129 // The output contains the sign, the decimal point, precision digits, | 143 |
| 144 USE(kMinPrecisionDigits); |
| 145 USE(kMaxPrecisionDigits); |
| 146 // The output contains the sign, a potential leading 0, the decimal point, |
| 147 // at most kMax{Leading|Trailing} padding zeroes, precision digits, |
| 130 // the exponent-character, the exponent-sign, three exponent digits | 148 // the exponent-character, the exponent-sign, three exponent digits |
| 131 // plus the \0. | 149 // plus the \0. |
| 132 ASSERT(kBufferSize >= 1 + 1 + kMaxPrecisionDigits + 1 + 1 + 3 + 1); | 150 // Note that padding and exponent are exclusive. We still add them up. |
| 151 ASSERT(kBufferSize >= 1 + 1 + 1 + kMaxLeadingPaddingZeroes + |
| 152 kMaxTrailingPaddingZeroes + kMaxPrecisionDigits + 1 + 1 + 3 + 1); |
| 133 | 153 |
| 134 if (!(kMinPrecisionDigits <= precision && precision <= kMaxPrecisionDigits)) { | 154 ASSERT(kMinPrecisionDigits <= precision && precision <= kMaxPrecisionDigits); |
| 135 return false; | |
| 136 } | |
| 137 | 155 |
| 138 const double_conversion::DoubleToStringConverter converter( | 156 const double_conversion::DoubleToStringConverter converter( |
| 139 kConversionFlags, | 157 kConversionFlags, |
| 140 kDoubleToStringCommonInfinitySymbol, | 158 kDoubleToStringCommonInfinitySymbol, |
| 141 kDoubleToStringCommonNaNSymbol, | 159 kDoubleToStringCommonNaNSymbol, |
| 142 kDoubleToStringCommonExponentChar, | 160 kDoubleToStringCommonExponentChar, |
| 143 0, 0, // Ignored in precision mode. | 161 0, 0, // Ignored in precision mode. |
| 144 kMaxLeadingPaddingZeroes, | 162 kMaxLeadingPaddingZeroes, |
| 145 kMaxTrailingPaddingZeroes); | 163 kMaxTrailingPaddingZeroes); |
| 146 | 164 |
| 147 UNIMPLEMENTED(); | 165 char* buffer = reinterpret_cast<char*>( |
| 148 return false; | 166 Isolate::Current()->current_zone()->Allocate(kBufferSize)); |
| 167 buffer[kBufferSize - 1] = '\0'; |
| 168 double_conversion::StringBuilder builder(buffer, kBufferSize); |
| 169 bool status = converter.ToPrecision(d, precision, &builder); |
| 170 ASSERT(status); |
| 171 int length = builder.position(); |
| 172 return String::New(reinterpret_cast<uint8_t*>(builder.Finalize()), length); |
| 149 } | 173 } |
| 150 | 174 |
| 151 } // namespace dart | 175 } // namespace dart |
| OLD | NEW |