1 // © 2018 and later: Unicode, Inc. and others.
2 // License & terms of use: http://www.unicode.org/copyright.html
4 // From the double-conversion library. Original license:
6 // Copyright 2010 the V8 project authors. All rights reserved.
7 // Redistribution and use in source and binary forms, with or without
8 // modification, are permitted provided that the following conditions are
11 // * Redistributions of source code must retain the above copyright
12 // notice, this list of conditions and the following disclaimer.
13 // * Redistributions in binary form must reproduce the above
14 // copyright notice, this list of conditions and the following
15 // disclaimer in the documentation and/or other materials provided
16 // with the distribution.
17 // * Neither the name of Google Inc. nor the names of its
18 // contributors may be used to endorse or promote products derived
19 // from this software without specific prior written permission.
21 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
24 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
25 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
26 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
27 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
28 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
29 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
30 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
31 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
33 // ICU PATCH: ifdef around UCONFIG_NO_FORMATTING
34 #include "unicode/utypes.h"
35 #if !UCONFIG_NO_FORMATTING
41 // ICU PATCH: Customize header file paths for ICU.
42 // The file fixed-dtoa.h is not needed.
44 #include "double-conversion-double-to-string.h"
46 #include "double-conversion-bignum-dtoa.h"
47 #include "double-conversion-fast-dtoa.h"
48 #include "double-conversion-ieee.h"
49 #include "double-conversion-utils.h"
51 // ICU PATCH: Wrap in ICU namespace
54 namespace double_conversion
{
56 #if 0 // not needed for ICU
57 const DoubleToStringConverter
& DoubleToStringConverter::EcmaScriptConverter() {
58 int flags
= UNIQUE_ZERO
| EMIT_POSITIVE_EXPONENT_SIGN
;
59 static DoubleToStringConverter
converter(flags
,
69 bool DoubleToStringConverter::HandleSpecialValues(
71 StringBuilder
* result_builder
) const {
72 Double
double_inspect(value
);
73 if (double_inspect
.IsInfinite()) {
74 if (infinity_symbol_
== NULL
) return false;
76 result_builder
->AddCharacter('-');
78 result_builder
->AddString(infinity_symbol_
);
81 if (double_inspect
.IsNan()) {
82 if (nan_symbol_
== NULL
) return false;
83 result_builder
->AddString(nan_symbol_
);
90 void DoubleToStringConverter::CreateExponentialRepresentation(
91 const char* decimal_digits
,
94 StringBuilder
* result_builder
) const {
95 DOUBLE_CONVERSION_ASSERT(length
!= 0);
96 result_builder
->AddCharacter(decimal_digits
[0]);
98 result_builder
->AddCharacter('.');
99 result_builder
->AddSubstring(&decimal_digits
[1], length
-1);
101 result_builder
->AddCharacter(exponent_character_
);
103 result_builder
->AddCharacter('-');
104 exponent
= -exponent
;
106 if ((flags_
& EMIT_POSITIVE_EXPONENT_SIGN
) != 0) {
107 result_builder
->AddCharacter('+');
111 result_builder
->AddCharacter('0');
114 DOUBLE_CONVERSION_ASSERT(exponent
< 1e4
);
115 // Changing this constant requires updating the comment of DoubleToStringConverter constructor
116 const int kMaxExponentLength
= 5;
117 char buffer
[kMaxExponentLength
+ 1];
118 buffer
[kMaxExponentLength
] = '\0';
119 int first_char_pos
= kMaxExponentLength
;
120 while (exponent
> 0) {
121 buffer
[--first_char_pos
] = '0' + (exponent
% 10);
124 // Add prefix '0' to make exponent width >= min(min_exponent_with_, kMaxExponentLength)
125 // For example: convert 1e+9 -> 1e+09, if min_exponent_with_ is set to 2
126 while(kMaxExponentLength
- first_char_pos
< std::min(min_exponent_width_
, kMaxExponentLength
)) {
127 buffer
[--first_char_pos
] = '0';
129 result_builder
->AddSubstring(&buffer
[first_char_pos
],
130 kMaxExponentLength
- first_char_pos
);
134 void DoubleToStringConverter::CreateDecimalRepresentation(
135 const char* decimal_digits
,
138 int digits_after_point
,
139 StringBuilder
* result_builder
) const {
140 // Create a representation that is padded with zeros if needed.
141 if (decimal_point
<= 0) {
142 // "0.00000decimal_rep" or "0.000decimal_rep00".
143 result_builder
->AddCharacter('0');
144 if (digits_after_point
> 0) {
145 result_builder
->AddCharacter('.');
146 result_builder
->AddPadding('0', -decimal_point
);
147 DOUBLE_CONVERSION_ASSERT(length
<= digits_after_point
- (-decimal_point
));
148 result_builder
->AddSubstring(decimal_digits
, length
);
149 int remaining_digits
= digits_after_point
- (-decimal_point
) - length
;
150 result_builder
->AddPadding('0', remaining_digits
);
152 } else if (decimal_point
>= length
) {
153 // "decimal_rep0000.00000" or "decimal_rep.0000".
154 result_builder
->AddSubstring(decimal_digits
, length
);
155 result_builder
->AddPadding('0', decimal_point
- length
);
156 if (digits_after_point
> 0) {
157 result_builder
->AddCharacter('.');
158 result_builder
->AddPadding('0', digits_after_point
);
161 // "decima.l_rep000".
162 DOUBLE_CONVERSION_ASSERT(digits_after_point
> 0);
163 result_builder
->AddSubstring(decimal_digits
, decimal_point
);
164 result_builder
->AddCharacter('.');
165 DOUBLE_CONVERSION_ASSERT(length
- decimal_point
<= digits_after_point
);
166 result_builder
->AddSubstring(&decimal_digits
[decimal_point
],
167 length
- decimal_point
);
168 int remaining_digits
= digits_after_point
- (length
- decimal_point
);
169 result_builder
->AddPadding('0', remaining_digits
);
171 if (digits_after_point
== 0) {
172 if ((flags_
& EMIT_TRAILING_DECIMAL_POINT
) != 0) {
173 result_builder
->AddCharacter('.');
175 if ((flags_
& EMIT_TRAILING_ZERO_AFTER_POINT
) != 0) {
176 result_builder
->AddCharacter('0');
182 bool DoubleToStringConverter::ToShortestIeeeNumber(
184 StringBuilder
* result_builder
,
185 DoubleToStringConverter::DtoaMode mode
) const {
186 DOUBLE_CONVERSION_ASSERT(mode
== SHORTEST
|| mode
== SHORTEST_SINGLE
);
187 if (Double(value
).IsSpecial()) {
188 return HandleSpecialValues(value
, result_builder
);
193 const int kDecimalRepCapacity
= kBase10MaximalLength
+ 1;
194 char decimal_rep
[kDecimalRepCapacity
];
195 int decimal_rep_length
;
197 DoubleToAscii(value
, mode
, 0, decimal_rep
, kDecimalRepCapacity
,
198 &sign
, &decimal_rep_length
, &decimal_point
);
200 bool unique_zero
= (flags_
& UNIQUE_ZERO
) != 0;
201 if (sign
&& (value
!= 0.0 || !unique_zero
)) {
202 result_builder
->AddCharacter('-');
205 int exponent
= decimal_point
- 1;
206 if ((decimal_in_shortest_low_
<= exponent
) &&
207 (exponent
< decimal_in_shortest_high_
)) {
208 CreateDecimalRepresentation(decimal_rep
, decimal_rep_length
,
210 (std::max
)(0, decimal_rep_length
- decimal_point
),
213 CreateExponentialRepresentation(decimal_rep
, decimal_rep_length
, exponent
,
220 bool DoubleToStringConverter::ToFixed(double value
,
221 int requested_digits
,
222 StringBuilder
* result_builder
) const {
223 DOUBLE_CONVERSION_ASSERT(kMaxFixedDigitsBeforePoint
== 60);
224 const double kFirstNonFixed
= 1e60
;
226 if (Double(value
).IsSpecial()) {
227 return HandleSpecialValues(value
, result_builder
);
230 if (requested_digits
> kMaxFixedDigitsAfterPoint
) return false;
231 if (value
>= kFirstNonFixed
|| value
<= -kFirstNonFixed
) return false;
233 // Find a sufficiently precise decimal representation of n.
236 // Add space for the '\0' byte.
237 const int kDecimalRepCapacity
=
238 kMaxFixedDigitsBeforePoint
+ kMaxFixedDigitsAfterPoint
+ 1;
239 char decimal_rep
[kDecimalRepCapacity
];
240 int decimal_rep_length
;
241 DoubleToAscii(value
, FIXED
, requested_digits
,
242 decimal_rep
, kDecimalRepCapacity
,
243 &sign
, &decimal_rep_length
, &decimal_point
);
245 bool unique_zero
= ((flags_
& UNIQUE_ZERO
) != 0);
246 if (sign
&& (value
!= 0.0 || !unique_zero
)) {
247 result_builder
->AddCharacter('-');
250 CreateDecimalRepresentation(decimal_rep
, decimal_rep_length
, decimal_point
,
251 requested_digits
, result_builder
);
256 bool DoubleToStringConverter::ToExponential(
258 int requested_digits
,
259 StringBuilder
* result_builder
) const {
260 if (Double(value
).IsSpecial()) {
261 return HandleSpecialValues(value
, result_builder
);
264 if (requested_digits
< -1) return false;
265 if (requested_digits
> kMaxExponentialDigits
) return false;
269 // Add space for digit before the decimal point and the '\0' character.
270 const int kDecimalRepCapacity
= kMaxExponentialDigits
+ 2;
271 DOUBLE_CONVERSION_ASSERT(kDecimalRepCapacity
> kBase10MaximalLength
);
272 char decimal_rep
[kDecimalRepCapacity
];
274 // Problem: there is an assert in StringBuilder::AddSubstring() that
275 // will pass this buffer to strlen(), and this buffer is not generally
277 memset(decimal_rep
, 0, sizeof(decimal_rep
));
279 int decimal_rep_length
;
281 if (requested_digits
== -1) {
282 DoubleToAscii(value
, SHORTEST
, 0,
283 decimal_rep
, kDecimalRepCapacity
,
284 &sign
, &decimal_rep_length
, &decimal_point
);
286 DoubleToAscii(value
, PRECISION
, requested_digits
+ 1,
287 decimal_rep
, kDecimalRepCapacity
,
288 &sign
, &decimal_rep_length
, &decimal_point
);
289 DOUBLE_CONVERSION_ASSERT(decimal_rep_length
<= requested_digits
+ 1);
291 for (int i
= decimal_rep_length
; i
< requested_digits
+ 1; ++i
) {
292 decimal_rep
[i
] = '0';
294 decimal_rep_length
= requested_digits
+ 1;
297 bool unique_zero
= ((flags_
& UNIQUE_ZERO
) != 0);
298 if (sign
&& (value
!= 0.0 || !unique_zero
)) {
299 result_builder
->AddCharacter('-');
302 int exponent
= decimal_point
- 1;
303 CreateExponentialRepresentation(decimal_rep
,
311 bool DoubleToStringConverter::ToPrecision(double value
,
313 StringBuilder
* result_builder
) const {
314 if (Double(value
).IsSpecial()) {
315 return HandleSpecialValues(value
, result_builder
);
318 if (precision
< kMinPrecisionDigits
|| precision
> kMaxPrecisionDigits
) {
322 // Find a sufficiently precise decimal representation of n.
325 // Add one for the terminating null character.
326 const int kDecimalRepCapacity
= kMaxPrecisionDigits
+ 1;
327 char decimal_rep
[kDecimalRepCapacity
];
328 int decimal_rep_length
;
330 DoubleToAscii(value
, PRECISION
, precision
,
331 decimal_rep
, kDecimalRepCapacity
,
332 &sign
, &decimal_rep_length
, &decimal_point
);
333 DOUBLE_CONVERSION_ASSERT(decimal_rep_length
<= precision
);
335 bool unique_zero
= ((flags_
& UNIQUE_ZERO
) != 0);
336 if (sign
&& (value
!= 0.0 || !unique_zero
)) {
337 result_builder
->AddCharacter('-');
340 // The exponent if we print the number as x.xxeyyy. That is with the
341 // decimal point after the first digit.
342 int exponent
= decimal_point
- 1;
344 int extra_zero
= ((flags_
& EMIT_TRAILING_ZERO_AFTER_POINT
) != 0) ? 1 : 0;
345 if ((-decimal_point
+ 1 > max_leading_padding_zeroes_in_precision_mode_
) ||
346 (decimal_point
- precision
+ extra_zero
>
347 max_trailing_padding_zeroes_in_precision_mode_
)) {
348 // Fill buffer to contain 'precision' digits.
349 // Usually the buffer is already at the correct length, but 'DoubleToAscii'
350 // is allowed to return less characters.
351 for (int i
= decimal_rep_length
; i
< precision
; ++i
) {
352 decimal_rep
[i
] = '0';
355 CreateExponentialRepresentation(decimal_rep
,
360 CreateDecimalRepresentation(decimal_rep
, decimal_rep_length
, decimal_point
,
361 (std::max
)(0, precision
- decimal_point
),
366 #endif // not needed for ICU
369 static BignumDtoaMode
DtoaToBignumDtoaMode(
370 DoubleToStringConverter::DtoaMode dtoa_mode
) {
372 case DoubleToStringConverter::SHORTEST
: return BIGNUM_DTOA_SHORTEST
;
373 case DoubleToStringConverter::SHORTEST_SINGLE
:
374 return BIGNUM_DTOA_SHORTEST_SINGLE
;
375 case DoubleToStringConverter::FIXED
: return BIGNUM_DTOA_FIXED
;
376 case DoubleToStringConverter::PRECISION
: return BIGNUM_DTOA_PRECISION
;
378 DOUBLE_CONVERSION_UNREACHABLE();
383 void DoubleToStringConverter::DoubleToAscii(double v
,
385 int requested_digits
,
391 Vector
<char> vector(buffer
, buffer_length
);
392 DOUBLE_CONVERSION_ASSERT(!Double(v
).IsSpecial());
393 DOUBLE_CONVERSION_ASSERT(mode
== SHORTEST
|| mode
== SHORTEST_SINGLE
|| requested_digits
>= 0);
395 if (Double(v
).Sign() < 0) {
402 if (mode
== PRECISION
&& requested_digits
== 0) {
419 fast_worked
= FastDtoa(v
, FAST_DTOA_SHORTEST
, 0, vector
, length
, point
);
421 #if 0 // not needed for ICU
422 case SHORTEST_SINGLE
:
423 fast_worked
= FastDtoa(v
, FAST_DTOA_SHORTEST_SINGLE
, 0,
424 vector
, length
, point
);
427 fast_worked
= FastFixedDtoa(v
, requested_digits
, vector
, length
, point
);
430 fast_worked
= FastDtoa(v
, FAST_DTOA_PRECISION
, requested_digits
,
431 vector
, length
, point
);
433 #endif // not needed for ICU
436 DOUBLE_CONVERSION_UNREACHABLE();
438 if (fast_worked
) return;
440 // If the fast dtoa didn't succeed use the slower bignum version.
441 BignumDtoaMode bignum_mode
= DtoaToBignumDtoaMode(mode
);
442 BignumDtoa(v
, bignum_mode
, requested_digits
, vector
, length
, point
);
443 vector
[*length
] = '\0';
446 } // namespace double_conversion
448 // ICU PATCH: Close ICU namespace
450 #endif // ICU PATCH: close #if !UCONFIG_NO_FORMATTING