1// Copyright 2011 the V8 project authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include <limits.h>
6#include <stdarg.h>
7#include <cmath>
8
9#include "src/v8.h"
10
11#include "src/assert-scope.h"
12#include "src/conversions-inl.h"
13#include "src/conversions.h"
14#include "src/dtoa.h"
15#include "src/factory.h"
16#include "src/list-inl.h"
17#include "src/strtod.h"
18#include "src/utils.h"
19
20#ifndef _STLP_VENDOR_CSTD
21// STLPort doesn't import fpclassify into the std namespace.
22using std::fpclassify;
23#endif
24
25namespace v8 {
26namespace internal {
27
28
29namespace {
30
31// C++-style iterator adaptor for StringCharacterStream
32// (unlike C++ iterators the end-marker has different type).
33class StringCharacterStreamIterator {
34 public:
35  class EndMarker {};
36
37  explicit StringCharacterStreamIterator(StringCharacterStream* stream);
38
39  uint16_t operator*() const;
40  void operator++();
41  bool operator==(EndMarker const&) const { return end_; }
42  bool operator!=(EndMarker const& m) const { return !end_; }
43
44 private:
45  StringCharacterStream* const stream_;
46  uint16_t current_;
47  bool end_;
48};
49
50
51StringCharacterStreamIterator::StringCharacterStreamIterator(
52    StringCharacterStream* stream) : stream_(stream) {
53  ++(*this);
54}
55
56uint16_t StringCharacterStreamIterator::operator*() const {
57  return current_;
58}
59
60
61void StringCharacterStreamIterator::operator++() {
62  end_ = !stream_->HasMore();
63  if (!end_) {
64    current_ = stream_->GetNext();
65  }
66}
67}  // End anonymous namespace.
68
69
70double StringToDouble(UnicodeCache* unicode_cache,
71                      const char* str, int flags, double empty_string_val) {
72  // We cast to const uint8_t* here to avoid instantiating the
73  // InternalStringToDouble() template for const char* as well.
74  const uint8_t* start = reinterpret_cast<const uint8_t*>(str);
75  const uint8_t* end = start + StrLength(str);
76  return InternalStringToDouble(unicode_cache, start, end, flags,
77                                empty_string_val);
78}
79
80
81double StringToDouble(UnicodeCache* unicode_cache,
82                      Vector<const uint8_t> str,
83                      int flags,
84                      double empty_string_val) {
85  // We cast to const uint8_t* here to avoid instantiating the
86  // InternalStringToDouble() template for const char* as well.
87  const uint8_t* start = reinterpret_cast<const uint8_t*>(str.start());
88  const uint8_t* end = start + str.length();
89  return InternalStringToDouble(unicode_cache, start, end, flags,
90                                empty_string_val);
91}
92
93
94double StringToDouble(UnicodeCache* unicode_cache,
95                      Vector<const uc16> str,
96                      int flags,
97                      double empty_string_val) {
98  const uc16* end = str.start() + str.length();
99  return InternalStringToDouble(unicode_cache, str.start(), end, flags,
100                                empty_string_val);
101}
102
103
104// Converts a string into an integer.
105double StringToInt(UnicodeCache* unicode_cache,
106                   Vector<const uint8_t> vector,
107                   int radix) {
108  return InternalStringToInt(
109      unicode_cache, vector.start(), vector.start() + vector.length(), radix);
110}
111
112
113double StringToInt(UnicodeCache* unicode_cache,
114                   Vector<const uc16> vector,
115                   int radix) {
116  return InternalStringToInt(
117      unicode_cache, vector.start(), vector.start() + vector.length(), radix);
118}
119
120
121const char* DoubleToCString(double v, Vector<char> buffer) {
122  switch (fpclassify(v)) {
123    case FP_NAN: return "NaN";
124    case FP_INFINITE: return (v < 0.0 ? "-Infinity" : "Infinity");
125    case FP_ZERO: return "0";
126    default: {
127      SimpleStringBuilder builder(buffer.start(), buffer.length());
128      int decimal_point;
129      int sign;
130      const int kV8DtoaBufferCapacity = kBase10MaximalLength + 1;
131      char decimal_rep[kV8DtoaBufferCapacity];
132      int length;
133
134      DoubleToAscii(v, DTOA_SHORTEST, 0,
135                    Vector<char>(decimal_rep, kV8DtoaBufferCapacity),
136                    &sign, &length, &decimal_point);
137
138      if (sign) builder.AddCharacter('-');
139
140      if (length <= decimal_point && decimal_point <= 21) {
141        // ECMA-262 section 9.8.1 step 6.
142        builder.AddString(decimal_rep);
143        builder.AddPadding('0', decimal_point - length);
144
145      } else if (0 < decimal_point && decimal_point <= 21) {
146        // ECMA-262 section 9.8.1 step 7.
147        builder.AddSubstring(decimal_rep, decimal_point);
148        builder.AddCharacter('.');
149        builder.AddString(decimal_rep + decimal_point);
150
151      } else if (decimal_point <= 0 && decimal_point > -6) {
152        // ECMA-262 section 9.8.1 step 8.
153        builder.AddString("0.");
154        builder.AddPadding('0', -decimal_point);
155        builder.AddString(decimal_rep);
156
157      } else {
158        // ECMA-262 section 9.8.1 step 9 and 10 combined.
159        builder.AddCharacter(decimal_rep[0]);
160        if (length != 1) {
161          builder.AddCharacter('.');
162          builder.AddString(decimal_rep + 1);
163        }
164        builder.AddCharacter('e');
165        builder.AddCharacter((decimal_point >= 0) ? '+' : '-');
166        int exponent = decimal_point - 1;
167        if (exponent < 0) exponent = -exponent;
168        builder.AddDecimalInteger(exponent);
169      }
170    return builder.Finalize();
171    }
172  }
173}
174
175
176const char* IntToCString(int n, Vector<char> buffer) {
177  bool negative = false;
178  if (n < 0) {
179    // We must not negate the most negative int.
180    if (n == kMinInt) return DoubleToCString(n, buffer);
181    negative = true;
182    n = -n;
183  }
184  // Build the string backwards from the least significant digit.
185  int i = buffer.length();
186  buffer[--i] = '\0';
187  do {
188    buffer[--i] = '0' + (n % 10);
189    n /= 10;
190  } while (n);
191  if (negative) buffer[--i] = '-';
192  return buffer.start() + i;
193}
194
195
196char* DoubleToFixedCString(double value, int f) {
197  const int kMaxDigitsBeforePoint = 21;
198  const double kFirstNonFixed = 1e21;
199  const int kMaxDigitsAfterPoint = 20;
200  DCHECK(f >= 0);
201  DCHECK(f <= kMaxDigitsAfterPoint);
202
203  bool negative = false;
204  double abs_value = value;
205  if (value < 0) {
206    abs_value = -value;
207    negative = true;
208  }
209
210  // If abs_value has more than kMaxDigitsBeforePoint digits before the point
211  // use the non-fixed conversion routine.
212  if (abs_value >= kFirstNonFixed) {
213    char arr[100];
214    Vector<char> buffer(arr, arraysize(arr));
215    return StrDup(DoubleToCString(value, buffer));
216  }
217
218  // Find a sufficiently precise decimal representation of n.
219  int decimal_point;
220  int sign;
221  // Add space for the '\0' byte.
222  const int kDecimalRepCapacity =
223      kMaxDigitsBeforePoint + kMaxDigitsAfterPoint + 1;
224  char decimal_rep[kDecimalRepCapacity];
225  int decimal_rep_length;
226  DoubleToAscii(value, DTOA_FIXED, f,
227                Vector<char>(decimal_rep, kDecimalRepCapacity),
228                &sign, &decimal_rep_length, &decimal_point);
229
230  // Create a representation that is padded with zeros if needed.
231  int zero_prefix_length = 0;
232  int zero_postfix_length = 0;
233
234  if (decimal_point <= 0) {
235    zero_prefix_length = -decimal_point + 1;
236    decimal_point = 1;
237  }
238
239  if (zero_prefix_length + decimal_rep_length < decimal_point + f) {
240    zero_postfix_length = decimal_point + f - decimal_rep_length -
241                          zero_prefix_length;
242  }
243
244  unsigned rep_length =
245      zero_prefix_length + decimal_rep_length + zero_postfix_length;
246  SimpleStringBuilder rep_builder(rep_length + 1);
247  rep_builder.AddPadding('0', zero_prefix_length);
248  rep_builder.AddString(decimal_rep);
249  rep_builder.AddPadding('0', zero_postfix_length);
250  char* rep = rep_builder.Finalize();
251
252  // Create the result string by appending a minus and putting in a
253  // decimal point if needed.
254  unsigned result_size = decimal_point + f + 2;
255  SimpleStringBuilder builder(result_size + 1);
256  if (negative) builder.AddCharacter('-');
257  builder.AddSubstring(rep, decimal_point);
258  if (f > 0) {
259    builder.AddCharacter('.');
260    builder.AddSubstring(rep + decimal_point, f);
261  }
262  DeleteArray(rep);
263  return builder.Finalize();
264}
265
266
267static char* CreateExponentialRepresentation(char* decimal_rep,
268                                             int exponent,
269                                             bool negative,
270                                             int significant_digits) {
271  bool negative_exponent = false;
272  if (exponent < 0) {
273    negative_exponent = true;
274    exponent = -exponent;
275  }
276
277  // Leave room in the result for appending a minus, for a period, the
278  // letter 'e', a minus or a plus depending on the exponent, and a
279  // three digit exponent.
280  unsigned result_size = significant_digits + 7;
281  SimpleStringBuilder builder(result_size + 1);
282
283  if (negative) builder.AddCharacter('-');
284  builder.AddCharacter(decimal_rep[0]);
285  if (significant_digits != 1) {
286    builder.AddCharacter('.');
287    builder.AddString(decimal_rep + 1);
288    int rep_length = StrLength(decimal_rep);
289    builder.AddPadding('0', significant_digits - rep_length);
290  }
291
292  builder.AddCharacter('e');
293  builder.AddCharacter(negative_exponent ? '-' : '+');
294  builder.AddDecimalInteger(exponent);
295  return builder.Finalize();
296}
297
298
299char* DoubleToExponentialCString(double value, int f) {
300  const int kMaxDigitsAfterPoint = 20;
301  // f might be -1 to signal that f was undefined in JavaScript.
302  DCHECK(f >= -1 && f <= kMaxDigitsAfterPoint);
303
304  bool negative = false;
305  if (value < 0) {
306    value = -value;
307    negative = true;
308  }
309
310  // Find a sufficiently precise decimal representation of n.
311  int decimal_point;
312  int sign;
313  // f corresponds to the digits after the point. There is always one digit
314  // before the point. The number of requested_digits equals hence f + 1.
315  // And we have to add one character for the null-terminator.
316  const int kV8DtoaBufferCapacity = kMaxDigitsAfterPoint + 1 + 1;
317  // Make sure that the buffer is big enough, even if we fall back to the
318  // shortest representation (which happens when f equals -1).
319  DCHECK(kBase10MaximalLength <= kMaxDigitsAfterPoint + 1);
320  char decimal_rep[kV8DtoaBufferCapacity];
321  int decimal_rep_length;
322
323  if (f == -1) {
324    DoubleToAscii(value, DTOA_SHORTEST, 0,
325                  Vector<char>(decimal_rep, kV8DtoaBufferCapacity),
326                  &sign, &decimal_rep_length, &decimal_point);
327    f = decimal_rep_length - 1;
328  } else {
329    DoubleToAscii(value, DTOA_PRECISION, f + 1,
330                  Vector<char>(decimal_rep, kV8DtoaBufferCapacity),
331                  &sign, &decimal_rep_length, &decimal_point);
332  }
333  DCHECK(decimal_rep_length > 0);
334  DCHECK(decimal_rep_length <= f + 1);
335
336  int exponent = decimal_point - 1;
337  char* result =
338      CreateExponentialRepresentation(decimal_rep, exponent, negative, f+1);
339
340  return result;
341}
342
343
344char* DoubleToPrecisionCString(double value, int p) {
345  const int kMinimalDigits = 1;
346  const int kMaximalDigits = 21;
347  DCHECK(p >= kMinimalDigits && p <= kMaximalDigits);
348  USE(kMinimalDigits);
349
350  bool negative = false;
351  if (value < 0) {
352    value = -value;
353    negative = true;
354  }
355
356  // Find a sufficiently precise decimal representation of n.
357  int decimal_point;
358  int sign;
359  // Add one for the terminating null character.
360  const int kV8DtoaBufferCapacity = kMaximalDigits + 1;
361  char decimal_rep[kV8DtoaBufferCapacity];
362  int decimal_rep_length;
363
364  DoubleToAscii(value, DTOA_PRECISION, p,
365                Vector<char>(decimal_rep, kV8DtoaBufferCapacity),
366                &sign, &decimal_rep_length, &decimal_point);
367  DCHECK(decimal_rep_length <= p);
368
369  int exponent = decimal_point - 1;
370
371  char* result = NULL;
372
373  if (exponent < -6 || exponent >= p) {
374    result =
375        CreateExponentialRepresentation(decimal_rep, exponent, negative, p);
376  } else {
377    // Use fixed notation.
378    //
379    // Leave room in the result for appending a minus, a period and in
380    // the case where decimal_point is not positive for a zero in
381    // front of the period.
382    unsigned result_size = (decimal_point <= 0)
383        ? -decimal_point + p + 3
384        : p + 2;
385    SimpleStringBuilder builder(result_size + 1);
386    if (negative) builder.AddCharacter('-');
387    if (decimal_point <= 0) {
388      builder.AddString("0.");
389      builder.AddPadding('0', -decimal_point);
390      builder.AddString(decimal_rep);
391      builder.AddPadding('0', p - decimal_rep_length);
392    } else {
393      const int m = Min(decimal_rep_length, decimal_point);
394      builder.AddSubstring(decimal_rep, m);
395      builder.AddPadding('0', decimal_point - decimal_rep_length);
396      if (decimal_point < p) {
397        builder.AddCharacter('.');
398        const int extra = negative ? 2 : 1;
399        if (decimal_rep_length > decimal_point) {
400          const int len = StrLength(decimal_rep + decimal_point);
401          const int n = Min(len, p - (builder.position() - extra));
402          builder.AddSubstring(decimal_rep + decimal_point, n);
403        }
404        builder.AddPadding('0', extra + (p - builder.position()));
405      }
406    }
407    result = builder.Finalize();
408  }
409
410  return result;
411}
412
413
414char* DoubleToRadixCString(double value, int radix) {
415  DCHECK(radix >= 2 && radix <= 36);
416
417  // Character array used for conversion.
418  static const char chars[] = "0123456789abcdefghijklmnopqrstuvwxyz";
419
420  // Buffer for the integer part of the result. 1024 chars is enough
421  // for max integer value in radix 2.  We need room for a sign too.
422  static const int kBufferSize = 1100;
423  char integer_buffer[kBufferSize];
424  integer_buffer[kBufferSize - 1] = '\0';
425
426  // Buffer for the decimal part of the result.  We only generate up
427  // to kBufferSize - 1 chars for the decimal part.
428  char decimal_buffer[kBufferSize];
429  decimal_buffer[kBufferSize - 1] = '\0';
430
431  // Make sure the value is positive.
432  bool is_negative = value < 0.0;
433  if (is_negative) value = -value;
434
435  // Get the integer part and the decimal part.
436  double integer_part = std::floor(value);
437  double decimal_part = value - integer_part;
438
439  // Convert the integer part starting from the back.  Always generate
440  // at least one digit.
441  int integer_pos = kBufferSize - 2;
442  do {
443    double remainder = std::fmod(integer_part, radix);
444    integer_buffer[integer_pos--] = chars[static_cast<int>(remainder)];
445    integer_part -= remainder;
446    integer_part /= radix;
447  } while (integer_part >= 1.0);
448  // Sanity check.
449  DCHECK(integer_pos > 0);
450  // Add sign if needed.
451  if (is_negative) integer_buffer[integer_pos--] = '-';
452
453  // Convert the decimal part.  Repeatedly multiply by the radix to
454  // generate the next char.  Never generate more than kBufferSize - 1
455  // chars.
456  //
457  // TODO(1093998): We will often generate a full decimal_buffer of
458  // chars because hitting zero will often not happen.  The right
459  // solution would be to continue until the string representation can
460  // be read back and yield the original value.  To implement this
461  // efficiently, we probably have to modify dtoa.
462  int decimal_pos = 0;
463  while ((decimal_part > 0.0) && (decimal_pos < kBufferSize - 1)) {
464    decimal_part *= radix;
465    decimal_buffer[decimal_pos++] =
466        chars[static_cast<int>(std::floor(decimal_part))];
467    decimal_part -= std::floor(decimal_part);
468  }
469  decimal_buffer[decimal_pos] = '\0';
470
471  // Compute the result size.
472  int integer_part_size = kBufferSize - 2 - integer_pos;
473  // Make room for zero termination.
474  unsigned result_size = integer_part_size + decimal_pos;
475  // If the number has a decimal part, leave room for the period.
476  if (decimal_pos > 0) result_size++;
477  // Allocate result and fill in the parts.
478  SimpleStringBuilder builder(result_size + 1);
479  builder.AddSubstring(integer_buffer + integer_pos + 1, integer_part_size);
480  if (decimal_pos > 0) builder.AddCharacter('.');
481  builder.AddSubstring(decimal_buffer, decimal_pos);
482  return builder.Finalize();
483}
484
485
486double StringToDouble(UnicodeCache* unicode_cache,
487                      String* string,
488                      int flags,
489                      double empty_string_val) {
490  DisallowHeapAllocation no_gc;
491  String::FlatContent flat = string->GetFlatContent();
492  // ECMA-262 section 15.1.2.3, empty string is NaN
493  if (flat.IsOneByte()) {
494    return StringToDouble(
495        unicode_cache, flat.ToOneByteVector(), flags, empty_string_val);
496  } else {
497    return StringToDouble(
498        unicode_cache, flat.ToUC16Vector(), flags, empty_string_val);
499  }
500}
501
502
503} }  // namespace v8::internal
504