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