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