Coverage Report

Created: 2026-03-31 07:41

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/qtbase/src/3rdparty/double-conversion/double-conversion/double-to-string.cc
Line
Count
Source
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
40
namespace double_conversion {
41
42
0
const DoubleToStringConverter& DoubleToStringConverter::EcmaScriptConverter() {
43
0
  int flags = UNIQUE_ZERO | EMIT_POSITIVE_EXPONENT_SIGN;
44
0
  static DoubleToStringConverter converter(flags,
45
0
                                           "Infinity",
46
0
                                           "NaN",
47
0
                                           'e',
48
0
                                           -6, 21,
49
0
                                           6, 0);
50
0
  return converter;
51
0
}
52
53
54
bool DoubleToStringConverter::HandleSpecialValues(
55
    double value,
56
0
    StringBuilder* result_builder) const {
57
0
  Double double_inspect(value);
58
0
  if (double_inspect.IsInfinite()) {
59
0
    if (infinity_symbol_ == DOUBLE_CONVERSION_NULLPTR) return false;
60
0
    if (value < 0) {
61
0
      result_builder->AddCharacter('-');
62
0
    }
63
0
    result_builder->AddString(infinity_symbol_);
64
0
    return true;
65
0
  }
66
0
  if (double_inspect.IsNan()) {
67
0
    if (nan_symbol_ == DOUBLE_CONVERSION_NULLPTR) return false;
68
0
    result_builder->AddString(nan_symbol_);
69
0
    return true;
70
0
  }
71
0
  return false;
72
0
}
73
74
75
void DoubleToStringConverter::CreateExponentialRepresentation(
76
    const char* decimal_digits,
77
    int length,
78
    int exponent,
79
0
    StringBuilder* result_builder) const {
80
0
  DOUBLE_CONVERSION_ASSERT(length != 0);
81
0
  result_builder->AddCharacter(decimal_digits[0]);
82
0
  if (length == 1) {
83
0
    if ((flags_ & EMIT_TRAILING_DECIMAL_POINT_IN_EXPONENTIAL) != 0) {
84
0
      result_builder->AddCharacter('.');
85
0
      if ((flags_ & EMIT_TRAILING_ZERO_AFTER_POINT_IN_EXPONENTIAL) != 0) {
86
0
          result_builder->AddCharacter('0');
87
0
      }
88
0
    }
89
0
  } else {
90
0
    result_builder->AddCharacter('.');
91
0
    result_builder->AddSubstring(&decimal_digits[1], length-1);
92
0
  }
93
0
  result_builder->AddCharacter(exponent_character_);
94
0
  if (exponent < 0) {
95
0
    result_builder->AddCharacter('-');
96
0
    exponent = -exponent;
97
0
  } else {
98
0
    if ((flags_ & EMIT_POSITIVE_EXPONENT_SIGN) != 0) {
99
0
      result_builder->AddCharacter('+');
100
0
    }
101
0
  }
102
0
  DOUBLE_CONVERSION_ASSERT(exponent < 1e4);
103
  // Changing this constant requires updating the comment of DoubleToStringConverter constructor
104
0
  const int kMaxExponentLength = 5;
105
0
  char buffer[kMaxExponentLength + 1];
106
0
  buffer[kMaxExponentLength] = '\0';
107
0
  int first_char_pos = kMaxExponentLength;
108
0
  if (exponent == 0) {
109
0
    buffer[--first_char_pos] = '0';
110
0
  } else {
111
0
    while (exponent > 0) {
112
0
      buffer[--first_char_pos] = '0' + (exponent % 10);
113
0
      exponent /= 10;
114
0
    }
115
0
  }
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
0
  while(kMaxExponentLength - first_char_pos < std::min(min_exponent_width_, kMaxExponentLength)) {
119
0
    buffer[--first_char_pos] = '0';
120
0
  }
121
0
  result_builder->AddSubstring(&buffer[first_char_pos],
122
0
                               kMaxExponentLength - first_char_pos);
123
0
}
124
125
126
void DoubleToStringConverter::CreateDecimalRepresentation(
127
    const char* decimal_digits,
128
    int length,
129
    int decimal_point,
130
    int digits_after_point,
131
0
    StringBuilder* result_builder) const {
132
  // Create a representation that is padded with zeros if needed.
133
0
  if (decimal_point <= 0) {
134
      // "0.00000decimal_rep" or "0.000decimal_rep00".
135
0
    result_builder->AddCharacter('0');
136
0
    if (digits_after_point > 0) {
137
0
      result_builder->AddCharacter('.');
138
0
      result_builder->AddPadding('0', -decimal_point);
139
0
      DOUBLE_CONVERSION_ASSERT(length <= digits_after_point - (-decimal_point));
140
0
      result_builder->AddSubstring(decimal_digits, length);
141
0
      int remaining_digits = digits_after_point - (-decimal_point) - length;
142
0
      result_builder->AddPadding('0', remaining_digits);
143
0
    }
144
0
  } else if (decimal_point >= length) {
145
    // "decimal_rep0000.00000" or "decimal_rep.0000".
146
0
    result_builder->AddSubstring(decimal_digits, length);
147
0
    result_builder->AddPadding('0', decimal_point - length);
148
0
    if (digits_after_point > 0) {
149
0
      result_builder->AddCharacter('.');
150
0
      result_builder->AddPadding('0', digits_after_point);
151
0
    }
152
0
  } else {
153
    // "decima.l_rep000".
154
0
    DOUBLE_CONVERSION_ASSERT(digits_after_point > 0);
155
0
    result_builder->AddSubstring(decimal_digits, decimal_point);
156
0
    result_builder->AddCharacter('.');
157
0
    DOUBLE_CONVERSION_ASSERT(length - decimal_point <= digits_after_point);
158
0
    result_builder->AddSubstring(&decimal_digits[decimal_point],
159
0
                                 length - decimal_point);
160
0
    int remaining_digits = digits_after_point - (length - decimal_point);
161
0
    result_builder->AddPadding('0', remaining_digits);
162
0
  }
163
0
  if (digits_after_point == 0) {
164
0
    if ((flags_ & EMIT_TRAILING_DECIMAL_POINT) != 0) {
165
0
      result_builder->AddCharacter('.');
166
0
    }
167
0
    if ((flags_ & EMIT_TRAILING_ZERO_AFTER_POINT) != 0) {
168
0
      result_builder->AddCharacter('0');
169
0
    }
170
0
  }
171
0
}
172
173
174
bool DoubleToStringConverter::ToShortestIeeeNumber(
175
    double value,
176
    StringBuilder* result_builder,
177
0
    DoubleToStringConverter::DtoaMode mode) const {
178
0
  DOUBLE_CONVERSION_ASSERT(mode == SHORTEST || mode == SHORTEST_SINGLE);
179
0
  if (Double(value).IsSpecial()) {
180
0
    return HandleSpecialValues(value, result_builder);
181
0
  }
182
183
0
  int decimal_point = 0;
184
0
  bool sign;
185
0
  const int kDecimalRepCapacity = kBase10MaximalLength + 1;
186
0
  char decimal_rep[kDecimalRepCapacity];
187
0
  int decimal_rep_length;
188
189
0
  DoubleToAscii(value, mode, 0, decimal_rep, kDecimalRepCapacity,
190
0
                &sign, &decimal_rep_length, &decimal_point);
191
192
0
  bool unique_zero = (flags_ & UNIQUE_ZERO) != 0;
193
0
  if (sign && (value != 0.0 || !unique_zero)) {
194
0
    result_builder->AddCharacter('-');
195
0
  }
196
197
0
  int exponent = decimal_point - 1;
198
0
  if ((decimal_in_shortest_low_ <= exponent) &&
199
0
      (exponent < decimal_in_shortest_high_)) {
200
0
    CreateDecimalRepresentation(decimal_rep, decimal_rep_length,
201
0
                                decimal_point,
202
0
                                (std::max)(0, decimal_rep_length - decimal_point),
203
0
                                result_builder);
204
0
  } else {
205
0
    CreateExponentialRepresentation(decimal_rep, decimal_rep_length, exponent,
206
0
                                    result_builder);
207
0
  }
208
0
  return true;
209
0
}
210
211
212
bool DoubleToStringConverter::ToFixed(double value,
213
                                      int requested_digits,
214
0
                                      StringBuilder* result_builder) const {
215
0
  DOUBLE_CONVERSION_ASSERT(kMaxFixedDigitsBeforePoint == 60);
216
0
  const double kFirstNonFixed = 1e60;
217
218
0
  if (Double(value).IsSpecial()) {
219
0
    return HandleSpecialValues(value, result_builder);
220
0
  }
221
222
0
  if (requested_digits > kMaxFixedDigitsAfterPoint) return false;
223
0
  if (value >= kFirstNonFixed || value <= -kFirstNonFixed) return false;
224
225
  // Find a sufficiently precise decimal representation of n.
226
0
  int decimal_point;
227
0
  bool sign;
228
  // Add space for the '\0' byte.
229
0
  const int kDecimalRepCapacity =
230
0
      kMaxFixedDigitsBeforePoint + kMaxFixedDigitsAfterPoint + 1;
231
0
  char decimal_rep[kDecimalRepCapacity];
232
0
  int decimal_rep_length;
233
0
  DoubleToAscii(value, FIXED, requested_digits,
234
0
                decimal_rep, kDecimalRepCapacity,
235
0
                &sign, &decimal_rep_length, &decimal_point);
236
237
0
  bool unique_zero = ((flags_ & UNIQUE_ZERO) != 0);
238
0
  if (sign && (value != 0.0 || !unique_zero)) {
239
0
    result_builder->AddCharacter('-');
240
0
  }
241
242
0
  CreateDecimalRepresentation(decimal_rep, decimal_rep_length, decimal_point,
243
0
                              requested_digits, result_builder);
244
0
  return true;
245
0
}
246
247
248
bool DoubleToStringConverter::ToExponential(
249
    double value,
250
    int requested_digits,
251
0
    StringBuilder* result_builder) const {
252
0
  if (Double(value).IsSpecial()) {
253
0
    return HandleSpecialValues(value, result_builder);
254
0
  }
255
256
0
  if (requested_digits < -1) return false;
257
0
  if (requested_digits > kMaxExponentialDigits) return false;
258
259
0
  int decimal_point;
260
0
  bool sign;
261
  // Add space for digit before the decimal point and the '\0' character.
262
0
  const int kDecimalRepCapacity = kMaxExponentialDigits + 2;
263
0
  DOUBLE_CONVERSION_ASSERT(kDecimalRepCapacity > kBase10MaximalLength);
264
0
  char decimal_rep[kDecimalRepCapacity];
265
0
#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
0
  memset(decimal_rep, 0, sizeof(decimal_rep));
270
0
#endif
271
0
  int decimal_rep_length;
272
273
0
  if (requested_digits == -1) {
274
0
    DoubleToAscii(value, SHORTEST, 0,
275
0
                  decimal_rep, kDecimalRepCapacity,
276
0
                  &sign, &decimal_rep_length, &decimal_point);
277
0
  } else {
278
0
    DoubleToAscii(value, PRECISION, requested_digits + 1,
279
0
                  decimal_rep, kDecimalRepCapacity,
280
0
                  &sign, &decimal_rep_length, &decimal_point);
281
0
    DOUBLE_CONVERSION_ASSERT(decimal_rep_length <= requested_digits + 1);
282
283
0
    for (int i = decimal_rep_length; i < requested_digits + 1; ++i) {
284
0
      decimal_rep[i] = '0';
285
0
    }
286
0
    decimal_rep_length = requested_digits + 1;
287
0
  }
288
289
0
  bool unique_zero = ((flags_ & UNIQUE_ZERO) != 0);
290
0
  if (sign && (value != 0.0 || !unique_zero)) {
291
0
    result_builder->AddCharacter('-');
292
0
  }
293
294
0
  int exponent = decimal_point - 1;
295
0
  CreateExponentialRepresentation(decimal_rep,
296
0
                                  decimal_rep_length,
297
0
                                  exponent,
298
0
                                  result_builder);
299
0
  return true;
300
0
}
301
302
303
bool DoubleToStringConverter::ToPrecision(double value,
304
                                          int precision,
305
0
                                          StringBuilder* result_builder) const {
306
0
  if (Double(value).IsSpecial()) {
307
0
    return HandleSpecialValues(value, result_builder);
308
0
  }
309
310
0
  if (precision < kMinPrecisionDigits || precision > kMaxPrecisionDigits) {
311
0
    return false;
312
0
  }
313
314
  // Find a sufficiently precise decimal representation of n.
315
0
  int decimal_point;
316
0
  bool sign;
317
  // Add one for the terminating null character.
318
0
  const int kDecimalRepCapacity = kMaxPrecisionDigits + 1;
319
0
  char decimal_rep[kDecimalRepCapacity];
320
0
  int decimal_rep_length;
321
322
0
  DoubleToAscii(value, PRECISION, precision,
323
0
                decimal_rep, kDecimalRepCapacity,
324
0
                &sign, &decimal_rep_length, &decimal_point);
325
0
  DOUBLE_CONVERSION_ASSERT(decimal_rep_length <= precision);
326
327
0
  bool unique_zero = ((flags_ & UNIQUE_ZERO) != 0);
328
0
  if (sign && (value != 0.0 || !unique_zero)) {
329
0
    result_builder->AddCharacter('-');
330
0
  }
331
332
  // The exponent if we print the number as x.xxeyyy. That is with the
333
  // decimal point after the first digit.
334
0
  int exponent = decimal_point - 1;
335
336
0
  int extra_zero = ((flags_ & EMIT_TRAILING_ZERO_AFTER_POINT) != 0) ? 1 : 0;
337
0
  bool as_exponential =
338
0
      (-decimal_point + 1 > max_leading_padding_zeroes_in_precision_mode_) ||
339
0
      (decimal_point - precision + extra_zero >
340
0
       max_trailing_padding_zeroes_in_precision_mode_);
341
0
  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
0
    int stop = as_exponential ? 1 : std::max(1, decimal_point);
345
0
    while (decimal_rep_length > stop && decimal_rep[decimal_rep_length - 1] == '0') {
346
0
      --decimal_rep_length;
347
0
    }
348
    // Clamp precision to avoid the code below re-adding the zeros.
349
0
    precision = std::min(precision, decimal_rep_length);
350
0
  }
351
0
  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
0
    for (int i = decimal_rep_length; i < precision; ++i) {
356
0
      decimal_rep[i] = '0';
357
0
    }
358
359
0
    CreateExponentialRepresentation(decimal_rep,
360
0
                                    precision,
361
0
                                    exponent,
362
0
                                    result_builder);
363
0
  } else {
364
0
    CreateDecimalRepresentation(decimal_rep, decimal_rep_length, decimal_point,
365
0
                                (std::max)(0, precision - decimal_point),
366
0
                                result_builder);
367
0
  }
