663f4e8dec254c4126142dc2b5e628e5a8aad97c
[platform/upstream/nodejs.git] / deps / v8 / src / conversions.cc
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.
22 using std::fpclassify;
23 #endif
24
25 namespace v8 {
26 namespace internal {
27
28
29 namespace {
30
31 // C++-style iterator adaptor for StringCharacterStream
32 // (unlike C++ iterators the end-marker has different type).
33 class 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
51 StringCharacterStreamIterator::StringCharacterStreamIterator(
52     StringCharacterStream* stream) : stream_(stream) {
53   ++(*this);
54 }
55
56 uint16_t StringCharacterStreamIterator::operator*() const {
57   return current_;
58 }
59
60
61 void StringCharacterStreamIterator::operator++() {
62   end_ = !stream_->HasMore();
63   if (!end_) {
64     current_ = stream_->GetNext();
65   }
66 }
67 }  // End anonymous namespace.
68
69
70 double 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
81 double 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
94 double 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.
105 double 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
113 double 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
121 const 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
176 const 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
196 char* 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
267 static 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
299 char* 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
344 char* 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
414 char* 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
486 double StringToDouble(UnicodeCache* unicode_cache, Handle<String> string,
487                       int flags, double empty_string_val) {
488   Handle<String> flattened = String::Flatten(string);
489   {
490     DisallowHeapAllocation no_gc;
491     String::FlatContent flat = flattened->GetFlatContent();
492     DCHECK(flat.IsFlat());
493     // ECMA-262 section 15.1.2.3, empty string is NaN
494     if (flat.IsOneByte()) {
495       return StringToDouble(unicode_cache, flat.ToOneByteVector(), flags,
496                             empty_string_val);
497     } else {
498       return StringToDouble(unicode_cache, flat.ToUC16Vector(), flags,
499                             empty_string_val);
500     }
501   }
502 }
503
504
505 } }  // namespace v8::internal