blob: 4b4faa551ffc87a70e49414db043f1e7c7974226 [file] [log] [blame]
ager@chromium.org9258b6b2008-09-11 09:11:10 +00001// Copyright 2006-2008 the V8 project authors. All rights reserved.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002// 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 <stdarg.h>
29
30#include "v8.h"
31
32#include "conversions-inl.h"
33#include "factory.h"
34#include "scanner.h"
35
36namespace v8 { namespace internal {
37
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000038int HexValue(uc32 c) {
39 if ('0' <= c && c <= '9')
40 return c - '0';
41 if ('a' <= c && c <= 'f')
42 return c - 'a' + 10;
43 if ('A' <= c && c <= 'F')
44 return c - 'A' + 10;
45 return -1;
46}
47
48
49// Provide a common interface to getting a character at a certain
50// index from a char* or a String object.
51static inline int GetChar(const char* str, int index) {
52 ASSERT(index >= 0 && index < static_cast<int>(strlen(str)));
53 return str[index];
54}
55
56
57static inline int GetChar(String* str, int index) {
ager@chromium.org870a0b62008-11-04 11:43:05 +000058 StringShape shape(str);
59 return str->Get(shape, index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000060}
61
62
63static inline int GetLength(const char* str) {
64 return strlen(str);
65}
66
67
68static inline int GetLength(String* str) {
69 return str->length();
70}
71
72
73static inline const char* GetCString(const char* str, int index) {
74 return str + index;
75}
76
77
78static inline const char* GetCString(String* str, int index) {
ager@chromium.org870a0b62008-11-04 11:43:05 +000079 StringShape shape(str);
80 int length = str->length(shape);
81 char* result = NewArray<char>(length + 1);
82 for (int i = index; i < length; i++) {
83 uc16 c = str->Get(shape, i);
84 if (c <= 127) {
85 result[i - index] = static_cast<char>(c);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000086 } else {
87 result[i - index] = 127; // Force number parsing to fail.
88 }
89 }
ager@chromium.org870a0b62008-11-04 11:43:05 +000090 result[length - index] = '\0';
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000091 return result;
92}
93
94
95static inline void ReleaseCString(const char* original, const char* str) {
96}
97
98
99static inline void ReleaseCString(String* original, const char* str) {
100 DeleteArray(const_cast<char *>(str));
101}
102
103
104static inline bool IsSpace(const char* str, int index) {
105 ASSERT(index >= 0 && index < static_cast<int>(strlen(str)));
106 return Scanner::kIsWhiteSpace.get(str[index]);
107}
108
109
110static inline bool IsSpace(String* str, int index) {
ager@chromium.org870a0b62008-11-04 11:43:05 +0000111 StringShape shape(str);
112 return Scanner::kIsWhiteSpace.get(str->Get(shape, index));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000113}
114
115
116static inline bool SubStringEquals(const char* str,
117 int index,
118 const char* other) {
119 return strncmp(str + index, other, strlen(other)) != 0;
120}
121
122
123static inline bool SubStringEquals(String* str, int index, const char* other) {
124 HandleScope scope;
ager@chromium.orgc3e50d82008-11-05 11:53:10 +0000125 int str_length = str->length();
ager@chromium.org870a0b62008-11-04 11:43:05 +0000126 int other_length = strlen(other);
127 int end = index + other_length < str_length ?
128 index + other_length :
129 str_length;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000130 Handle<String> slice =
ager@chromium.orgc3e50d82008-11-05 11:53:10 +0000131 Factory::NewStringSlice(Handle<String>(str), index, end);
ager@chromium.org870a0b62008-11-04 11:43:05 +0000132 return slice->IsEqualTo(Vector<const char>(other, other_length));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000133}
134
135
136// Check if a string should be parsed as an octal number. The string
137// can be either a char* or a String*.
138template<class S>
139static bool ShouldParseOctal(S* s, int i) {
140 int index = i;
141 int len = GetLength(s);
142 if (index < len && GetChar(s, index) != '0') return false;
143
144 // If the first real character (following '0') is not an octal
145 // digit, bail out early. This also takes care of numbers of the
146 // forms 0.xxx and 0exxx by not allowing the first 0 to be
147 // interpreted as an octal.
148 index++;
149 if (index < len) {
150 int d = GetChar(s, index) - '0';
151 if (d < 0 || d > 7) return false;
152 } else {
153 return false;
154 }
155
156 // Traverse all digits (including the first). If there is an octal
157 // prefix which is not a part of a longer decimal prefix, we return
158 // true. Otherwise, false is returned.
159 while (index < len) {
160 int d = GetChar(s, index++) - '0';
161 if (d == 8 || d == 9) return false;
162 if (d < 0 || d > 7) return true;
163 }
164 return true;
165}
166
167
168extern "C" double gay_strtod(const char* s00, const char** se);
169
170
171// Parse an int from a string starting a given index and in a given
172// radix. The string can be either a char* or a String*.
173template <class S>
174static int InternalStringToInt(S* s, int i, int radix, double* value) {
175 int len = GetLength(s);
176
177 // Setup limits for computing the value.
178 ASSERT(2 <= radix && radix <= 36);
179 int lim_0 = '0' + (radix < 10 ? radix : 10);
180 int lim_a = 'a' + (radix - 10);
181 int lim_A = 'A' + (radix - 10);
182
183 // NOTE: The code for computing the value may seem a bit complex at
184 // first glance. It is structured to use 32-bit multiply-and-add
185 // loops as long as possible to avoid loosing precision.
186
187 double v = 0.0;
188 int j;
189 for (j = i; j < len;) {
190 // Parse the longest part of the string starting at index j
191 // possible while keeping the multiplier, and thus the part
192 // itself, within 32 bits.
193 uint32_t part = 0, multiplier = 1;
194 int k;
195 for (k = j; k < len; k++) {
196 int c = GetChar(s, k);
197 if (c >= '0' && c < lim_0) {
198 c = c - '0';
199 } else if (c >= 'a' && c < lim_a) {
200 c = c - 'a' + 10;
201 } else if (c >= 'A' && c < lim_A) {
202 c = c - 'A' + 10;
203 } else {
204 break;
205 }
206
207 // Update the value of the part as long as the multiplier fits
208 // in 32 bits. When we can't guarantee that the next iteration
209 // will not overflow the multiplier, we stop parsing the part
210 // by leaving the loop.
211 static const uint32_t kMaximumMultiplier = 0xffffffffU / 36;
212 uint32_t m = multiplier * radix;
213 if (m > kMaximumMultiplier) break;
214 part = part * radix + c;
215 multiplier = m;
216 ASSERT(multiplier > part);
217 }
218
219 // Compute the number of part digits. If no digits were parsed;
220 // we're done parsing the entire string.
221 int digits = k - j;
222 if (digits == 0) break;
223
224 // Update the value and skip the part in the string.
225 ASSERT(multiplier ==
226 pow(static_cast<double>(radix), static_cast<double>(digits)));
227 v = v * multiplier + part;
228 j = k;
229 }
230
231 // If the resulting value is larger than 2^53 the value does not fit
232 // in the mantissa of the double and there is a loss of precision.
233 // When the value is larger than 2^53 the rounding depends on the
234 // code generation. If the code generator spills the double value
235 // it uses 64 bits and if it does not it uses 80 bits.
236 //
237 // If there is a potential for overflow we resort to strtod for
238 // radix 10 numbers to get higher precision. For numbers in another
239 // radix we live with the loss of precision.
240 static const double kPreciseConversionLimit = 9007199254740992.0;
241 if (radix == 10 && v > kPreciseConversionLimit) {
242 const char* cstr = GetCString(s, i);
243 const char* end;
244 v = gay_strtod(cstr, &end);
245 ReleaseCString(s, cstr);
246 }
247
248 *value = v;
249 return j;
250}
251
252
253int StringToInt(String* str, int index, int radix, double* value) {
254 return InternalStringToInt(str, index, radix, value);
255}
256
257
258int StringToInt(const char* str, int index, int radix, double* value) {
259 return InternalStringToInt(const_cast<char*>(str), index, radix, value);
260}
261
262
263static const double JUNK_STRING_VALUE = OS::nan_value();
264
265
266// Convert a string to a double value. The string can be either a
267// char* or a String*.
268template<class S>
269static double InternalStringToDouble(S* str,
270 int flags,
271 double empty_string_val) {
272 double result = 0.0;
273 int index = 0;
274
275 int len = GetLength(str);
276
277 // Skip leading spaces.
278 while ((index < len) && IsSpace(str, index)) index++;
279
kasperl@chromium.orgb9123622008-09-17 14:05:56 +0000280 // Is the string empty?
281 if (index >= len) return empty_string_val;
282
283 // Get the first character.
284 uint16_t first = GetChar(str, index);
285
286 // Numbers can only start with '-', '+', '.', 'I' (Infinity), or a digit.
287 if (first != '-' && first != '+' && first != '.' && first != 'I' &&
288 (first > '9' || first < '0')) {
289 return JUNK_STRING_VALUE;
290 }
291
292 // Compute sign of result based on first character.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000293 int sign = 1;
kasperl@chromium.orgb9123622008-09-17 14:05:56 +0000294 if (first == '-') {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000295 sign = -1;
296 index++;
297 // String only containing a '-' are junk chars.
298 if (index == len) return JUNK_STRING_VALUE;
299 }
300
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000301 // do we have a hex number?
302 // (since the string is 0-terminated, it's ok to look one char beyond the end)
303 if ((flags & ALLOW_HEX) != 0 &&
304 (index + 1) < len &&
305 GetChar(str, index) == '0' &&
306 (GetChar(str, index + 1) == 'x' || GetChar(str, index + 1) == 'X')) {
307 index += 2;
308 index = StringToInt(str, index, 16, &result);
309 } else if ((flags & ALLOW_OCTALS) != 0 && ShouldParseOctal(str, index)) {
310 // NOTE: We optimistically try to parse the number as an octal (if
311 // we're allowed to), even though this is not as dictated by
312 // ECMA-262. The reason for doing this is compatibility with IE and
313 // Firefox.
314 index = StringToInt(str, index, 8, &result);
315 } else {
316 const char* cstr = GetCString(str, index);
317 const char* end;
318 // Optimistically parse the number and then, if that fails,
319 // check if it might have been {+,-,}Infinity.
320 result = gay_strtod(cstr, &end);
321 ReleaseCString(str, cstr);
322 if (result != 0.0 || end != cstr) {
323 // It appears that strtod worked
324 index += end - cstr;
325 } else {
326 // Check for {+,-,}Infinity
327 bool is_negative = (GetChar(str, index) == '-');
328 if (GetChar(str, index) == '+' || GetChar(str, index) == '-')
329 index++;
330 if (!SubStringEquals(str, index, "Infinity"))
331 return JUNK_STRING_VALUE;
332 result = is_negative ? -INFINITY : INFINITY;
333 index += 8;
334 }
335 }
336
337 if ((flags & ALLOW_TRAILING_JUNK) == 0) {
338 // skip trailing spaces
339 while ((index < len) && IsSpace(str, index)) index++;
340 // string ending with junk?
341 if (index < len) return JUNK_STRING_VALUE;
342 }
343
344 return sign * result;
345}
346
347
348double StringToDouble(String* str, int flags, double empty_string_val) {
349 return InternalStringToDouble(str, flags, empty_string_val);
350}
351
352
353double StringToDouble(const char* str, int flags, double empty_string_val) {
354 return InternalStringToDouble(str, flags, empty_string_val);
355}
356
357
358extern "C" char* dtoa(double d, int mode, int ndigits,
359 int* decpt, int* sign, char** rve);
360
361extern "C" void freedtoa(char* s);
362
363const char* DoubleToCString(double v, Vector<char> buffer) {
364 StringBuilder builder(buffer.start(), buffer.length());
365
366 switch (fpclassify(v)) {
367 case FP_NAN:
368 builder.AddString("NaN");
369 break;
370
371 case FP_INFINITE:
372 if (v < 0.0) {
373 builder.AddString("-Infinity");
374 } else {
375 builder.AddString("Infinity");
376 }
377 break;
378
379 case FP_ZERO:
380 builder.AddCharacter('0');
381 break;
382
383 default: {
384 int decimal_point;
385 int sign;
386
387 char* decimal_rep = dtoa(v, 0, 0, &decimal_point, &sign, NULL);
388 int length = strlen(decimal_rep);
389
390 if (sign) builder.AddCharacter('-');
391
392 if (length <= decimal_point && decimal_point <= 21) {
393 // ECMA-262 section 9.8.1 step 6.
394 builder.AddString(decimal_rep);
395 builder.AddPadding('0', decimal_point - length);
396
397 } else if (0 < decimal_point && decimal_point <= 21) {
398 // ECMA-262 section 9.8.1 step 7.
399 builder.AddSubstring(decimal_rep, decimal_point);
400 builder.AddCharacter('.');
401 builder.AddString(decimal_rep + decimal_point);
402
403 } else if (decimal_point <= 0 && decimal_point > -6) {
404 // ECMA-262 section 9.8.1 step 8.
405 builder.AddString("0.");
406 builder.AddPadding('0', -decimal_point);
407 builder.AddString(decimal_rep);
408
409 } else {
410 // ECMA-262 section 9.8.1 step 9 and 10 combined.
411 builder.AddCharacter(decimal_rep[0]);
412 if (length != 1) {
413 builder.AddCharacter('.');
414 builder.AddString(decimal_rep + 1);
415 }
416 builder.AddCharacter('e');
417 builder.AddCharacter((decimal_point >= 0) ? '+' : '-');
418 int exponent = decimal_point - 1;
419 if (exponent < 0) exponent = -exponent;
420 builder.AddFormatted("%d", exponent);
421 }
422
423 freedtoa(decimal_rep);
424 }
425 }
426 return builder.Finalize();
427}
428
429
430const char* IntToCString(int n, Vector<char> buffer) {
431 bool negative = false;
432 if (n < 0) {
433 // We must not negate the most negative int.
434 if (n == kMinInt) return DoubleToCString(n, buffer);
435 negative = true;
436 n = -n;
437 }
438 // Build the string backwards from the least significant digit.
439 int i = buffer.length();
440 buffer[--i] = '\0';
441 do {
442 buffer[--i] = '0' + (n % 10);
443 n /= 10;
444 } while (n);
445 if (negative) buffer[--i] = '-';
446 return buffer.start() + i;
447}
448
449
450char* DoubleToFixedCString(double value, int f) {
451 ASSERT(f >= 0);
452
453 bool negative = false;
454 double abs_value = value;
455 if (value < 0) {
456 abs_value = -value;
457 negative = true;
458 }
459
460 if (abs_value >= 1e21) {
461 char arr[100];
462 Vector<char> buffer(arr, ARRAY_SIZE(arr));
463 return StrDup(DoubleToCString(value, buffer));
464 }
465
466 // Find a sufficiently precise decimal representation of n.
467 int decimal_point;
468 int sign;
469 char* decimal_rep = dtoa(abs_value, 3, f, &decimal_point, &sign, NULL);
470 int decimal_rep_length = strlen(decimal_rep);
471
472 // Create a representation that is padded with zeros if needed.
473 int zero_prefix_length = 0;
474 int zero_postfix_length = 0;
475
476 if (decimal_point <= 0) {
477 zero_prefix_length = -decimal_point + 1;
478 decimal_point = 1;
479 }
480
481 if (zero_prefix_length + decimal_rep_length < decimal_point + f) {
482 zero_postfix_length = decimal_point + f - decimal_rep_length -
483 zero_prefix_length;
484 }
485
486 unsigned rep_length =
487 zero_prefix_length + decimal_rep_length + zero_postfix_length;
488 StringBuilder rep_builder(rep_length + 1);
489 rep_builder.AddPadding('0', zero_prefix_length);
490 rep_builder.AddString(decimal_rep);
491 rep_builder.AddPadding('0', zero_postfix_length);
492 char* rep = rep_builder.Finalize();
493 freedtoa(decimal_rep);
494
495 // Create the result string by appending a minus and putting in a
496 // decimal point if needed.
497 unsigned result_size = decimal_point + f + 2;
498 StringBuilder builder(result_size + 1);
499 if (negative) builder.AddCharacter('-');
500 builder.AddSubstring(rep, decimal_point);
501 if (f > 0) {
502 builder.AddCharacter('.');
503 builder.AddSubstring(rep + decimal_point, f);
504 }
505 DeleteArray(rep);
506 return builder.Finalize();
507}
508
509
510static char* CreateExponentialRepresentation(char* decimal_rep,
511 int exponent,
512 bool negative,
513 int significant_digits) {
514 bool negative_exponent = false;
515 if (exponent < 0) {
516 negative_exponent = true;
517 exponent = -exponent;
518 }
519
520 // Leave room in the result for appending a minus, for a period, the
521 // letter 'e', a minus or a plus depending on the exponent, and a
522 // three digit exponent.
523 unsigned result_size = significant_digits + 7;
524 StringBuilder builder(result_size + 1);
525
526 if (negative) builder.AddCharacter('-');
527 builder.AddCharacter(decimal_rep[0]);
528 if (significant_digits != 1) {
529 builder.AddCharacter('.');
530 builder.AddString(decimal_rep + 1);
531 builder.AddPadding('0', significant_digits - strlen(decimal_rep));
532 }
533
534 builder.AddCharacter('e');
535 builder.AddCharacter(negative_exponent ? '-' : '+');
536 builder.AddFormatted("%d", exponent);
537 return builder.Finalize();
538}
539
540
541
542char* DoubleToExponentialCString(double value, int f) {
543 // f might be -1 to signal that f was undefined in JavaScript.
544 ASSERT(f >= -1 && f <= 20);
545
546 bool negative = false;
547 if (value < 0) {
548 value = -value;
549 negative = true;
550 }
551
552 // Find a sufficiently precise decimal representation of n.
553 int decimal_point;
554 int sign;
555 char* decimal_rep = NULL;
556 if (f == -1) {
557 decimal_rep = dtoa(value, 0, 0, &decimal_point, &sign, NULL);
558 f = strlen(decimal_rep) - 1;
559 } else {
560 decimal_rep = dtoa(value, 2, f + 1, &decimal_point, &sign, NULL);
561 }
562 int decimal_rep_length = strlen(decimal_rep);
563 ASSERT(decimal_rep_length > 0);
564 ASSERT(decimal_rep_length <= f + 1);
565 USE(decimal_rep_length);
566
567 int exponent = decimal_point - 1;
568 char* result =
569 CreateExponentialRepresentation(decimal_rep, exponent, negative, f+1);
570
571 freedtoa(decimal_rep);
572
573 return result;
574}
575
576
577char* DoubleToPrecisionCString(double value, int p) {
578 ASSERT(p >= 1 && p <= 21);
579
580 bool negative = false;
581 if (value < 0) {
582 value = -value;
583 negative = true;
584 }
585
586 // Find a sufficiently precise decimal representation of n.
587 int decimal_point;
588 int sign;
589 char* decimal_rep = dtoa(value, 2, p, &decimal_point, &sign, NULL);
590 int decimal_rep_length = strlen(decimal_rep);
591 ASSERT(decimal_rep_length <= p);
592
593 int exponent = decimal_point - 1;
594
595 char* result = NULL;
596
597 if (exponent < -6 || exponent >= p) {
598 result =
599 CreateExponentialRepresentation(decimal_rep, exponent, negative, p);
600 } else {
601 // Use fixed notation.
602 //
603 // Leave room in the result for appending a minus, a period and in
604 // the case where decimal_point is not positive for a zero in
605 // front of the period.
606 unsigned result_size = (decimal_point <= 0)
607 ? -decimal_point + p + 3
608 : p + 2;
609 StringBuilder builder(result_size + 1);
610 if (negative) builder.AddCharacter('-');
611 if (decimal_point <= 0) {
612 builder.AddString("0.");
613 builder.AddPadding('0', -decimal_point);
614 builder.AddString(decimal_rep);
615 builder.AddPadding('0', p - decimal_rep_length);
616 } else {
617 const int m = Min(decimal_rep_length, decimal_point);
618 builder.AddSubstring(decimal_rep, m);
619 builder.AddPadding('0', decimal_point - decimal_rep_length);
620 if (decimal_point < p) {
621 builder.AddCharacter('.');
622 const int extra = negative ? 2 : 1;
623 if (decimal_rep_length > decimal_point) {
624 const int len = strlen(decimal_rep + decimal_point);
625 const int n = Min(len, p - (builder.position() - extra));
626 builder.AddSubstring(decimal_rep + decimal_point, n);
627 }
628 builder.AddPadding('0', extra + (p - builder.position()));
629 }
630 }
631 result = builder.Finalize();
632 }
633
634 freedtoa(decimal_rep);
635 return result;
636}
637
638
639char* DoubleToRadixCString(double value, int radix) {
640 ASSERT(radix >= 2 && radix <= 36);
641
642 // Character array used for conversion.
643 static const char chars[] = "0123456789abcdefghijklmnopqrstuvwxyz";
644
645 // Buffer for the integer part of the result. 1024 chars is enough
646 // for max integer value in radix 2. We need room for a sign too.
647 static const int kBufferSize = 1100;
648 char integer_buffer[kBufferSize];
649 integer_buffer[kBufferSize - 1] = '\0';
650
651 // Buffer for the decimal part of the result. We only generate up
652 // to kBufferSize - 1 chars for the decimal part.
653 char decimal_buffer[kBufferSize];
654 decimal_buffer[kBufferSize - 1] = '\0';
655
656 // Make sure the value is positive.
657 bool is_negative = value < 0.0;
658 if (is_negative) value = -value;
659
660 // Get the integer part and the decimal part.
661 double integer_part = floor(value);
662 double decimal_part = value - integer_part;
663
664 // Convert the integer part starting from the back. Always generate
665 // at least one digit.
666 int integer_pos = kBufferSize - 2;
667 do {
668 integer_buffer[integer_pos--] =
669 chars[static_cast<int>(fmod(integer_part, radix))];
670 integer_part /= radix;
671 } while (integer_part >= 1.0);
672 // Sanity check.
673 ASSERT(integer_pos > 0);
674 // Add sign if needed.
675 if (is_negative) integer_buffer[integer_pos--] = '-';
676
677 // Convert the decimal part. Repeatedly multiply by the radix to
678 // generate the next char. Never generate more than kBufferSize - 1
679 // chars.
680 //
681 // TODO(1093998): We will often generate a full decimal_buffer of
682 // chars because hitting zero will often not happen. The right
683 // solution would be to continue until the string representation can
684 // be read back and yield the original value. To implement this
685 // efficiently, we probably have to modify dtoa.
686 int decimal_pos = 0;
687 while ((decimal_part > 0.0) && (decimal_pos < kBufferSize - 1)) {
688 decimal_part *= radix;
689 decimal_buffer[decimal_pos++] =
690 chars[static_cast<int>(floor(decimal_part))];
691 decimal_part -= floor(decimal_part);
692 }
693 decimal_buffer[decimal_pos] = '\0';
694
695 // Compute the result size.
696 int integer_part_size = kBufferSize - 2 - integer_pos;
697 // Make room for zero termination.
698 unsigned result_size = integer_part_size + decimal_pos;
699 // If the number has a decimal part, leave room for the period.
700 if (decimal_pos > 0) result_size++;
701 // Allocate result and fill in the parts.
702 StringBuilder builder(result_size + 1);
703 builder.AddSubstring(integer_buffer + integer_pos + 1, integer_part_size);
704 if (decimal_pos > 0) builder.AddCharacter('.');
705 builder.AddSubstring(decimal_buffer, decimal_pos);
706 return builder.Finalize();
707}
708
709
710} } // namespace v8::internal