368
0
  return true;
369
0
}
370
371
372
static BignumDtoaMode DtoaToBignumDtoaMode(
373
0
    DoubleToStringConverter::DtoaMode dtoa_mode) {
374
0
  switch (dtoa_mode) {
375
0
    case DoubleToStringConverter::SHORTEST:  return BIGNUM_DTOA_SHORTEST;
376
0
    case DoubleToStringConverter::SHORTEST_SINGLE:
377
0
        return BIGNUM_DTOA_SHORTEST_SINGLE;
378
0
    case DoubleToStringConverter::FIXED:     return BIGNUM_DTOA_FIXED;
379
0
    case DoubleToStringConverter::PRECISION: return BIGNUM_DTOA_PRECISION;
380
0
    default:
381
0
      DOUBLE_CONVERSION_UNREACHABLE();
382
0
  }
383
0
}
384
385
386
void DoubleToStringConverter::DoubleToAscii(double v,
387
                                            DtoaMode mode,
388
                                            int requested_digits,
389
                                            char* buffer,
390
                                            int buffer_length,
391
                                            bool* sign,
392
                                            int* length,
393
0
                                            int* point) {
394
0
  Vector<char> vector(buffer, buffer_length);
395
0
  DOUBLE_CONVERSION_ASSERT(!Double(v).IsSpecial());
396
0
  DOUBLE_CONVERSION_ASSERT(mode == SHORTEST || mode == SHORTEST_SINGLE || requested_digits >= 0);
397
398
0
  if (Double(v).Sign() < 0) {
399
0
    *sign = true;
400
0
    v = -v;
401
0
  } else {
402
0
    *sign = false;
403
0
  }
404
405
0
  if (mode == PRECISION && requested_digits == 0) {
406
0
    vector[0] = '\0';
407
0
    *length = 0;
408
0
    *point = 0;
409
0
    return;
410
0
  }
411
412
0
  if (v == 0) {
413
0
    vector[0] = '0';
414
0
    vector[1] = '\0';
415
0
    *length = 1;
416
0
    *point = 1;
417
0
    return;
418
0
  }
419
420
0
  bool fast_worked;
421
0
  switch (mode) {
422
0
    case SHORTEST:
423
0
      fast_worked = FastDtoa(v, FAST_DTOA_SHORTEST, 0, vector, length, point);
424
0
      break;
425
0
    case SHORTEST_SINGLE:
426
0
      fast_worked = FastDtoa(v, FAST_DTOA_SHORTEST_SINGLE, 0,
427
0
                             vector, length, point);
428
0
      break;
429
0
    case FIXED:
430
0
      fast_worked = FastFixedDtoa(v, requested_digits, vector, length, point);
431
0
      break;
432
0
    case PRECISION:
433
0
      fast_worked = FastDtoa(v, FAST_DTOA_PRECISION, requested_digits,
434
0
                             vector, length, point);
435
0
      break;
436
0
    default:
437
0
      fast_worked = false;
438
0
      DOUBLE_CONVERSION_UNREACHABLE();
439
0
  }
440
0
  if (fast_worked) return;
441
442
  // If the fast dtoa didn't succeed use the slower bignum version.
443
0
  BignumDtoaMode bignum_mode = DtoaToBignumDtoaMode(mode);
444
0
  BignumDtoa(v, bignum_mode, requested_digits, vector, length, point);
445
0
  vector[*length] = '\0';
446
0
}
447
448
}  // namespace double_conversion