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 |