18b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch// Copyright 2011 the V8 project authors. All rights reserved.
2b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch// Use of this source code is governed by a BSD-style license that can be
3b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch// found in the LICENSE file.
4a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
5014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch#include "src/conversions.h"
6014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
76ded16be15dd865a9b21ea304d5273c8be299c87Steve Block#include <limits.h>
8b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch#include <stdarg.h>
9b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch#include <cmath>
10b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
11b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch#include "src/assert-scope.h"
12014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch#include "src/char-predicates-inl.h"
13014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch#include "src/codegen.h"
14b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch#include "src/conversions-inl.h"
15b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch#include "src/dtoa.h"
16b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch#include "src/factory.h"
17b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch#include "src/list-inl.h"
18b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch#include "src/strtod.h"
19b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch#include "src/utils.h"
20b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
21b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch#ifndef _STLP_VENDOR_CSTD
22b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch// STLPort doesn't import fpclassify into the std namespace.
23b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdochusing std::fpclassify;
24b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch#endif
25a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
26a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blocknamespace v8 {
27a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blocknamespace internal {
28a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
29a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
30b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdochnamespace {
31b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
32b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch// C++-style iterator adaptor for StringCharacterStream
33b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch// (unlike C++ iterators the end-marker has different type).
34b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdochclass StringCharacterStreamIterator {
35b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch public:
36b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  class EndMarker {};
37b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
38b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  explicit StringCharacterStreamIterator(StringCharacterStream* stream);
39b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
40b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  uint16_t operator*() const;
41b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  void operator++();
42b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  bool operator==(EndMarker const&) const { return end_; }
43b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  bool operator!=(EndMarker const& m) const { return !end_; }
44b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
45b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch private:
46b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  StringCharacterStream* const stream_;
47b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  uint16_t current_;
48b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  bool end_;
49b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch};
50b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
51b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
52b8a8cc1952d61a2f3a2568848933943a543b5d3eBen MurdochStringCharacterStreamIterator::StringCharacterStreamIterator(
53b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    StringCharacterStream* stream) : stream_(stream) {
54b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  ++(*this);
55b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch}
56b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
57b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdochuint16_t StringCharacterStreamIterator::operator*() const {
58b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  return current_;
59b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch}
60b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
61b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
62b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdochvoid StringCharacterStreamIterator::operator++() {
63b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  end_ = !stream_->HasMore();
64b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  if (!end_) {
65b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    current_ = stream_->GetNext();
66b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  }
67b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch}
68b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch}  // End anonymous namespace.
69b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
70b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
718b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdochdouble StringToDouble(UnicodeCache* unicode_cache,
728b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch                      const char* str, int flags, double empty_string_val) {
73b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  // We cast to const uint8_t* here to avoid instantiating the
74b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  // InternalStringToDouble() template for const char* as well.
75b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  const uint8_t* start = reinterpret_cast<const uint8_t*>(str);
76b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  const uint8_t* end = start + StrLength(str);
77b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  return InternalStringToDouble(unicode_cache, start, end, flags,
7844f0eee88ff00398ff7f715fab053374d808c90dSteve Block                                empty_string_val);
79a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
80a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
81a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
828b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdochdouble StringToDouble(UnicodeCache* unicode_cache,
83b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch                      Vector<const uint8_t> str,
8480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen                      int flags,
8580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen                      double empty_string_val) {
86b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  // We cast to const uint8_t* here to avoid instantiating the
87b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  // InternalStringToDouble() template for const char* as well.
88b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  const uint8_t* start = reinterpret_cast<const uint8_t*>(str.start());
89b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  const uint8_t* end = start + str.length();
90b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  return InternalStringToDouble(unicode_cache, start, end, flags,
9144f0eee88ff00398ff7f715fab053374d808c90dSteve Block                                empty_string_val);
9280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen}
9380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
94b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
95257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdochdouble StringToDouble(UnicodeCache* unicode_cache,
96257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch                      Vector<const uc16> str,
97257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch                      int flags,
98257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch                      double empty_string_val) {
99257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  const uc16* end = str.start() + str.length();
100257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  return InternalStringToDouble(unicode_cache, str.start(), end, flags,
101257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch                                empty_string_val);
102257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch}
103257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
10480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
105b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch// Converts a string into an integer.
106b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdochdouble StringToInt(UnicodeCache* unicode_cache,
107b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch                   Vector<const uint8_t> vector,
108b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch                   int radix) {
109b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  return InternalStringToInt(
110b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch      unicode_cache, vector.start(), vector.start() + vector.length(), radix);
111b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch}
112b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
113b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
114b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdochdouble StringToInt(UnicodeCache* unicode_cache,
115b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch                   Vector<const uc16> vector,
116b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch                   int radix) {
117b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  return InternalStringToInt(
118b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch      unicode_cache, vector.start(), vector.start() + vector.length(), radix);
119b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch}
120b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
121b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
122a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockconst char* DoubleToCString(double v, Vector<char> buffer) {
123a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  switch (fpclassify(v)) {
1241e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block    case FP_NAN: return "NaN";
1251e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block    case FP_INFINITE: return (v < 0.0 ? "-Infinity" : "Infinity");
1261e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block    case FP_ZERO: return "0";
127a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    default: {
1283fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch      SimpleStringBuilder builder(buffer.start(), buffer.length());
129a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      int decimal_point;
130a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      int sign;
13125f6136652d8341ed047e7fc1a450af5bd218ea9Kristian Monsen      const int kV8DtoaBufferCapacity = kBase10MaximalLength + 1;
1328a31eba00023874d4a1dcdc5f411cc4336776874Shimeng (Simon) Wang      char decimal_rep[kV8DtoaBufferCapacity];
1336ded16be15dd865a9b21ea304d5273c8be299c87Steve Block      int length;
13425f6136652d8341ed047e7fc1a450af5bd218ea9Kristian Monsen
1358a31eba00023874d4a1dcdc5f411cc4336776874Shimeng (Simon) Wang      DoubleToAscii(v, DTOA_SHORTEST, 0,
1368a31eba00023874d4a1dcdc5f411cc4336776874Shimeng (Simon) Wang                    Vector<char>(decimal_rep, kV8DtoaBufferCapacity),
1378a31eba00023874d4a1dcdc5f411cc4336776874Shimeng (Simon) Wang                    &sign, &length, &decimal_point);
138a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
139a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      if (sign) builder.AddCharacter('-');
140a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
141a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      if (length <= decimal_point && decimal_point <= 21) {
142a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        // ECMA-262 section 9.8.1 step 6.
143a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        builder.AddString(decimal_rep);
144a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        builder.AddPadding('0', decimal_point - length);
145a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
146a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      } else if (0 < decimal_point && decimal_point <= 21) {
147a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        // ECMA-262 section 9.8.1 step 7.
148a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        builder.AddSubstring(decimal_rep, decimal_point);
149a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        builder.AddCharacter('.');
150a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        builder.AddString(decimal_rep + decimal_point);
151a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
152a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      } else if (decimal_point <= 0 && decimal_point > -6) {
153a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        // ECMA-262 section 9.8.1 step 8.
154a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        builder.AddString("0.");
155a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        builder.AddPadding('0', -decimal_point);
156a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        builder.AddString(decimal_rep);
157a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
158a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      } else {
159a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        // ECMA-262 section 9.8.1 step 9 and 10 combined.
160a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        builder.AddCharacter(decimal_rep[0]);
161a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        if (length != 1) {
162a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block          builder.AddCharacter('.');
163a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block          builder.AddString(decimal_rep + 1);
164a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        }
165a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        builder.AddCharacter('e');
166a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        builder.AddCharacter((decimal_point >= 0) ? '+' : '-');
167a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        int exponent = decimal_point - 1;
168a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        if (exponent < 0) exponent = -exponent;
1693fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch        builder.AddDecimalInteger(exponent);
170a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      }
1711e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block    return builder.Finalize();
172a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    }
173a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  }
174a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
175a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
176a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
177a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockconst char* IntToCString(int n, Vector<char> buffer) {
178a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  bool negative = false;
179a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  if (n < 0) {
180a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    // We must not negate the most negative int.
181a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    if (n == kMinInt) return DoubleToCString(n, buffer);
182a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    negative = true;
183a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    n = -n;
184a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  }
185a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Build the string backwards from the least significant digit.
186a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  int i = buffer.length();
187a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  buffer[--i] = '\0';
188a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  do {
189a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    buffer[--i] = '0' + (n % 10);
190a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    n /= 10;
191a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  } while (n);
192a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  if (negative) buffer[--i] = '-';
193a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  return buffer.start() + i;
194a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
195a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
196a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
197a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockchar* DoubleToFixedCString(double value, int f) {
1983e5fa29ddb82551500b118e9bf37af3966277b70Teng-Hui Zhu  const int kMaxDigitsBeforePoint = 21;
19925f6136652d8341ed047e7fc1a450af5bd218ea9Kristian Monsen  const double kFirstNonFixed = 1e21;
20025f6136652d8341ed047e7fc1a450af5bd218ea9Kristian Monsen  const int kMaxDigitsAfterPoint = 20;
201b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  DCHECK(f >= 0);
202b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  DCHECK(f <= kMaxDigitsAfterPoint);
203a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
204a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  bool negative = false;
205a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  double abs_value = value;
206a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  if (value < 0) {
207a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    abs_value = -value;
208a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    negative = true;
209a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  }
210a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
21125f6136652d8341ed047e7fc1a450af5bd218ea9Kristian Monsen  // If abs_value has more than kMaxDigitsBeforePoint digits before the point
21225f6136652d8341ed047e7fc1a450af5bd218ea9Kristian Monsen  // use the non-fixed conversion routine.
21325f6136652d8341ed047e7fc1a450af5bd218ea9Kristian Monsen  if (abs_value >= kFirstNonFixed) {
214a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    char arr[100];
215b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    Vector<char> buffer(arr, arraysize(arr));
216a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    return StrDup(DoubleToCString(value, buffer));
217a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  }
218a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
219a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Find a sufficiently precise decimal representation of n.
220a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  int decimal_point;
221a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  int sign;
2223e5fa29ddb82551500b118e9bf37af3966277b70Teng-Hui Zhu  // Add space for the '\0' byte.
22325f6136652d8341ed047e7fc1a450af5bd218ea9Kristian Monsen  const int kDecimalRepCapacity =
2243e5fa29ddb82551500b118e9bf37af3966277b70Teng-Hui Zhu      kMaxDigitsBeforePoint + kMaxDigitsAfterPoint + 1;
22525f6136652d8341ed047e7fc1a450af5bd218ea9Kristian Monsen  char decimal_rep[kDecimalRepCapacity];
22625f6136652d8341ed047e7fc1a450af5bd218ea9Kristian Monsen  int decimal_rep_length;
2278a31eba00023874d4a1dcdc5f411cc4336776874Shimeng (Simon) Wang  DoubleToAscii(value, DTOA_FIXED, f,
2288a31eba00023874d4a1dcdc5f411cc4336776874Shimeng (Simon) Wang                Vector<char>(decimal_rep, kDecimalRepCapacity),
2298a31eba00023874d4a1dcdc5f411cc4336776874Shimeng (Simon) Wang                &sign, &decimal_rep_length, &decimal_point);
230a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
231a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Create a representation that is padded with zeros if needed.
232a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  int zero_prefix_length = 0;
233a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  int zero_postfix_length = 0;
234a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
235a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  if (decimal_point <= 0) {
236a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    zero_prefix_length = -decimal_point + 1;
237a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    decimal_point = 1;
238a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  }
239a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
240a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  if (zero_prefix_length + decimal_rep_length < decimal_point + f) {
241a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    zero_postfix_length = decimal_point + f - decimal_rep_length -
242a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                          zero_prefix_length;
243a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  }
244a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
245a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  unsigned rep_length =
246a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      zero_prefix_length + decimal_rep_length + zero_postfix_length;
2473fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  SimpleStringBuilder rep_builder(rep_length + 1);
248a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  rep_builder.AddPadding('0', zero_prefix_length);
249a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  rep_builder.AddString(decimal_rep);
250a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  rep_builder.AddPadding('0', zero_postfix_length);
251a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  char* rep = rep_builder.Finalize();
252a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
253a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Create the result string by appending a minus and putting in a
254a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // decimal point if needed.
255a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  unsigned result_size = decimal_point + f + 2;
2563fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  SimpleStringBuilder builder(result_size + 1);
257a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  if (negative) builder.AddCharacter('-');
258a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  builder.AddSubstring(rep, decimal_point);
259a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  if (f > 0) {
260a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    builder.AddCharacter('.');
261a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    builder.AddSubstring(rep + decimal_point, f);
262a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  }
263a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  DeleteArray(rep);
264a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  return builder.Finalize();
265a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
266a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
267a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
268a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockstatic char* CreateExponentialRepresentation(char* decimal_rep,
269a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                                             int exponent,
270a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                                             bool negative,
271a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                                             int significant_digits) {
272a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  bool negative_exponent = false;
273a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  if (exponent < 0) {
274a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    negative_exponent = true;
275a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    exponent = -exponent;
276a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  }
277a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
278a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Leave room in the result for appending a minus, for a period, the
279a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // letter 'e', a minus or a plus depending on the exponent, and a
280a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // three digit exponent.
281a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  unsigned result_size = significant_digits + 7;
2823fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  SimpleStringBuilder builder(result_size + 1);
283a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
284a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  if (negative) builder.AddCharacter('-');
285a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  builder.AddCharacter(decimal_rep[0]);
286a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  if (significant_digits != 1) {
287a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    builder.AddCharacter('.');
288a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    builder.AddString(decimal_rep + 1);
289d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block    int rep_length = StrLength(decimal_rep);
290d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block    builder.AddPadding('0', significant_digits - rep_length);
291a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  }
292a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
293a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  builder.AddCharacter('e');
294a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  builder.AddCharacter(negative_exponent ? '-' : '+');
2953fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  builder.AddDecimalInteger(exponent);
296a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  return builder.Finalize();
297a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
298a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
299a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
300a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockchar* DoubleToExponentialCString(double value, int f) {
3010d5e116f6aee03185f237311a943491bb079a768Kristian Monsen  const int kMaxDigitsAfterPoint = 20;
302a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // f might be -1 to signal that f was undefined in JavaScript.
303b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  DCHECK(f >= -1 && f <= kMaxDigitsAfterPoint);
304a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
305a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  bool negative = false;
306a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  if (value < 0) {
307a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    value = -value;
308a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    negative = true;
309a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  }
310a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
311a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Find a sufficiently precise decimal representation of n.
312a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  int decimal_point;
313a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  int sign;
3140d5e116f6aee03185f237311a943491bb079a768Kristian Monsen  // f corresponds to the digits after the point. There is always one digit
3150d5e116f6aee03185f237311a943491bb079a768Kristian Monsen  // before the point. The number of requested_digits equals hence f + 1.
3160d5e116f6aee03185f237311a943491bb079a768Kristian Monsen  // And we have to add one character for the null-terminator.
3170d5e116f6aee03185f237311a943491bb079a768Kristian Monsen  const int kV8DtoaBufferCapacity = kMaxDigitsAfterPoint + 1 + 1;
3180d5e116f6aee03185f237311a943491bb079a768Kristian Monsen  // Make sure that the buffer is big enough, even if we fall back to the
3190d5e116f6aee03185f237311a943491bb079a768Kristian Monsen  // shortest representation (which happens when f equals -1).
320b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  DCHECK(kBase10MaximalLength <= kMaxDigitsAfterPoint + 1);
3218a31eba00023874d4a1dcdc5f411cc4336776874Shimeng (Simon) Wang  char decimal_rep[kV8DtoaBufferCapacity];
3220d5e116f6aee03185f237311a943491bb079a768Kristian Monsen  int decimal_rep_length;
3230d5e116f6aee03185f237311a943491bb079a768Kristian Monsen
324a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  if (f == -1) {
3258a31eba00023874d4a1dcdc5f411cc4336776874Shimeng (Simon) Wang    DoubleToAscii(value, DTOA_SHORTEST, 0,
3268a31eba00023874d4a1dcdc5f411cc4336776874Shimeng (Simon) Wang                  Vector<char>(decimal_rep, kV8DtoaBufferCapacity),
3278a31eba00023874d4a1dcdc5f411cc4336776874Shimeng (Simon) Wang                  &sign, &decimal_rep_length, &decimal_point);
3288a31eba00023874d4a1dcdc5f411cc4336776874Shimeng (Simon) Wang    f = decimal_rep_length - 1;
329a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  } else {
3308a31eba00023874d4a1dcdc5f411cc4336776874Shimeng (Simon) Wang    DoubleToAscii(value, DTOA_PRECISION, f + 1,
3318a31eba00023874d4a1dcdc5f411cc4336776874Shimeng (Simon) Wang                  Vector<char>(decimal_rep, kV8DtoaBufferCapacity),
3328a31eba00023874d4a1dcdc5f411cc4336776874Shimeng (Simon) Wang                  &sign, &decimal_rep_length, &decimal_point);
333a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  }
334b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  DCHECK(decimal_rep_length > 0);
335b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  DCHECK(decimal_rep_length <= f + 1);
336a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
337a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  int exponent = decimal_point - 1;
338a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  char* result =
339a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      CreateExponentialRepresentation(decimal_rep, exponent, negative, f+1);
340a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
341a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  return result;
342a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
343a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
344a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
345a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockchar* DoubleToPrecisionCString(double value, int p) {
3460d5e116f6aee03185f237311a943491bb079a768Kristian Monsen  const int kMinimalDigits = 1;
3470d5e116f6aee03185f237311a943491bb079a768Kristian Monsen  const int kMaximalDigits = 21;
348b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  DCHECK(p >= kMinimalDigits && p <= kMaximalDigits);
3490d5e116f6aee03185f237311a943491bb079a768Kristian Monsen  USE(kMinimalDigits);
350a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
351a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  bool negative = false;
352a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  if (value < 0) {
353a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    value = -value;
354a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    negative = true;
355a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  }
356a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
357a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Find a sufficiently precise decimal representation of n.
358a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  int decimal_point;
359a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  int sign;
3600d5e116f6aee03185f237311a943491bb079a768Kristian Monsen  // Add one for the terminating null character.
3610d5e116f6aee03185f237311a943491bb079a768Kristian Monsen  const int kV8DtoaBufferCapacity = kMaximalDigits + 1;
3628a31eba00023874d4a1dcdc5f411cc4336776874Shimeng (Simon) Wang  char decimal_rep[kV8DtoaBufferCapacity];
3630d5e116f6aee03185f237311a943491bb079a768Kristian Monsen  int decimal_rep_length;
3640d5e116f6aee03185f237311a943491bb079a768Kristian Monsen
3658a31eba00023874d4a1dcdc5f411cc4336776874Shimeng (Simon) Wang  DoubleToAscii(value, DTOA_PRECISION, p,
3668a31eba00023874d4a1dcdc5f411cc4336776874Shimeng (Simon) Wang                Vector<char>(decimal_rep, kV8DtoaBufferCapacity),
3678a31eba00023874d4a1dcdc5f411cc4336776874Shimeng (Simon) Wang                &sign, &decimal_rep_length, &decimal_point);
368b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  DCHECK(decimal_rep_length <= p);
369a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
370a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  int exponent = decimal_point - 1;
371a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
372a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  char* result = NULL;
373a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
374a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  if (exponent < -6 || exponent >= p) {
375a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    result =
376a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        CreateExponentialRepresentation(decimal_rep, exponent, negative, p);
377a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  } else {
378a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    // Use fixed notation.
379a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    //
380a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    // Leave room in the result for appending a minus, a period and in
381a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    // the case where decimal_point is not positive for a zero in
382a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    // front of the period.
383a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    unsigned result_size = (decimal_point <= 0)
384a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        ? -decimal_point + p + 3
385a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        : p + 2;
3863fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch    SimpleStringBuilder builder(result_size + 1);
387a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    if (negative) builder.AddCharacter('-');
388a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    if (decimal_point <= 0) {
389a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      builder.AddString("0.");
390a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      builder.AddPadding('0', -decimal_point);
391a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      builder.AddString(decimal_rep);
392a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      builder.AddPadding('0', p - decimal_rep_length);
393a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    } else {
394a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      const int m = Min(decimal_rep_length, decimal_point);
395a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      builder.AddSubstring(decimal_rep, m);
396a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      builder.AddPadding('0', decimal_point - decimal_rep_length);
397a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      if (decimal_point < p) {
398a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        builder.AddCharacter('.');
399a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        const int extra = negative ? 2 : 1;
400a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        if (decimal_rep_length > decimal_point) {
401d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block          const int len = StrLength(decimal_rep + decimal_point);
402a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block          const int n = Min(len, p - (builder.position() - extra));
403a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block          builder.AddSubstring(decimal_rep + decimal_point, n);
404a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        }
405a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        builder.AddPadding('0', extra + (p - builder.position()));
406a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      }
407a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    }
408a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    result = builder.Finalize();
409a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  }
410a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
411a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  return result;
412a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
413a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
414a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
415a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockchar* DoubleToRadixCString(double value, int radix) {
416b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  DCHECK(radix >= 2 && radix <= 36);
417a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
418a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Character array used for conversion.
419a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  static const char chars[] = "0123456789abcdefghijklmnopqrstuvwxyz";
420a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
421a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Buffer for the integer part of the result. 1024 chars is enough
422a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // for max integer value in radix 2.  We need room for a sign too.
423a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  static const int kBufferSize = 1100;
424a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  char integer_buffer[kBufferSize];
425a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  integer_buffer[kBufferSize - 1] = '\0';
426a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
427a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Buffer for the decimal part of the result.  We only generate up
428a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // to kBufferSize - 1 chars for the decimal part.
429a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  char decimal_buffer[kBufferSize];
430a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  decimal_buffer[kBufferSize - 1] = '\0';
431a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
432a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Make sure the value is positive.
433a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  bool is_negative = value < 0.0;
434a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  if (is_negative) value = -value;
435a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
436a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Get the integer part and the decimal part.
437b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  double integer_part = std::floor(value);
438a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  double decimal_part = value - integer_part;
439a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
440a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Convert the integer part starting from the back.  Always generate
441a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // at least one digit.
442a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  int integer_pos = kBufferSize - 2;
443a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  do {
444014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    double remainder = modulo(integer_part, radix);
445b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    integer_buffer[integer_pos--] = chars[static_cast<int>(remainder)];
446b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    integer_part -= remainder;
447a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    integer_part /= radix;
448a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  } while (integer_part >= 1.0);
449a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Sanity check.
450b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  DCHECK(integer_pos > 0);
451a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Add sign if needed.
452a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  if (is_negative) integer_buffer[integer_pos--] = '-';
453a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
454a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Convert the decimal part.  Repeatedly multiply by the radix to
455a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // generate the next char.  Never generate more than kBufferSize - 1
456a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // chars.
457a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  //
458a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // TODO(1093998): We will often generate a full decimal_buffer of
459a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // chars because hitting zero will often not happen.  The right
460a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // solution would be to continue until the string representation can
461a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // be read back and yield the original value.  To implement this
462a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // efficiently, we probably have to modify dtoa.
463a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  int decimal_pos = 0;
464a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  while ((decimal_part > 0.0) && (decimal_pos < kBufferSize - 1)) {
465a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    decimal_part *= radix;
466a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    decimal_buffer[decimal_pos++] =
467b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch        chars[static_cast<int>(std::floor(decimal_part))];
468b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    decimal_part -= std::floor(decimal_part);
469a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  }
470a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  decimal_buffer[decimal_pos] = '\0';
471a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
472a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Compute the result size.
473a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  int integer_part_size = kBufferSize - 2 - integer_pos;
474a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Make room for zero termination.
475a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  unsigned result_size = integer_part_size + decimal_pos;
476a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // If the number has a decimal part, leave room for the period.
477a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  if (decimal_pos > 0) result_size++;
478a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Allocate result and fill in the parts.
4793fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  SimpleStringBuilder builder(result_size + 1);
480a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  builder.AddSubstring(integer_buffer + integer_pos + 1, integer_part_size);
481a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  if (decimal_pos > 0) builder.AddCharacter('.');
482a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  builder.AddSubstring(decimal_buffer, decimal_pos);
483a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  return builder.Finalize();
484a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
485a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
486b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
487014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch// ES6 18.2.4 parseFloat(string)
488958fae7ec3f466955f8e5b50fa5b8d38b9e91675Emily Bernierdouble StringToDouble(UnicodeCache* unicode_cache, Handle<String> string,
489958fae7ec3f466955f8e5b50fa5b8d38b9e91675Emily Bernier                      int flags, double empty_string_val) {
490958fae7ec3f466955f8e5b50fa5b8d38b9e91675Emily Bernier  Handle<String> flattened = String::Flatten(string);
491958fae7ec3f466955f8e5b50fa5b8d38b9e91675Emily Bernier  {
492958fae7ec3f466955f8e5b50fa5b8d38b9e91675Emily Bernier    DisallowHeapAllocation no_gc;
493958fae7ec3f466955f8e5b50fa5b8d38b9e91675Emily Bernier    String::FlatContent flat = flattened->GetFlatContent();
494958fae7ec3f466955f8e5b50fa5b8d38b9e91675Emily Bernier    DCHECK(flat.IsFlat());
495958fae7ec3f466955f8e5b50fa5b8d38b9e91675Emily Bernier    if (flat.IsOneByte()) {
496958fae7ec3f466955f8e5b50fa5b8d38b9e91675Emily Bernier      return StringToDouble(unicode_cache, flat.ToOneByteVector(), flags,
497958fae7ec3f466955f8e5b50fa5b8d38b9e91675Emily Bernier                            empty_string_val);
498958fae7ec3f466955f8e5b50fa5b8d38b9e91675Emily Bernier    } else {
499958fae7ec3f466955f8e5b50fa5b8d38b9e91675Emily Bernier      return StringToDouble(unicode_cache, flat.ToUC16Vector(), flags,
500958fae7ec3f466955f8e5b50fa5b8d38b9e91675Emily Bernier                            empty_string_val);
501958fae7ec3f466955f8e5b50fa5b8d38b9e91675Emily Bernier    }
502b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  }
503b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch}
504b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
505b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
506014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdochbool IsSpecialIndex(UnicodeCache* unicode_cache, String* string) {
507014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  // Max length of canonical double: -X.XXXXXXXXXXXXXXXXX-eXXX
508014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  const int kBufferSize = 24;
509014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  const int length = string->length();
510014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  if (length == 0 || length > kBufferSize) return false;
511014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  uint16_t buffer[kBufferSize];
512014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  String::WriteToFlat(string, buffer, 0, length);
513014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  // If the first char is not a digit or a '-' or we can't match 'NaN' or
514014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  // '(-)Infinity', bailout immediately.
515014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  int offset = 0;
516014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  if (!IsDecimalDigit(buffer[0])) {
517014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    if (buffer[0] == '-') {
518014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch      if (length == 1) return false;  // Just '-' is bad.
519014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch      if (!IsDecimalDigit(buffer[1])) {
520014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch        if (buffer[1] == 'I' && length == 9) {
521014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch          // Allow matching of '-Infinity' below.
522014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch        } else {
523014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch          return false;
524014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch        }
525014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch      }
526014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch      offset++;
527014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    } else if (buffer[0] == 'I' && length == 8) {
528014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch      // Allow matching of 'Infinity' below.
529014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    } else if (buffer[0] == 'N' && length == 3) {
530014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch      // Match NaN.
531014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch      return buffer[1] == 'a' && buffer[2] == 'N';
532014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    } else {
533014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch      return false;
534014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    }
535014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  }
536014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  // Expected fast path: key is an integer.
537014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  static const int kRepresentableIntegerLength = 15;  // (-)XXXXXXXXXXXXXXX
538014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  if (length - offset <= kRepresentableIntegerLength) {
539014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    const int initial_offset = offset;
540014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    bool matches = true;
541014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    for (; offset < length; offset++) {
542014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch      matches &= IsDecimalDigit(buffer[offset]);
543014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    }
544014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    if (matches) {
545014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch      // Match 0 and -0.
546014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch      if (buffer[initial_offset] == '0') return initial_offset == length - 1;
547014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch      return true;
548014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    }
549014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  }
550014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  // Slow path: test DoubleToString(StringToDouble(string)) == string.
551014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  Vector<const uint16_t> vector(buffer, length);
552014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  double d = StringToDouble(unicode_cache, vector, NO_FLAGS);
553014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  if (std::isnan(d)) return false;
554014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  // Compute reverse string.
555014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  char reverse_buffer[kBufferSize + 1];  // Result will be /0 terminated.
556014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  Vector<char> reverse_vector(reverse_buffer, arraysize(reverse_buffer));
557014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  const char* reverse_string = DoubleToCString(d, reverse_vector);
558014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  for (int i = 0; i < length; ++i) {
559014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    if (static_cast<uint16_t>(reverse_string[i]) != buffer[i]) return false;
560014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  }
561014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  return true;
562014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch}
563014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch}  // namespace internal
564014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch}  // namespace v8
565