tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

double-conversion-double-to-string.cpp (16863B)


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