Flutter Engine
The Flutter Engine
double-to-string.cc
Go to the documentation of this file.
1// Copyright 2010 the V8 project authors. All rights reserved.
2// Redistribution and use in source and binary forms, with or without
3// modification, are permitted provided that the following conditions are
4// met:
5//
6// * Redistributions of source code must retain the above copyright
7// notice, this list of conditions and the following disclaimer.
8// * Redistributions in binary form must reproduce the above
9// copyright notice, this list of conditions and the following
10// disclaimer in the documentation and/or other materials provided
11// with the distribution.
12// * Neither the name of Google Inc. nor the names of its
13// contributors may be used to endorse or promote products derived
14// from this software without specific prior written permission.
15//
16// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27
28#include <algorithm>
29#include <climits>
30#include <cmath>
31
32#include "double-to-string.h"
33
34#include "bignum-dtoa.h"
35#include "fast-dtoa.h"
36#include "fixed-dtoa.h"
37#include "ieee.h"
38#include "utils.h"
39
40namespace double_conversion {
41
45 "Infinity",
46 "NaN",
47 'e',
48 -6, 21,
49 6, 0);
50 return converter;
51}
52
53
54bool DoubleToStringConverter::HandleSpecialValues(
55 double value,
56 StringBuilder* result_builder) const {
57 Double double_inspect(value);
58 if (double_inspect.IsInfinite()) {
59 if (infinity_symbol_ == DOUBLE_CONVERSION_NULLPTR) return false;
60 if (value < 0) {
61 result_builder->AddCharacter('-');
62 }
63 result_builder->AddString(infinity_symbol_);
64 return true;
65 }
66 if (double_inspect.IsNan()) {
67 if (nan_symbol_ == DOUBLE_CONVERSION_NULLPTR) return false;
68 result_builder->AddString(nan_symbol_);
69 return true;
70 }
71 return false;
72}
73
74
75void DoubleToStringConverter::CreateExponentialRepresentation(
76 const char* decimal_digits,
77 int length,
78 int exponent,
79 StringBuilder* result_builder) const {
81 result_builder->AddCharacter(decimal_digits[0]);
82 if (length == 1) {
84 result_builder->AddCharacter('.');
86 result_builder->AddCharacter('0');
87 }
88 }
89 } else {
90 result_builder->AddCharacter('.');
91 result_builder->AddSubstring(&decimal_digits[1], length-1);
92 }
93 result_builder->AddCharacter(exponent_character_);
94 if (exponent < 0) {
95 result_builder->AddCharacter('-');
96 exponent = -exponent;
97 } else {
98 if ((flags_ & EMIT_POSITIVE_EXPONENT_SIGN) != 0) {
99 result_builder->AddCharacter('+');
100 }
101 }
102 DOUBLE_CONVERSION_ASSERT(exponent < 1e4);
103 // Changing this constant requires updating the comment of DoubleToStringConverter constructor
104 const int kMaxExponentLength = 5;
105 char buffer[kMaxExponentLength + 1];
106 buffer[kMaxExponentLength] = '\0';
107 int first_char_pos = kMaxExponentLength;
108 if (exponent == 0) {
109 buffer[--first_char_pos] = '0';
110 } else {
111 while (exponent > 0) {
112 buffer[--first_char_pos] = '0' + (exponent % 10);
113 exponent /= 10;
114 }
115 }
116 // Add prefix '0' to make exponent width >= min(min_exponent_with_, kMaxExponentLength)
117 // For example: convert 1e+9 -> 1e+09, if min_exponent_with_ is set to 2
118 while(kMaxExponentLength - first_char_pos < std::min(min_exponent_width_, kMaxExponentLength)) {
119 buffer[--first_char_pos] = '0';
120 }
121 result_builder->AddSubstring(&buffer[first_char_pos],
122 kMaxExponentLength - first_char_pos);
123}
124
125
126void DoubleToStringConverter::CreateDecimalRepresentation(
127 const char* decimal_digits,
128 int length,
129 int decimal_point,
130 int digits_after_point,
131 StringBuilder* result_builder) const {
132 // Create a representation that is padded with zeros if needed.
133 if (decimal_point <= 0) {
134 // "0.00000decimal_rep" or "0.000decimal_rep00".
135 result_builder->AddCharacter('0');
136 if (digits_after_point > 0) {
137 result_builder->AddCharacter('.');
138 result_builder->AddPadding('0', -decimal_point);
139 DOUBLE_CONVERSION_ASSERT(length <= digits_after_point - (-decimal_point));
140 result_builder->AddSubstring(decimal_digits, length);
141 int remaining_digits = digits_after_point - (-decimal_point) - length;
142 result_builder->AddPadding('0', remaining_digits);
143 }
144 } else if (decimal_point >= length) {
145 // "decimal_rep0000.00000" or "decimal_rep.0000".
146 result_builder->AddSubstring(decimal_digits, length);
147 result_builder->AddPadding('0', decimal_point - length);
148 if (digits_after_point > 0) {
149 result_builder->AddCharacter('.');
150 result_builder->AddPadding('0', digits_after_point);
151 }
152 } else {
153 // "decima.l_rep000".
154 DOUBLE_CONVERSION_ASSERT(digits_after_point > 0);
155 result_builder->AddSubstring(decimal_digits, decimal_point);
156 result_builder->AddCharacter('.');
157 DOUBLE_CONVERSION_ASSERT(length - decimal_point <= digits_after_point);
158 result_builder->AddSubstring(&decimal_digits[decimal_point],
159 length - decimal_point);
160 int remaining_digits = digits_after_point - (length - decimal_point);
161 result_builder->AddPadding('0', remaining_digits);
162 }
163 if (digits_after_point == 0) {
164 if ((flags_ & EMIT_TRAILING_DECIMAL_POINT) != 0) {
165 result_builder->AddCharacter('.');
166 }
167 if ((flags_ & EMIT_TRAILING_ZERO_AFTER_POINT) != 0) {
168 result_builder->AddCharacter('0');
169 }
170 }
171}
172
173
174bool DoubleToStringConverter::ToShortestIeeeNumber(
175 double value,
176 StringBuilder* result_builder,
179 if (Double(value).IsSpecial()) {
180 return HandleSpecialValues(value, result_builder);
181 }
182
183 int decimal_point;
184 bool sign;
185 const int kDecimalRepCapacity = kBase10MaximalLength + 1;
186 char decimal_rep[kDecimalRepCapacity];
187 int decimal_rep_length;
188
189 DoubleToAscii(value, mode, 0, decimal_rep, kDecimalRepCapacity,
190 &sign, &decimal_rep_length, &decimal_point);
191
192 bool unique_zero = (flags_ & UNIQUE_ZERO) != 0;
193 if (sign && (value != 0.0 || !unique_zero)) {
194 result_builder->AddCharacter('-');
195 }
196
197 int exponent = decimal_point - 1;
198 if ((decimal_in_shortest_low_ <= exponent) &&
199 (exponent < decimal_in_shortest_high_)) {
200 CreateDecimalRepresentation(decimal_rep, decimal_rep_length,
201 decimal_point,
202 (std::max)(0, decimal_rep_length - decimal_point),
203 result_builder);
204 } else {
205 CreateExponentialRepresentation(decimal_rep, decimal_rep_length, exponent,
206 result_builder);
207 }
208 return true;
209}
210
211
213 int requested_digits,
214 StringBuilder* result_builder) const {
216 const double kFirstNonFixed = 1e60;
217
218 if (Double(value).IsSpecial()) {
219 return HandleSpecialValues(value, result_builder);
220 }
221
222 if (requested_digits > kMaxFixedDigitsAfterPoint) return false;
223 if (value >= kFirstNonFixed || value <= -kFirstNonFixed) return false;
224
225 // Find a sufficiently precise decimal representation of n.
226 int decimal_point;
227 bool sign;
228 // Add space for the '\0' byte.
229 const int kDecimalRepCapacity =
231 char decimal_rep[kDecimalRepCapacity];
232 int decimal_rep_length;
233 DoubleToAscii(value, FIXED, requested_digits,
234 decimal_rep, kDecimalRepCapacity,
235 &sign, &decimal_rep_length, &decimal_point);
236
237 bool unique_zero = ((flags_ & UNIQUE_ZERO) != 0);
238 if (sign && (value != 0.0 || !unique_zero)) {
239 result_builder->AddCharacter('-');
240 }
241
242 CreateDecimalRepresentation(decimal_rep, decimal_rep_length, decimal_point,
243 requested_digits, result_builder);
244 return true;
245}
246
247
249 double value,
250 int requested_digits,
251 StringBuilder* result_builder) const {
252 if (Double(value).IsSpecial()) {
253 return HandleSpecialValues(value, result_builder);
254 }
255
256 if (requested_digits < -1) return false;
257 if (requested_digits > kMaxExponentialDigits) return false;
258
259 int decimal_point;
260 bool sign;
261 // Add space for digit before the decimal point and the '\0' character.
262 const int kDecimalRepCapacity = kMaxExponentialDigits + 2;
263 DOUBLE_CONVERSION_ASSERT(kDecimalRepCapacity > kBase10MaximalLength);
264 char decimal_rep[kDecimalRepCapacity];
265#ifndef NDEBUG
266 // Problem: there is an assert in StringBuilder::AddSubstring() that
267 // will pass this buffer to strlen(), and this buffer is not generally
268 // null-terminated.
269 memset(decimal_rep, 0, sizeof(decimal_rep));
270#endif
271 int decimal_rep_length;
272
273 if (requested_digits == -1) {
275 decimal_rep, kDecimalRepCapacity,
276 &sign, &decimal_rep_length, &decimal_point);
277 } else {
278 DoubleToAscii(value, PRECISION, requested_digits + 1,
279 decimal_rep, kDecimalRepCapacity,
280 &sign, &decimal_rep_length, &decimal_point);
281 DOUBLE_CONVERSION_ASSERT(decimal_rep_length <= requested_digits + 1);
282
283 for (int i = decimal_rep_length; i < requested_digits + 1; ++i) {
284 decimal_rep[i] = '0';
285 }
286 decimal_rep_length = requested_digits + 1;
287 }
288
289 bool unique_zero = ((flags_ & UNIQUE_ZERO) != 0);
290 if (sign && (value != 0.0 || !unique_zero)) {
291 result_builder->AddCharacter('-');
292 }
293
294 int exponent = decimal_point - 1;
295 CreateExponentialRepresentation(decimal_rep,
296 decimal_rep_length,
297 exponent,
298 result_builder);
299 return true;
300}
301
302
304 int precision,
305 StringBuilder* result_builder) const {
306 if (Double(value).IsSpecial()) {
307 return HandleSpecialValues(value, result_builder);
308 }
309
310 if (precision < kMinPrecisionDigits || precision > kMaxPrecisionDigits) {
311 return false;
312 }
313
314 // Find a sufficiently precise decimal representation of n.
315 int decimal_point;
316 bool sign;
317 // Add one for the terminating null character.
318 const int kDecimalRepCapacity = kMaxPrecisionDigits + 1;
319 char decimal_rep[kDecimalRepCapacity];
320 int decimal_rep_length;
321
322 DoubleToAscii(value, PRECISION, precision,
323 decimal_rep, kDecimalRepCapacity,
324 &sign, &decimal_rep_length, &decimal_point);
325 DOUBLE_CONVERSION_ASSERT(decimal_rep_length <= precision);
326
327 bool unique_zero = ((flags_ & UNIQUE_ZERO) != 0);
328 if (sign && (value != 0.0 || !unique_zero)) {
329 result_builder->AddCharacter('-');
330 }
331
332 // The exponent if we print the number as x.xxeyyy. That is with the
333 // decimal point after the first digit.
334 int exponent = decimal_point - 1;
335
336 int extra_zero = ((flags_ & EMIT_TRAILING_ZERO_AFTER_POINT) != 0) ? 1 : 0;
337 bool as_exponential =
338 (-decimal_point + 1 > max_leading_padding_zeroes_in_precision_mode_) ||
339 (decimal_point - precision + extra_zero >
340 max_trailing_padding_zeroes_in_precision_mode_);
341 if ((flags_ & NO_TRAILING_ZERO) != 0) {
342 // Truncate trailing zeros that occur after the decimal point (if exponential,
343 // that is everything after the first digit).
344 int stop = as_exponential ? 1 : std::max(1, decimal_point);
345 while (decimal_rep_length > stop && decimal_rep[decimal_rep_length - 1] == '0') {
346 --decimal_rep_length;
347 }
348 // Clamp precision to avoid the code below re-adding the zeros.
349 precision = std::min(precision, decimal_rep_length);
350 }
351 if (as_exponential) {
352 // Fill buffer to contain 'precision' digits.
353 // Usually the buffer is already at the correct length, but 'DoubleToAscii'
354 // is allowed to return less characters.
355 for (int i = decimal_rep_length; i < precision; ++i) {
356 decimal_rep[i] = '0';
357 }
358
359 CreateExponentialRepresentation(decimal_rep,
360 precision,
361 exponent,
362 result_builder);
363 } else {
364 CreateDecimalRepresentation(decimal_rep, decimal_rep_length, decimal_point,
365 (std::max)(0, precision - decimal_point),
366 result_builder);
367 }
368 return true;
369}
370
371
374 switch (dtoa_mode) {
380 default:
382 }
383}
384
385
388 int requested_digits,
389 char* buffer,
390 int buffer_length,
391 bool* sign,
392 int* length,
393 int* point) {
394 Vector<char> vector(buffer, buffer_length);
395 DOUBLE_CONVERSION_ASSERT(!Double(v).IsSpecial());
396 DOUBLE_CONVERSION_ASSERT(mode == SHORTEST || mode == SHORTEST_SINGLE || requested_digits >= 0);
397
398 if (Double(v).Sign() < 0) {
399 *sign = true;
400 v = -v;
401 } else {
402 *sign = false;
403 }
404
405 if (mode == PRECISION && requested_digits == 0) {
406 vector[0] = '\0';
407 *length = 0;
408 return;
409 }
410
411 if (v == 0) {
412 vector[0] = '0';
413 vector[1] = '\0';
414 *length = 1;
415 *point = 1;
416 return;
417 }
418
419 bool fast_worked;
420 switch (mode) {
421 case SHORTEST:
422 fast_worked = FastDtoa(v, FAST_DTOA_SHORTEST, 0, vector, length, point);
423 break;
424 case SHORTEST_SINGLE:
425 fast_worked = FastDtoa(v, FAST_DTOA_SHORTEST_SINGLE, 0,
426 vector, length, point);
427 break;
428 case FIXED:
429 fast_worked = FastFixedDtoa(v, requested_digits, vector, length, point);
430 break;
431 case PRECISION:
432 fast_worked = FastDtoa(v, FAST_DTOA_PRECISION, requested_digits,
433 vector, length, point);
434 break;
435 default:
436 fast_worked = false;
438 }
439 if (fast_worked) return;
440
441 // If the fast dtoa didn't succeed use the slower bignum version.
443 BignumDtoa(v, bignum_mode, requested_digits, vector, length, point);
444 vector[*length] = '\0';
445}
446
447} // namespace double_conversion
static int sign(SkScalar x)
Definition: SkPath.cpp:2205
bool ToFixed(double value, int requested_digits, StringBuilder *result_builder) const
static const DoubleToStringConverter & EcmaScriptConverter()
bool ToExponential(double value, int requested_digits, StringBuilder *result_builder) const
static void DoubleToAscii(double v, DtoaMode mode, int requested_digits, char *buffer, int buffer_length, bool *sign, int *length, int *point)
bool ToPrecision(double value, int precision, StringBuilder *result_builder) const
void AddString(const char *s)
Definition: utils.h:327
FlutterSemanticsFlag flags
uint8_t value
static float max(float r, float g, float b)
Definition: hsl.cpp:49
static float min(float r, float g, float b)
Definition: hsl.cpp:48
size_t length
string converter
Definition: cacheimages.py:19
void BignumDtoa(double v, BignumDtoaMode mode, int requested_digits, Vector< char > buffer, int *length, int *decimal_point)
Definition: bignum-dtoa.cc:89
@ FAST_DTOA_SHORTEST_SINGLE
Definition: fast-dtoa.h:41
static BignumDtoaMode DtoaToBignumDtoaMode(DoubleToStringConverter::DtoaMode dtoa_mode)
bool FastDtoa(double v, FastDtoaMode mode, int requested_digits, Vector< char > buffer, int *length, int *decimal_point)
Definition: fast-dtoa.cc:635
bool FastFixedDtoa(double v, int fractional_count, Vector< char > buffer, int *length, int *decimal_point)
Definition: fixed-dtoa.cc:310
DEF_SWITCHES_START aot vmservice shared library Name of the *so containing AOT compiled Dart assets for launching the service isolate vm snapshot The VM snapshot data that will be memory mapped as read only SnapshotAssetPath must be present isolate snapshot The isolate snapshot data that will be memory mapped as read only SnapshotAssetPath must be present cache dir Path to the cache directory This is different from the persistent_cache_path in embedder which is used for Skia shader cache icu native lib Path to the library file that exports the ICU data vm service The hostname IP address on which the Dart VM Service should be served If not defaults to or::depending on whether ipv6 is specified vm service A custom Dart VM Service port The default is to pick a randomly available open port disable vm Disable the Dart VM Service The Dart VM Service is never available in release mode disable vm service Disable mDNS Dart VM Service publication Bind to the IPv6 localhost address for the Dart VM Service Ignored if vm service host is set endless trace buffer
Definition: switches.h:126
it will be possible to load the file into Perfetto s trace viewer disable asset Prevents usage of any non test fonts unless they were explicitly Loaded via prefetched default font Indicates whether the embedding started a prefetch of the default font manager before creating the engine run In non interactive mode
Definition: switches.h:228
#define DOUBLE_CONVERSION_NULLPTR
Definition: utils.h:41
#define DOUBLE_CONVERSION_ASSERT(condition)
Definition: utils.h:46
#define DOUBLE_CONVERSION_UNREACHABLE()
Definition: utils.h:77