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 bool DoubleToCString(double d, char* buffer, int buffer_size, |
| 20 int* result_length) { |
20 static const int kDecimalLow = -6; | 21 static const int kDecimalLow = -6; |
21 static const int kDecimalHigh = 21; | 22 static const int kDecimalHigh = 21; |
| 23 |
| 24 // The output contains the sign, at most kDecimalHigh - 1 digits, |
| 25 // the decimal point followed by a 0 plus the \0. |
| 26 ASSERT(buffer_size >= 1 + (kDecimalHigh - 1) + 1 + 1 + 1); |
| 27 // Or it contains the sign, a 0, the decimal point, kDecimalLow '0's, |
| 28 // 17 digits (the precision needed for doubles), plus the \0. |
| 29 ASSERT(buffer_size >= 1 + 1 + 1 + kDecimalLow + 17 + 1); |
| 30 // Alternatively it contains a sign, at most 17 digits (precision needed for |
| 31 // any double), the decimal point, the exponent character, the exponent's |
| 32 // sign, at most three exponent digits, plus the \0. |
| 33 ASSERT(buffer_size >= 1 + 17 + 1 + 1 + 1 + 3 + 1); |
| 34 |
22 static const int kConversionFlags = | 35 static const int kConversionFlags = |
23 double_conversion::DoubleToStringConverter::EMIT_POSITIVE_EXPONENT_SIGN | | 36 double_conversion::DoubleToStringConverter::EMIT_POSITIVE_EXPONENT_SIGN | |
24 double_conversion::DoubleToStringConverter::EMIT_TRAILING_DECIMAL_POINT | | 37 double_conversion::DoubleToStringConverter::EMIT_TRAILING_DECIMAL_POINT | |
25 double_conversion::DoubleToStringConverter::EMIT_TRAILING_ZERO_AFTER_POINT; | 38 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 | 39 |
38 const double_conversion::DoubleToStringConverter converter( | 40 const double_conversion::DoubleToStringConverter converter( |
39 kConversionFlags, | 41 kConversionFlags, |
40 kDoubleToStringCommonInfinitySymbol, | 42 kDoubleToStringCommonInfinitySymbol, |
41 kDoubleToStringCommonNaNSymbol, | 43 kDoubleToStringCommonNaNSymbol, |
42 kDoubleToStringCommonExponentChar, | 44 kDoubleToStringCommonExponentChar, |
43 kDecimalLow, | 45 kDecimalLow, |
44 kDecimalHigh, | 46 kDecimalHigh, |
45 0, 0); // Last two values are ignored in shortest mode. | 47 0, 0); // Last two values are ignored in shortest mode. |
46 | 48 |
47 UNIMPLEMENTED(); | 49 double_conversion::StringBuilder builder(buffer, buffer_size); |
48 return false; | 50 bool status = converter.ToShortest(d, &builder); |
| 51 if (!status) return false; |
| 52 *result_length = builder.position() + 1; // Include trailing \0 character. |
| 53 char* result = builder.Finalize(); |
| 54 ASSERT(result == buffer); |
| 55 return true; |
49 } | 56 } |
50 | 57 |
51 bool DoubleToStringAsFixed(double d, int fraction_digits, String& result) { | 58 RawString* DoubleToStringAsFixed(double d, int fraction_digits) { |
52 static const int kMinFractionDigits = 0; | 59 static const int kMinFractionDigits = 0; |
53 static const int kMaxFractionDigits = 20; | 60 static const int kMaxFractionDigits = 20; |
54 static const int kMaxDigitsBeforePoint = 20; | 61 static const int kMaxDigitsBeforePoint = 20; |
55 // The boundaries are exclusive. | 62 // The boundaries are exclusive. |
56 static const double kLowerBoundary = -1e21; | 63 static const double kLowerBoundary = -1e21; |
57 static const double kUpperBoundary = 1e21; | 64 static const double kUpperBoundary = 1e21; |
58 // TODO(floitsch): remove the UNIQUE_ZERO flag when the test is updated. | 65 // TODO(floitsch): remove the UNIQUE_ZERO flag when the test is updated. |
59 static const int kConversionFlags = | 66 static const int kConversionFlags = |
60 double_conversion::DoubleToStringConverter::UNIQUE_ZERO; | 67 double_conversion::DoubleToStringConverter::NO_FLAGS; |
61 const int kBufferSize = 128; | 68 const int kBufferSize = 128; |
| 69 |
| 70 USE(kMaxDigitsBeforePoint); |
| 71 USE(kMaxFractionDigits); |
| 72 USE(kMinFractionDigits); |
| 73 USE(kMaxFractionDigits); |
62 // The output contains the sign, at most kMaxDigitsBeforePoint digits, | 74 // The output contains the sign, at most kMaxDigitsBeforePoint digits, |
63 // the decimal point followed by at most fraction_digits digits plus the \0. | 75 // the decimal point followed by at most fraction_digits digits plus the \0. |
64 ASSERT(kBufferSize >= 1 + kMaxDigitsBeforePoint + 1 + kMaxFractionDigits + 1); | 76 ASSERT(kBufferSize >= 1 + kMaxDigitsBeforePoint + 1 + kMaxFractionDigits + 1); |
65 | 77 |
66 if (d <= kLowerBoundary || d >= kUpperBoundary) { | 78 if (d <= kLowerBoundary || d >= kUpperBoundary) { |
67 return false; | 79 return NULL; |
68 } | 80 } |
69 if (fraction_digits < kMinFractionDigits || | 81 assert(kMinFractionDigits <= fraction_digits && |
70 fraction_digits > kMaxFractionDigits) { | 82 fraction_digits <= kMaxFractionDigits); |
71 return false; | |
72 } | |
73 | 83 |
74 const double_conversion::DoubleToStringConverter converter( | 84 const double_conversion::DoubleToStringConverter converter( |
75 kConversionFlags, | 85 kConversionFlags, |
76 kDoubleToStringCommonInfinitySymbol, | 86 kDoubleToStringCommonInfinitySymbol, |
77 kDoubleToStringCommonNaNSymbol, | 87 kDoubleToStringCommonNaNSymbol, |
78 kDoubleToStringCommonExponentChar, | 88 kDoubleToStringCommonExponentChar, |
79 0, 0, 0, 0); // Last four values are ignored in fixed mode. | 89 0, 0, 0, 0); // Last four values are ignored in fixed mode. |
80 | 90 |
81 char buffer[kBufferSize]; | 91 char buffer[kBufferSize]; |
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 if (!status) return NULL; |
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[kBufferSize]; |
117 return false; | 125 double_conversion::StringBuilder builder(buffer, kBufferSize); |
| 126 bool status = converter.ToExponential(d, fraction_digits, &builder); |
| 127 if (!status) return NULL; |
| 128 int length = builder.position(); |
| 129 return String::New(reinterpret_cast<uint8_t*>(builder.Finalize()), length); |
118 } | 130 } |
119 | 131 |
120 | 132 |
121 bool DoubleToStringAsPrecision(double d, int precision, String& result) { | 133 RawString* DoubleToStringAsPrecision(double d, int precision) { |
122 static const int kMinPrecisionDigits = 1; | 134 static const int kMinPrecisionDigits = 1; |
123 static const int kMaxPrecisionDigits = 21; | 135 static const int kMaxPrecisionDigits = 21; |
124 static const int kMaxLeadingPaddingZeroes = 6; | 136 static const int kMaxLeadingPaddingZeroes = 6; |
125 static const int kMaxTrailingPaddingZeroes = 0; | 137 static const int kMaxTrailingPaddingZeroes = 0; |
126 static const int kConversionFlags = | 138 static const int kConversionFlags = |
127 double_conversion::DoubleToStringConverter::EMIT_POSITIVE_EXPONENT_SIGN; | 139 double_conversion::DoubleToStringConverter::EMIT_POSITIVE_EXPONENT_SIGN; |
128 const int kBufferSize = 128; | 140 const int kBufferSize = 128; |
| 141 |
| 142 USE(kMinPrecisionDigits); |
| 143 USE(kMaxPrecisionDigits); |
129 // The output contains the sign, the decimal point, precision digits, | 144 // The output contains the sign, the decimal point, precision digits, |
130 // the exponent-character, the exponent-sign, three exponent digits | 145 // the exponent-character, the exponent-sign, three exponent digits |
131 // plus the \0. | 146 // plus the \0. |
132 ASSERT(kBufferSize >= 1 + 1 + kMaxPrecisionDigits + 1 + 1 + 3 + 1); | 147 ASSERT(kBufferSize >= 1 + 1 + kMaxPrecisionDigits + 1 + 1 + 3 + 1); |
133 | 148 |
134 if (!(kMinPrecisionDigits <= precision && precision <= kMaxPrecisionDigits)) { | 149 assert(kMinPrecisionDigits <= precision && precision <= kMaxPrecisionDigits); |
135 return false; | |
136 } | |
137 | 150 |
138 const double_conversion::DoubleToStringConverter converter( | 151 const double_conversion::DoubleToStringConverter converter( |
139 kConversionFlags, | 152 kConversionFlags, |
140 kDoubleToStringCommonInfinitySymbol, | 153 kDoubleToStringCommonInfinitySymbol, |
141 kDoubleToStringCommonNaNSymbol, | 154 kDoubleToStringCommonNaNSymbol, |
142 kDoubleToStringCommonExponentChar, | 155 kDoubleToStringCommonExponentChar, |
143 0, 0, // Ignored in precision mode. | 156 0, 0, // Ignored in precision mode. |
144 kMaxLeadingPaddingZeroes, | 157 kMaxLeadingPaddingZeroes, |
145 kMaxTrailingPaddingZeroes); | 158 kMaxTrailingPaddingZeroes); |
146 | 159 |
147 UNIMPLEMENTED(); | 160 char buffer[kBufferSize]; |
148 return false; | 161 double_conversion::StringBuilder builder(buffer, kBufferSize); |
| 162 bool status = converter.ToPrecision(d, precision, &builder); |
| 163 if (!status) return NULL; |
| 164 int length = builder.position(); |
| 165 return String::New(reinterpret_cast<uint8_t*>(builder.Finalize()), length); |
149 } | 166 } |
150 | 167 |
151 } // namespace dart | 168 } // namespace dart |
OLD | NEW |