Tue, 06 Jan 2015 21:39:09 +0100
Conditionally force memory storage according to privacy.thirdparty.isolate;
This solves Tor bug #9701, complying with disk avoidance documented in
https://www.torproject.org/projects/torbrowser/design/#disk-avoidance.
michael@0 | 1 | // Copyright 2010 the V8 project authors. All rights reserved. |
michael@0 | 2 | // Redistribution and use in source and binary forms, with or without |
michael@0 | 3 | // modification, are permitted provided that the following conditions are |
michael@0 | 4 | // met: |
michael@0 | 5 | // |
michael@0 | 6 | // * Redistributions of source code must retain the above copyright |
michael@0 | 7 | // notice, this list of conditions and the following disclaimer. |
michael@0 | 8 | // * Redistributions in binary form must reproduce the above |
michael@0 | 9 | // copyright notice, this list of conditions and the following |
michael@0 | 10 | // disclaimer in the documentation and/or other materials provided |
michael@0 | 11 | // with the distribution. |
michael@0 | 12 | // * Neither the name of Google Inc. nor the names of its |
michael@0 | 13 | // contributors may be used to endorse or promote products derived |
michael@0 | 14 | // from this software without specific prior written permission. |
michael@0 | 15 | // |
michael@0 | 16 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
michael@0 | 17 | // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
michael@0 | 18 | // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
michael@0 | 19 | // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
michael@0 | 20 | // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
michael@0 | 21 | // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
michael@0 | 22 | // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
michael@0 | 23 | // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
michael@0 | 24 | // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
michael@0 | 25 | // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
michael@0 | 26 | // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
michael@0 | 27 | |
michael@0 | 28 | #include <limits.h> |
michael@0 | 29 | #include <math.h> |
michael@0 | 30 | |
michael@0 | 31 | #include "double-conversion.h" |
michael@0 | 32 | |
michael@0 | 33 | #include "bignum-dtoa.h" |
michael@0 | 34 | #include "fast-dtoa.h" |
michael@0 | 35 | #include "fixed-dtoa.h" |
michael@0 | 36 | #include "ieee.h" |
michael@0 | 37 | #include "strtod.h" |
michael@0 | 38 | #include "utils.h" |
michael@0 | 39 | |
michael@0 | 40 | namespace double_conversion { |
michael@0 | 41 | |
michael@0 | 42 | const DoubleToStringConverter& DoubleToStringConverter::EcmaScriptConverter() { |
michael@0 | 43 | int flags = UNIQUE_ZERO | EMIT_POSITIVE_EXPONENT_SIGN; |
michael@0 | 44 | static DoubleToStringConverter converter(flags, |
michael@0 | 45 | "Infinity", |
michael@0 | 46 | "NaN", |
michael@0 | 47 | 'e', |
michael@0 | 48 | -6, 21, |
michael@0 | 49 | 6, 0); |
michael@0 | 50 | return converter; |
michael@0 | 51 | } |
michael@0 | 52 | |
michael@0 | 53 | |
michael@0 | 54 | bool DoubleToStringConverter::HandleSpecialValues( |
michael@0 | 55 | double value, |
michael@0 | 56 | StringBuilder* result_builder) const { |
michael@0 | 57 | Double double_inspect(value); |
michael@0 | 58 | if (double_inspect.IsInfinite()) { |
michael@0 | 59 | if (infinity_symbol_ == NULL) return false; |
michael@0 | 60 | if (value < 0) { |
michael@0 | 61 | result_builder->AddCharacter('-'); |
michael@0 | 62 | } |
michael@0 | 63 | result_builder->AddString(infinity_symbol_); |
michael@0 | 64 | return true; |
michael@0 | 65 | } |
michael@0 | 66 | if (double_inspect.IsNan()) { |
michael@0 | 67 | if (nan_symbol_ == NULL) return false; |
michael@0 | 68 | result_builder->AddString(nan_symbol_); |
michael@0 | 69 | return true; |
michael@0 | 70 | } |
michael@0 | 71 | return false; |
michael@0 | 72 | } |
michael@0 | 73 | |
michael@0 | 74 | |
michael@0 | 75 | void DoubleToStringConverter::CreateExponentialRepresentation( |
michael@0 | 76 | const char* decimal_digits, |
michael@0 | 77 | int length, |
michael@0 | 78 | int exponent, |
michael@0 | 79 | StringBuilder* result_builder) const { |
michael@0 | 80 | ASSERT(length != 0); |
michael@0 | 81 | result_builder->AddCharacter(decimal_digits[0]); |
michael@0 | 82 | if (length != 1) { |
michael@0 | 83 | result_builder->AddCharacter('.'); |
michael@0 | 84 | result_builder->AddSubstring(&decimal_digits[1], length-1); |
michael@0 | 85 | } |
michael@0 | 86 | result_builder->AddCharacter(exponent_character_); |
michael@0 | 87 | if (exponent < 0) { |
michael@0 | 88 | result_builder->AddCharacter('-'); |
michael@0 | 89 | exponent = -exponent; |
michael@0 | 90 | } else { |
michael@0 | 91 | if ((flags_ & EMIT_POSITIVE_EXPONENT_SIGN) != 0) { |
michael@0 | 92 | result_builder->AddCharacter('+'); |
michael@0 | 93 | } |
michael@0 | 94 | } |
michael@0 | 95 | if (exponent == 0) { |
michael@0 | 96 | result_builder->AddCharacter('0'); |
michael@0 | 97 | return; |
michael@0 | 98 | } |
michael@0 | 99 | ASSERT(exponent < 1e4); |
michael@0 | 100 | const int kMaxExponentLength = 5; |
michael@0 | 101 | char buffer[kMaxExponentLength + 1]; |
michael@0 | 102 | buffer[kMaxExponentLength] = '\0'; |
michael@0 | 103 | int first_char_pos = kMaxExponentLength; |
michael@0 | 104 | while (exponent > 0) { |
michael@0 | 105 | buffer[--first_char_pos] = '0' + (exponent % 10); |
michael@0 | 106 | exponent /= 10; |
michael@0 | 107 | } |
michael@0 | 108 | result_builder->AddSubstring(&buffer[first_char_pos], |
michael@0 | 109 | kMaxExponentLength - first_char_pos); |
michael@0 | 110 | } |
michael@0 | 111 | |
michael@0 | 112 | |
michael@0 | 113 | void DoubleToStringConverter::CreateDecimalRepresentation( |
michael@0 | 114 | const char* decimal_digits, |
michael@0 | 115 | int length, |
michael@0 | 116 | int decimal_point, |
michael@0 | 117 | int digits_after_point, |
michael@0 | 118 | StringBuilder* result_builder) const { |
michael@0 | 119 | // Create a representation that is padded with zeros if needed. |
michael@0 | 120 | if (decimal_point <= 0) { |
michael@0 | 121 | // "0.00000decimal_rep". |
michael@0 | 122 | result_builder->AddCharacter('0'); |
michael@0 | 123 | if (digits_after_point > 0) { |
michael@0 | 124 | result_builder->AddCharacter('.'); |
michael@0 | 125 | result_builder->AddPadding('0', -decimal_point); |
michael@0 | 126 | ASSERT(length <= digits_after_point - (-decimal_point)); |
michael@0 | 127 | result_builder->AddSubstring(decimal_digits, length); |
michael@0 | 128 | int remaining_digits = digits_after_point - (-decimal_point) - length; |
michael@0 | 129 | result_builder->AddPadding('0', remaining_digits); |
michael@0 | 130 | } |
michael@0 | 131 | } else if (decimal_point >= length) { |
michael@0 | 132 | // "decimal_rep0000.00000" or "decimal_rep.0000" |
michael@0 | 133 | result_builder->AddSubstring(decimal_digits, length); |
michael@0 | 134 | result_builder->AddPadding('0', decimal_point - length); |
michael@0 | 135 | if (digits_after_point > 0) { |
michael@0 | 136 | result_builder->AddCharacter('.'); |
michael@0 | 137 | result_builder->AddPadding('0', digits_after_point); |
michael@0 | 138 | } |
michael@0 | 139 | } else { |
michael@0 | 140 | // "decima.l_rep000" |
michael@0 | 141 | ASSERT(digits_after_point > 0); |
michael@0 | 142 | result_builder->AddSubstring(decimal_digits, decimal_point); |
michael@0 | 143 | result_builder->AddCharacter('.'); |
michael@0 | 144 | ASSERT(length - decimal_point <= digits_after_point); |
michael@0 | 145 | result_builder->AddSubstring(&decimal_digits[decimal_point], |
michael@0 | 146 | length - decimal_point); |
michael@0 | 147 | int remaining_digits = digits_after_point - (length - decimal_point); |
michael@0 | 148 | result_builder->AddPadding('0', remaining_digits); |
michael@0 | 149 | } |
michael@0 | 150 | if (digits_after_point == 0) { |
michael@0 | 151 | if ((flags_ & EMIT_TRAILING_DECIMAL_POINT) != 0) { |
michael@0 | 152 | result_builder->AddCharacter('.'); |
michael@0 | 153 | } |
michael@0 | 154 | if ((flags_ & EMIT_TRAILING_ZERO_AFTER_POINT) != 0) { |
michael@0 | 155 | result_builder->AddCharacter('0'); |
michael@0 | 156 | } |
michael@0 | 157 | } |
michael@0 | 158 | } |
michael@0 | 159 | |
michael@0 | 160 | |
michael@0 | 161 | bool DoubleToStringConverter::ToShortestIeeeNumber( |
michael@0 | 162 | double value, |
michael@0 | 163 | StringBuilder* result_builder, |
michael@0 | 164 | DoubleToStringConverter::DtoaMode mode) const { |
michael@0 | 165 | ASSERT(mode == SHORTEST || mode == SHORTEST_SINGLE); |
michael@0 | 166 | if (Double(value).IsSpecial()) { |
michael@0 | 167 | return HandleSpecialValues(value, result_builder); |
michael@0 | 168 | } |
michael@0 | 169 | |
michael@0 | 170 | int decimal_point; |
michael@0 | 171 | bool sign; |
michael@0 | 172 | const int kDecimalRepCapacity = kBase10MaximalLength + 1; |
michael@0 | 173 | char decimal_rep[kDecimalRepCapacity]; |
michael@0 | 174 | int decimal_rep_length; |
michael@0 | 175 | |
michael@0 | 176 | DoubleToAscii(value, mode, 0, decimal_rep, kDecimalRepCapacity, |
michael@0 | 177 | &sign, &decimal_rep_length, &decimal_point); |
michael@0 | 178 | |
michael@0 | 179 | bool unique_zero = (flags_ & UNIQUE_ZERO) != 0; |
michael@0 | 180 | if (sign && (value != 0.0 || !unique_zero)) { |
michael@0 | 181 | result_builder->AddCharacter('-'); |
michael@0 | 182 | } |
michael@0 | 183 | |
michael@0 | 184 | int exponent = decimal_point - 1; |
michael@0 | 185 | if ((decimal_in_shortest_low_ <= exponent) && |
michael@0 | 186 | (exponent < decimal_in_shortest_high_)) { |
michael@0 | 187 | CreateDecimalRepresentation(decimal_rep, decimal_rep_length, |
michael@0 | 188 | decimal_point, |
michael@0 | 189 | Max(0, decimal_rep_length - decimal_point), |
michael@0 | 190 | result_builder); |
michael@0 | 191 | } else { |
michael@0 | 192 | CreateExponentialRepresentation(decimal_rep, decimal_rep_length, exponent, |
michael@0 | 193 | result_builder); |
michael@0 | 194 | } |
michael@0 | 195 | return true; |
michael@0 | 196 | } |
michael@0 | 197 | |
michael@0 | 198 | |
michael@0 | 199 | bool DoubleToStringConverter::ToFixed(double value, |
michael@0 | 200 | int requested_digits, |
michael@0 | 201 | StringBuilder* result_builder) const { |
michael@0 | 202 | ASSERT(kMaxFixedDigitsBeforePoint == 60); |
michael@0 | 203 | const double kFirstNonFixed = 1e60; |
michael@0 | 204 | |
michael@0 | 205 | if (Double(value).IsSpecial()) { |
michael@0 | 206 | return HandleSpecialValues(value, result_builder); |
michael@0 | 207 | } |
michael@0 | 208 | |
michael@0 | 209 | if (requested_digits > kMaxFixedDigitsAfterPoint) return false; |
michael@0 | 210 | if (value >= kFirstNonFixed || value <= -kFirstNonFixed) return false; |
michael@0 | 211 | |
michael@0 | 212 | // Find a sufficiently precise decimal representation of n. |
michael@0 | 213 | int decimal_point; |
michael@0 | 214 | bool sign; |
michael@0 | 215 | // Add space for the '\0' byte. |
michael@0 | 216 | const int kDecimalRepCapacity = |
michael@0 | 217 | kMaxFixedDigitsBeforePoint + kMaxFixedDigitsAfterPoint + 1; |
michael@0 | 218 | char decimal_rep[kDecimalRepCapacity]; |
michael@0 | 219 | int decimal_rep_length; |
michael@0 | 220 | DoubleToAscii(value, FIXED, requested_digits, |
michael@0 | 221 | decimal_rep, kDecimalRepCapacity, |
michael@0 | 222 | &sign, &decimal_rep_length, &decimal_point); |
michael@0 | 223 | |
michael@0 | 224 | bool unique_zero = ((flags_ & UNIQUE_ZERO) != 0); |
michael@0 | 225 | if (sign && (value != 0.0 || !unique_zero)) { |
michael@0 | 226 | result_builder->AddCharacter('-'); |
michael@0 | 227 | } |
michael@0 | 228 | |
michael@0 | 229 | CreateDecimalRepresentation(decimal_rep, decimal_rep_length, decimal_point, |
michael@0 | 230 | requested_digits, result_builder); |
michael@0 | 231 | return true; |
michael@0 | 232 | } |
michael@0 | 233 | |
michael@0 | 234 | |
michael@0 | 235 | bool DoubleToStringConverter::ToExponential( |
michael@0 | 236 | double value, |
michael@0 | 237 | int requested_digits, |
michael@0 | 238 | StringBuilder* result_builder) const { |
michael@0 | 239 | if (Double(value).IsSpecial()) { |
michael@0 | 240 | return HandleSpecialValues(value, result_builder); |
michael@0 | 241 | } |
michael@0 | 242 | |
michael@0 | 243 | if (requested_digits < -1) return false; |
michael@0 | 244 | if (requested_digits > kMaxExponentialDigits) return false; |
michael@0 | 245 | |
michael@0 | 246 | int decimal_point; |
michael@0 | 247 | bool sign; |
michael@0 | 248 | // Add space for digit before the decimal point and the '\0' character. |
michael@0 | 249 | const int kDecimalRepCapacity = kMaxExponentialDigits + 2; |
michael@0 | 250 | ASSERT(kDecimalRepCapacity > kBase10MaximalLength); |
michael@0 | 251 | char decimal_rep[kDecimalRepCapacity]; |
michael@0 | 252 | int decimal_rep_length; |
michael@0 | 253 | |
michael@0 | 254 | if (requested_digits == -1) { |
michael@0 | 255 | DoubleToAscii(value, SHORTEST, 0, |
michael@0 | 256 | decimal_rep, kDecimalRepCapacity, |
michael@0 | 257 | &sign, &decimal_rep_length, &decimal_point); |
michael@0 | 258 | } else { |
michael@0 | 259 | DoubleToAscii(value, PRECISION, requested_digits + 1, |
michael@0 | 260 | decimal_rep, kDecimalRepCapacity, |
michael@0 | 261 | &sign, &decimal_rep_length, &decimal_point); |
michael@0 | 262 | ASSERT(decimal_rep_length <= requested_digits + 1); |
michael@0 | 263 | |
michael@0 | 264 | for (int i = decimal_rep_length; i < requested_digits + 1; ++i) { |
michael@0 | 265 | decimal_rep[i] = '0'; |
michael@0 | 266 | } |
michael@0 | 267 | decimal_rep_length = requested_digits + 1; |
michael@0 | 268 | } |
michael@0 | 269 | |
michael@0 | 270 | bool unique_zero = ((flags_ & UNIQUE_ZERO) != 0); |
michael@0 | 271 | if (sign && (value != 0.0 || !unique_zero)) { |
michael@0 | 272 | result_builder->AddCharacter('-'); |
michael@0 | 273 | } |
michael@0 | 274 | |
michael@0 | 275 | int exponent = decimal_point - 1; |
michael@0 | 276 | CreateExponentialRepresentation(decimal_rep, |
michael@0 | 277 | decimal_rep_length, |
michael@0 | 278 | exponent, |
michael@0 | 279 | result_builder); |
michael@0 | 280 | return true; |
michael@0 | 281 | } |
michael@0 | 282 | |
michael@0 | 283 | |
michael@0 | 284 | bool DoubleToStringConverter::ToPrecision(double value, |
michael@0 | 285 | int precision, |
michael@0 | 286 | bool* used_exponential_notation, |
michael@0 | 287 | StringBuilder* result_builder) const { |
michael@0 | 288 | *used_exponential_notation = false; |
michael@0 | 289 | if (Double(value).IsSpecial()) { |
michael@0 | 290 | return HandleSpecialValues(value, result_builder); |
michael@0 | 291 | } |
michael@0 | 292 | |
michael@0 | 293 | if (precision < kMinPrecisionDigits || precision > kMaxPrecisionDigits) { |
michael@0 | 294 | return false; |
michael@0 | 295 | } |
michael@0 | 296 | |
michael@0 | 297 | // Find a sufficiently precise decimal representation of n. |
michael@0 | 298 | int decimal_point; |
michael@0 | 299 | bool sign; |
michael@0 | 300 | // Add one for the terminating null character. |
michael@0 | 301 | const int kDecimalRepCapacity = kMaxPrecisionDigits + 1; |
michael@0 | 302 | char decimal_rep[kDecimalRepCapacity]; |
michael@0 | 303 | int decimal_rep_length; |
michael@0 | 304 | |
michael@0 | 305 | DoubleToAscii(value, PRECISION, precision, |
michael@0 | 306 | decimal_rep, kDecimalRepCapacity, |
michael@0 | 307 | &sign, &decimal_rep_length, &decimal_point); |
michael@0 | 308 | ASSERT(decimal_rep_length <= precision); |
michael@0 | 309 | |
michael@0 | 310 | bool unique_zero = ((flags_ & UNIQUE_ZERO) != 0); |
michael@0 | 311 | if (sign && (value != 0.0 || !unique_zero)) { |
michael@0 | 312 | result_builder->AddCharacter('-'); |
michael@0 | 313 | } |
michael@0 | 314 | |
michael@0 | 315 | // The exponent if we print the number as x.xxeyyy. That is with the |
michael@0 | 316 | // decimal point after the first digit. |
michael@0 | 317 | int exponent = decimal_point - 1; |
michael@0 | 318 | |
michael@0 | 319 | int extra_zero = ((flags_ & EMIT_TRAILING_ZERO_AFTER_POINT) != 0) ? 1 : 0; |
michael@0 | 320 | if ((-decimal_point + 1 > max_leading_padding_zeroes_in_precision_mode_) || |
michael@0 | 321 | (decimal_point - precision + extra_zero > |
michael@0 | 322 | max_trailing_padding_zeroes_in_precision_mode_)) { |
michael@0 | 323 | // Fill buffer to contain 'precision' digits. |
michael@0 | 324 | // Usually the buffer is already at the correct length, but 'DoubleToAscii' |
michael@0 | 325 | // is allowed to return less characters. |
michael@0 | 326 | for (int i = decimal_rep_length; i < precision; ++i) { |
michael@0 | 327 | decimal_rep[i] = '0'; |
michael@0 | 328 | } |
michael@0 | 329 | |
michael@0 | 330 | *used_exponential_notation = true; |
michael@0 | 331 | CreateExponentialRepresentation(decimal_rep, |
michael@0 | 332 | precision, |
michael@0 | 333 | exponent, |
michael@0 | 334 | result_builder); |
michael@0 | 335 | } else { |
michael@0 | 336 | CreateDecimalRepresentation(decimal_rep, decimal_rep_length, decimal_point, |
michael@0 | 337 | Max(0, precision - decimal_point), |
michael@0 | 338 | result_builder); |
michael@0 | 339 | } |
michael@0 | 340 | return true; |
michael@0 | 341 | } |
michael@0 | 342 | |
michael@0 | 343 | |
michael@0 | 344 | static BignumDtoaMode DtoaToBignumDtoaMode( |
michael@0 | 345 | DoubleToStringConverter::DtoaMode dtoa_mode) { |
michael@0 | 346 | switch (dtoa_mode) { |
michael@0 | 347 | case DoubleToStringConverter::SHORTEST: return BIGNUM_DTOA_SHORTEST; |
michael@0 | 348 | case DoubleToStringConverter::SHORTEST_SINGLE: |
michael@0 | 349 | return BIGNUM_DTOA_SHORTEST_SINGLE; |
michael@0 | 350 | case DoubleToStringConverter::FIXED: return BIGNUM_DTOA_FIXED; |
michael@0 | 351 | case DoubleToStringConverter::PRECISION: return BIGNUM_DTOA_PRECISION; |
michael@0 | 352 | default: |
michael@0 | 353 | UNREACHABLE(); |
michael@0 | 354 | return BIGNUM_DTOA_SHORTEST; // To silence compiler. |
michael@0 | 355 | } |
michael@0 | 356 | } |
michael@0 | 357 | |
michael@0 | 358 | |
michael@0 | 359 | void DoubleToStringConverter::DoubleToAscii(double v, |
michael@0 | 360 | DtoaMode mode, |
michael@0 | 361 | int requested_digits, |
michael@0 | 362 | char* buffer, |
michael@0 | 363 | int buffer_length, |
michael@0 | 364 | bool* sign, |
michael@0 | 365 | int* length, |
michael@0 | 366 | int* point) { |
michael@0 | 367 | Vector<char> vector(buffer, buffer_length); |
michael@0 | 368 | ASSERT(!Double(v).IsSpecial()); |
michael@0 | 369 | ASSERT(mode == SHORTEST || mode == SHORTEST_SINGLE || requested_digits >= 0); |
michael@0 | 370 | |
michael@0 | 371 | if (Double(v).Sign() < 0) { |
michael@0 | 372 | *sign = true; |
michael@0 | 373 | v = -v; |
michael@0 | 374 | } else { |
michael@0 | 375 | *sign = false; |
michael@0 | 376 | } |
michael@0 | 377 | |
michael@0 | 378 | if (mode == PRECISION && requested_digits == 0) { |
michael@0 | 379 | vector[0] = '\0'; |
michael@0 | 380 | *length = 0; |
michael@0 | 381 | return; |
michael@0 | 382 | } |
michael@0 | 383 | |
michael@0 | 384 | if (v == 0) { |
michael@0 | 385 | vector[0] = '0'; |
michael@0 | 386 | vector[1] = '\0'; |
michael@0 | 387 | *length = 1; |
michael@0 | 388 | *point = 1; |
michael@0 | 389 | return; |
michael@0 | 390 | } |
michael@0 | 391 | |
michael@0 | 392 | bool fast_worked; |
michael@0 | 393 | switch (mode) { |
michael@0 | 394 | case SHORTEST: |
michael@0 | 395 | fast_worked = FastDtoa(v, FAST_DTOA_SHORTEST, 0, vector, length, point); |
michael@0 | 396 | break; |
michael@0 | 397 | case SHORTEST_SINGLE: |
michael@0 | 398 | fast_worked = FastDtoa(v, FAST_DTOA_SHORTEST_SINGLE, 0, |
michael@0 | 399 | vector, length, point); |
michael@0 | 400 | break; |
michael@0 | 401 | case FIXED: |
michael@0 | 402 | fast_worked = FastFixedDtoa(v, requested_digits, vector, length, point); |
michael@0 | 403 | break; |
michael@0 | 404 | case PRECISION: |
michael@0 | 405 | fast_worked = FastDtoa(v, FAST_DTOA_PRECISION, requested_digits, |
michael@0 | 406 | vector, length, point); |
michael@0 | 407 | break; |
michael@0 | 408 | default: |
michael@0 | 409 | UNREACHABLE(); |
michael@0 | 410 | fast_worked = false; |
michael@0 | 411 | } |
michael@0 | 412 | if (fast_worked) return; |
michael@0 | 413 | |
michael@0 | 414 | // If the fast dtoa didn't succeed use the slower bignum version. |
michael@0 | 415 | BignumDtoaMode bignum_mode = DtoaToBignumDtoaMode(mode); |
michael@0 | 416 | BignumDtoa(v, bignum_mode, requested_digits, vector, length, point); |
michael@0 | 417 | vector[*length] = '\0'; |
michael@0 | 418 | } |
michael@0 | 419 | |
michael@0 | 420 | |
michael@0 | 421 | // Consumes the given substring from the iterator. |
michael@0 | 422 | // Returns false, if the substring does not match. |
michael@0 | 423 | static bool ConsumeSubString(const char** current, |
michael@0 | 424 | const char* end, |
michael@0 | 425 | const char* substring) { |
michael@0 | 426 | ASSERT(**current == *substring); |
michael@0 | 427 | for (substring++; *substring != '\0'; substring++) { |
michael@0 | 428 | ++*current; |
michael@0 | 429 | if (*current == end || **current != *substring) return false; |
michael@0 | 430 | } |
michael@0 | 431 | ++*current; |
michael@0 | 432 | return true; |
michael@0 | 433 | } |
michael@0 | 434 | |
michael@0 | 435 | |
michael@0 | 436 | // Maximum number of significant digits in decimal representation. |
michael@0 | 437 | // The longest possible double in decimal representation is |
michael@0 | 438 | // (2^53 - 1) * 2 ^ -1074 that is (2 ^ 53 - 1) * 5 ^ 1074 / 10 ^ 1074 |
michael@0 | 439 | // (768 digits). If we parse a number whose first digits are equal to a |
michael@0 | 440 | // mean of 2 adjacent doubles (that could have up to 769 digits) the result |
michael@0 | 441 | // must be rounded to the bigger one unless the tail consists of zeros, so |
michael@0 | 442 | // we don't need to preserve all the digits. |
michael@0 | 443 | const int kMaxSignificantDigits = 772; |
michael@0 | 444 | |
michael@0 | 445 | |
michael@0 | 446 | // Returns true if a nonspace found and false if the end has reached. |
michael@0 | 447 | static inline bool AdvanceToNonspace(const char** current, const char* end) { |
michael@0 | 448 | while (*current != end) { |
michael@0 | 449 | if (**current != ' ') return true; |
michael@0 | 450 | ++*current; |
michael@0 | 451 | } |
michael@0 | 452 | return false; |
michael@0 | 453 | } |
michael@0 | 454 | |
michael@0 | 455 | |
michael@0 | 456 | static bool isDigit(int x, int radix) { |
michael@0 | 457 | return (x >= '0' && x <= '9' && x < '0' + radix) |
michael@0 | 458 | || (radix > 10 && x >= 'a' && x < 'a' + radix - 10) |
michael@0 | 459 | || (radix > 10 && x >= 'A' && x < 'A' + radix - 10); |
michael@0 | 460 | } |
michael@0 | 461 | |
michael@0 | 462 | |
michael@0 | 463 | static double SignedZero(bool sign) { |
michael@0 | 464 | return sign ? -0.0 : 0.0; |
michael@0 | 465 | } |
michael@0 | 466 | |
michael@0 | 467 | |
michael@0 | 468 | // Parsing integers with radix 2, 4, 8, 16, 32. Assumes current != end. |
michael@0 | 469 | template <int radix_log_2> |
michael@0 | 470 | static double RadixStringToIeee(const char* current, |
michael@0 | 471 | const char* end, |
michael@0 | 472 | bool sign, |
michael@0 | 473 | bool allow_trailing_junk, |
michael@0 | 474 | double junk_string_value, |
michael@0 | 475 | bool read_as_double, |
michael@0 | 476 | const char** trailing_pointer) { |
michael@0 | 477 | ASSERT(current != end); |
michael@0 | 478 | |
michael@0 | 479 | const int kDoubleSize = Double::kSignificandSize; |
michael@0 | 480 | const int kSingleSize = Single::kSignificandSize; |
michael@0 | 481 | const int kSignificandSize = read_as_double? kDoubleSize: kSingleSize; |
michael@0 | 482 | |
michael@0 | 483 | // Skip leading 0s. |
michael@0 | 484 | while (*current == '0') { |
michael@0 | 485 | ++current; |
michael@0 | 486 | if (current == end) { |
michael@0 | 487 | *trailing_pointer = end; |
michael@0 | 488 | return SignedZero(sign); |
michael@0 | 489 | } |
michael@0 | 490 | } |
michael@0 | 491 | |
michael@0 | 492 | int64_t number = 0; |
michael@0 | 493 | int exponent = 0; |
michael@0 | 494 | const int radix = (1 << radix_log_2); |
michael@0 | 495 | |
michael@0 | 496 | do { |
michael@0 | 497 | int digit; |
michael@0 | 498 | if (*current >= '0' && *current <= '9' && *current < '0' + radix) { |
michael@0 | 499 | digit = static_cast<char>(*current) - '0'; |
michael@0 | 500 | } else if (radix > 10 && *current >= 'a' && *current < 'a' + radix - 10) { |
michael@0 | 501 | digit = static_cast<char>(*current) - 'a' + 10; |
michael@0 | 502 | } else if (radix > 10 && *current >= 'A' && *current < 'A' + radix - 10) { |
michael@0 | 503 | digit = static_cast<char>(*current) - 'A' + 10; |
michael@0 | 504 | } else { |
michael@0 | 505 | if (allow_trailing_junk || !AdvanceToNonspace(¤t, end)) { |
michael@0 | 506 | break; |
michael@0 | 507 | } else { |
michael@0 | 508 | return junk_string_value; |
michael@0 | 509 | } |
michael@0 | 510 | } |
michael@0 | 511 | |
michael@0 | 512 | number = number * radix + digit; |
michael@0 | 513 | int overflow = static_cast<int>(number >> kSignificandSize); |
michael@0 | 514 | if (overflow != 0) { |
michael@0 | 515 | // Overflow occurred. Need to determine which direction to round the |
michael@0 | 516 | // result. |
michael@0 | 517 | int overflow_bits_count = 1; |
michael@0 | 518 | while (overflow > 1) { |
michael@0 | 519 | overflow_bits_count++; |
michael@0 | 520 | overflow >>= 1; |
michael@0 | 521 | } |
michael@0 | 522 | |
michael@0 | 523 | int dropped_bits_mask = ((1 << overflow_bits_count) - 1); |
michael@0 | 524 | int dropped_bits = static_cast<int>(number) & dropped_bits_mask; |
michael@0 | 525 | number >>= overflow_bits_count; |
michael@0 | 526 | exponent = overflow_bits_count; |
michael@0 | 527 | |
michael@0 | 528 | bool zero_tail = true; |
michael@0 | 529 | while (true) { |
michael@0 | 530 | ++current; |
michael@0 | 531 | if (current == end || !isDigit(*current, radix)) break; |
michael@0 | 532 | zero_tail = zero_tail && *current == '0'; |
michael@0 | 533 | exponent += radix_log_2; |
michael@0 | 534 | } |
michael@0 | 535 | |
michael@0 | 536 | if (!allow_trailing_junk && AdvanceToNonspace(¤t, end)) { |
michael@0 | 537 | return junk_string_value; |
michael@0 | 538 | } |
michael@0 | 539 | |
michael@0 | 540 | int middle_value = (1 << (overflow_bits_count - 1)); |
michael@0 | 541 | if (dropped_bits > middle_value) { |
michael@0 | 542 | number++; // Rounding up. |
michael@0 | 543 | } else if (dropped_bits == middle_value) { |
michael@0 | 544 | // Rounding to even to consistency with decimals: half-way case rounds |
michael@0 | 545 | // up if significant part is odd and down otherwise. |
michael@0 | 546 | if ((number & 1) != 0 || !zero_tail) { |
michael@0 | 547 | number++; // Rounding up. |
michael@0 | 548 | } |
michael@0 | 549 | } |
michael@0 | 550 | |
michael@0 | 551 | // Rounding up may cause overflow. |
michael@0 | 552 | if ((number & ((int64_t)1 << kSignificandSize)) != 0) { |
michael@0 | 553 | exponent++; |
michael@0 | 554 | number >>= 1; |
michael@0 | 555 | } |
michael@0 | 556 | break; |
michael@0 | 557 | } |
michael@0 | 558 | ++current; |
michael@0 | 559 | } while (current != end); |
michael@0 | 560 | |
michael@0 | 561 | ASSERT(number < ((int64_t)1 << kSignificandSize)); |
michael@0 | 562 | ASSERT(static_cast<int64_t>(static_cast<double>(number)) == number); |
michael@0 | 563 | |
michael@0 | 564 | *trailing_pointer = current; |
michael@0 | 565 | |
michael@0 | 566 | if (exponent == 0) { |
michael@0 | 567 | if (sign) { |
michael@0 | 568 | if (number == 0) return -0.0; |
michael@0 | 569 | number = -number; |
michael@0 | 570 | } |
michael@0 | 571 | return static_cast<double>(number); |
michael@0 | 572 | } |
michael@0 | 573 | |
michael@0 | 574 | ASSERT(number != 0); |
michael@0 | 575 | return Double(DiyFp(number, exponent)).value(); |
michael@0 | 576 | } |
michael@0 | 577 | |
michael@0 | 578 | |
michael@0 | 579 | double StringToDoubleConverter::StringToIeee( |
michael@0 | 580 | const char* input, |
michael@0 | 581 | int length, |
michael@0 | 582 | int* processed_characters_count, |
michael@0 | 583 | bool read_as_double) const { |
michael@0 | 584 | const char* current = input; |
michael@0 | 585 | const char* end = input + length; |
michael@0 | 586 | |
michael@0 | 587 | *processed_characters_count = 0; |
michael@0 | 588 | |
michael@0 | 589 | const bool allow_trailing_junk = (flags_ & ALLOW_TRAILING_JUNK) != 0; |
michael@0 | 590 | const bool allow_leading_spaces = (flags_ & ALLOW_LEADING_SPACES) != 0; |
michael@0 | 591 | const bool allow_trailing_spaces = (flags_ & ALLOW_TRAILING_SPACES) != 0; |
michael@0 | 592 | const bool allow_spaces_after_sign = (flags_ & ALLOW_SPACES_AFTER_SIGN) != 0; |
michael@0 | 593 | |
michael@0 | 594 | // To make sure that iterator dereferencing is valid the following |
michael@0 | 595 | // convention is used: |
michael@0 | 596 | // 1. Each '++current' statement is followed by check for equality to 'end'. |
michael@0 | 597 | // 2. If AdvanceToNonspace returned false then current == end. |
michael@0 | 598 | // 3. If 'current' becomes equal to 'end' the function returns or goes to |
michael@0 | 599 | // 'parsing_done'. |
michael@0 | 600 | // 4. 'current' is not dereferenced after the 'parsing_done' label. |
michael@0 | 601 | // 5. Code before 'parsing_done' may rely on 'current != end'. |
michael@0 | 602 | if (current == end) return empty_string_value_; |
michael@0 | 603 | |
michael@0 | 604 | if (allow_leading_spaces || allow_trailing_spaces) { |
michael@0 | 605 | if (!AdvanceToNonspace(¤t, end)) { |
michael@0 | 606 | *processed_characters_count = current - input; |
michael@0 | 607 | return empty_string_value_; |
michael@0 | 608 | } |
michael@0 | 609 | if (!allow_leading_spaces && (input != current)) { |
michael@0 | 610 | // No leading spaces allowed, but AdvanceToNonspace moved forward. |
michael@0 | 611 | return junk_string_value_; |
michael@0 | 612 | } |
michael@0 | 613 | } |
michael@0 | 614 | |
michael@0 | 615 | // The longest form of simplified number is: "-<significant digits>.1eXXX\0". |
michael@0 | 616 | const int kBufferSize = kMaxSignificantDigits + 10; |
michael@0 | 617 | char buffer[kBufferSize]; // NOLINT: size is known at compile time. |
michael@0 | 618 | int buffer_pos = 0; |
michael@0 | 619 | |
michael@0 | 620 | // Exponent will be adjusted if insignificant digits of the integer part |
michael@0 | 621 | // or insignificant leading zeros of the fractional part are dropped. |
michael@0 | 622 | int exponent = 0; |
michael@0 | 623 | int significant_digits = 0; |
michael@0 | 624 | int insignificant_digits = 0; |
michael@0 | 625 | bool nonzero_digit_dropped = false; |
michael@0 | 626 | |
michael@0 | 627 | bool sign = false; |
michael@0 | 628 | |
michael@0 | 629 | if (*current == '+' || *current == '-') { |
michael@0 | 630 | sign = (*current == '-'); |
michael@0 | 631 | ++current; |
michael@0 | 632 | const char* next_non_space = current; |
michael@0 | 633 | // Skip following spaces (if allowed). |
michael@0 | 634 | if (!AdvanceToNonspace(&next_non_space, end)) return junk_string_value_; |
michael@0 | 635 | if (!allow_spaces_after_sign && (current != next_non_space)) { |
michael@0 | 636 | return junk_string_value_; |
michael@0 | 637 | } |
michael@0 | 638 | current = next_non_space; |
michael@0 | 639 | } |
michael@0 | 640 | |
michael@0 | 641 | if (infinity_symbol_ != NULL) { |
michael@0 | 642 | if (*current == infinity_symbol_[0]) { |
michael@0 | 643 | if (!ConsumeSubString(¤t, end, infinity_symbol_)) { |
michael@0 | 644 | return junk_string_value_; |
michael@0 | 645 | } |
michael@0 | 646 | |
michael@0 | 647 | if (!(allow_trailing_spaces || allow_trailing_junk) && (current != end)) { |
michael@0 | 648 | return junk_string_value_; |
michael@0 | 649 | } |
michael@0 | 650 | if (!allow_trailing_junk && AdvanceToNonspace(¤t, end)) { |
michael@0 | 651 | return junk_string_value_; |
michael@0 | 652 | } |
michael@0 | 653 | |
michael@0 | 654 | ASSERT(buffer_pos == 0); |
michael@0 | 655 | *processed_characters_count = current - input; |
michael@0 | 656 | return sign ? -Double::Infinity() : Double::Infinity(); |
michael@0 | 657 | } |
michael@0 | 658 | } |
michael@0 | 659 | |
michael@0 | 660 | if (nan_symbol_ != NULL) { |
michael@0 | 661 | if (*current == nan_symbol_[0]) { |
michael@0 | 662 | if (!ConsumeSubString(¤t, end, nan_symbol_)) { |
michael@0 | 663 | return junk_string_value_; |
michael@0 | 664 | } |
michael@0 | 665 | |
michael@0 | 666 | if (!(allow_trailing_spaces || allow_trailing_junk) && (current != end)) { |
michael@0 | 667 | return junk_string_value_; |
michael@0 | 668 | } |
michael@0 | 669 | if (!allow_trailing_junk && AdvanceToNonspace(¤t, end)) { |
michael@0 | 670 | return junk_string_value_; |
michael@0 | 671 | } |
michael@0 | 672 | |
michael@0 | 673 | ASSERT(buffer_pos == 0); |
michael@0 | 674 | *processed_characters_count = current - input; |
michael@0 | 675 | return sign ? -Double::NaN() : Double::NaN(); |
michael@0 | 676 | } |
michael@0 | 677 | } |
michael@0 | 678 | |
michael@0 | 679 | bool leading_zero = false; |
michael@0 | 680 | if (*current == '0') { |
michael@0 | 681 | ++current; |
michael@0 | 682 | if (current == end) { |
michael@0 | 683 | *processed_characters_count = current - input; |
michael@0 | 684 | return SignedZero(sign); |
michael@0 | 685 | } |
michael@0 | 686 | |
michael@0 | 687 | leading_zero = true; |
michael@0 | 688 | |
michael@0 | 689 | // It could be hexadecimal value. |
michael@0 | 690 | if ((flags_ & ALLOW_HEX) && (*current == 'x' || *current == 'X')) { |
michael@0 | 691 | ++current; |
michael@0 | 692 | if (current == end || !isDigit(*current, 16)) { |
michael@0 | 693 | return junk_string_value_; // "0x". |
michael@0 | 694 | } |
michael@0 | 695 | |
michael@0 | 696 | const char* tail_pointer = NULL; |
michael@0 | 697 | double result = RadixStringToIeee<4>(current, |
michael@0 | 698 | end, |
michael@0 | 699 | sign, |
michael@0 | 700 | allow_trailing_junk, |
michael@0 | 701 | junk_string_value_, |
michael@0 | 702 | read_as_double, |
michael@0 | 703 | &tail_pointer); |
michael@0 | 704 | if (tail_pointer != NULL) { |
michael@0 | 705 | if (allow_trailing_spaces) AdvanceToNonspace(&tail_pointer, end); |
michael@0 | 706 | *processed_characters_count = tail_pointer - input; |
michael@0 | 707 | } |
michael@0 | 708 | return result; |
michael@0 | 709 | } |
michael@0 | 710 | |
michael@0 | 711 | // Ignore leading zeros in the integer part. |
michael@0 | 712 | while (*current == '0') { |
michael@0 | 713 | ++current; |
michael@0 | 714 | if (current == end) { |
michael@0 | 715 | *processed_characters_count = current - input; |
michael@0 | 716 | return SignedZero(sign); |
michael@0 | 717 | } |
michael@0 | 718 | } |
michael@0 | 719 | } |
michael@0 | 720 | |
michael@0 | 721 | bool octal = leading_zero && (flags_ & ALLOW_OCTALS) != 0; |
michael@0 | 722 | |
michael@0 | 723 | // Copy significant digits of the integer part (if any) to the buffer. |
michael@0 | 724 | while (*current >= '0' && *current <= '9') { |
michael@0 | 725 | if (significant_digits < kMaxSignificantDigits) { |
michael@0 | 726 | ASSERT(buffer_pos < kBufferSize); |
michael@0 | 727 | buffer[buffer_pos++] = static_cast<char>(*current); |
michael@0 | 728 | significant_digits++; |
michael@0 | 729 | // Will later check if it's an octal in the buffer. |
michael@0 | 730 | } else { |
michael@0 | 731 | insignificant_digits++; // Move the digit into the exponential part. |
michael@0 | 732 | nonzero_digit_dropped = nonzero_digit_dropped || *current != '0'; |
michael@0 | 733 | } |
michael@0 | 734 | octal = octal && *current < '8'; |
michael@0 | 735 | ++current; |
michael@0 | 736 | if (current == end) goto parsing_done; |
michael@0 | 737 | } |
michael@0 | 738 | |
michael@0 | 739 | if (significant_digits == 0) { |
michael@0 | 740 | octal = false; |
michael@0 | 741 | } |
michael@0 | 742 | |
michael@0 | 743 | if (*current == '.') { |
michael@0 | 744 | if (octal && !allow_trailing_junk) return junk_string_value_; |
michael@0 | 745 | if (octal) goto parsing_done; |
michael@0 | 746 | |
michael@0 | 747 | ++current; |
michael@0 | 748 | if (current == end) { |
michael@0 | 749 | if (significant_digits == 0 && !leading_zero) { |
michael@0 | 750 | return junk_string_value_; |
michael@0 | 751 | } else { |
michael@0 | 752 | goto parsing_done; |
michael@0 | 753 | } |
michael@0 | 754 | } |
michael@0 | 755 | |
michael@0 | 756 | if (significant_digits == 0) { |
michael@0 | 757 | // octal = false; |
michael@0 | 758 | // Integer part consists of 0 or is absent. Significant digits start after |
michael@0 | 759 | // leading zeros (if any). |
michael@0 | 760 | while (*current == '0') { |
michael@0 | 761 | ++current; |
michael@0 | 762 | if (current == end) { |
michael@0 | 763 | *processed_characters_count = current - input; |
michael@0 | 764 | return SignedZero(sign); |
michael@0 | 765 | } |
michael@0 | 766 | exponent--; // Move this 0 into the exponent. |
michael@0 | 767 | } |
michael@0 | 768 | } |
michael@0 | 769 | |
michael@0 | 770 | // There is a fractional part. |
michael@0 | 771 | // We don't emit a '.', but adjust the exponent instead. |
michael@0 | 772 | while (*current >= '0' && *current <= '9') { |
michael@0 | 773 | if (significant_digits < kMaxSignificantDigits) { |
michael@0 | 774 | ASSERT(buffer_pos < kBufferSize); |
michael@0 | 775 | buffer[buffer_pos++] = static_cast<char>(*current); |
michael@0 | 776 | significant_digits++; |
michael@0 | 777 | exponent--; |
michael@0 | 778 | } else { |
michael@0 | 779 | // Ignore insignificant digits in the fractional part. |
michael@0 | 780 | nonzero_digit_dropped = nonzero_digit_dropped || *current != '0'; |
michael@0 | 781 | } |
michael@0 | 782 | ++current; |
michael@0 | 783 | if (current == end) goto parsing_done; |
michael@0 | 784 | } |
michael@0 | 785 | } |
michael@0 | 786 | |
michael@0 | 787 | if (!leading_zero && exponent == 0 && significant_digits == 0) { |
michael@0 | 788 | // If leading_zeros is true then the string contains zeros. |
michael@0 | 789 | // If exponent < 0 then string was [+-]\.0*... |
michael@0 | 790 | // If significant_digits != 0 the string is not equal to 0. |
michael@0 | 791 | // Otherwise there are no digits in the string. |
michael@0 | 792 | return junk_string_value_; |
michael@0 | 793 | } |
michael@0 | 794 | |
michael@0 | 795 | // Parse exponential part. |
michael@0 | 796 | if (*current == 'e' || *current == 'E') { |
michael@0 | 797 | if (octal && !allow_trailing_junk) return junk_string_value_; |
michael@0 | 798 | if (octal) goto parsing_done; |
michael@0 | 799 | ++current; |
michael@0 | 800 | if (current == end) { |
michael@0 | 801 | if (allow_trailing_junk) { |
michael@0 | 802 | goto parsing_done; |
michael@0 | 803 | } else { |
michael@0 | 804 | return junk_string_value_; |
michael@0 | 805 | } |
michael@0 | 806 | } |
michael@0 | 807 | char sign = '+'; |
michael@0 | 808 | if (*current == '+' || *current == '-') { |
michael@0 | 809 | sign = static_cast<char>(*current); |
michael@0 | 810 | ++current; |
michael@0 | 811 | if (current == end) { |
michael@0 | 812 | if (allow_trailing_junk) { |
michael@0 | 813 | goto parsing_done; |
michael@0 | 814 | } else { |
michael@0 | 815 | return junk_string_value_; |
michael@0 | 816 | } |
michael@0 | 817 | } |
michael@0 | 818 | } |
michael@0 | 819 | |
michael@0 | 820 | if (current == end || *current < '0' || *current > '9') { |
michael@0 | 821 | if (allow_trailing_junk) { |
michael@0 | 822 | goto parsing_done; |
michael@0 | 823 | } else { |
michael@0 | 824 | return junk_string_value_; |
michael@0 | 825 | } |
michael@0 | 826 | } |
michael@0 | 827 | |
michael@0 | 828 | const int max_exponent = INT_MAX / 2; |
michael@0 | 829 | ASSERT(-max_exponent / 2 <= exponent && exponent <= max_exponent / 2); |
michael@0 | 830 | int num = 0; |
michael@0 | 831 | do { |
michael@0 | 832 | // Check overflow. |
michael@0 | 833 | int digit = *current - '0'; |
michael@0 | 834 | if (num >= max_exponent / 10 |
michael@0 | 835 | && !(num == max_exponent / 10 && digit <= max_exponent % 10)) { |
michael@0 | 836 | num = max_exponent; |
michael@0 | 837 | } else { |
michael@0 | 838 | num = num * 10 + digit; |
michael@0 | 839 | } |
michael@0 | 840 | ++current; |
michael@0 | 841 | } while (current != end && *current >= '0' && *current <= '9'); |
michael@0 | 842 | |
michael@0 | 843 | exponent += (sign == '-' ? -num : num); |
michael@0 | 844 | } |
michael@0 | 845 | |
michael@0 | 846 | if (!(allow_trailing_spaces || allow_trailing_junk) && (current != end)) { |
michael@0 | 847 | return junk_string_value_; |
michael@0 | 848 | } |
michael@0 | 849 | if (!allow_trailing_junk && AdvanceToNonspace(¤t, end)) { |
michael@0 | 850 | return junk_string_value_; |
michael@0 | 851 | } |
michael@0 | 852 | if (allow_trailing_spaces) { |
michael@0 | 853 | AdvanceToNonspace(¤t, end); |
michael@0 | 854 | } |
michael@0 | 855 | |
michael@0 | 856 | parsing_done: |
michael@0 | 857 | exponent += insignificant_digits; |
michael@0 | 858 | |
michael@0 | 859 | if (octal) { |
michael@0 | 860 | double result; |
michael@0 | 861 | const char* tail_pointer = NULL; |
michael@0 | 862 | result = RadixStringToIeee<3>(buffer, |
michael@0 | 863 | buffer + buffer_pos, |
michael@0 | 864 | sign, |
michael@0 | 865 | allow_trailing_junk, |
michael@0 | 866 | junk_string_value_, |
michael@0 | 867 | read_as_double, |
michael@0 | 868 | &tail_pointer); |
michael@0 | 869 | ASSERT(tail_pointer != NULL); |
michael@0 | 870 | *processed_characters_count = current - input; |
michael@0 | 871 | return result; |
michael@0 | 872 | } |
michael@0 | 873 | |
michael@0 | 874 | if (nonzero_digit_dropped) { |
michael@0 | 875 | buffer[buffer_pos++] = '1'; |
michael@0 | 876 | exponent--; |
michael@0 | 877 | } |
michael@0 | 878 | |
michael@0 | 879 | ASSERT(buffer_pos < kBufferSize); |
michael@0 | 880 | buffer[buffer_pos] = '\0'; |
michael@0 | 881 | |
michael@0 | 882 | double converted; |
michael@0 | 883 | if (read_as_double) { |
michael@0 | 884 | converted = Strtod(Vector<const char>(buffer, buffer_pos), exponent); |
michael@0 | 885 | } else { |
michael@0 | 886 | converted = Strtof(Vector<const char>(buffer, buffer_pos), exponent); |
michael@0 | 887 | } |
michael@0 | 888 | *processed_characters_count = current - input; |
michael@0 | 889 | return sign? -converted: converted; |
michael@0 | 890 | } |
michael@0 | 891 | |
michael@0 | 892 | } // namespace double_conversion |