The data contained in this repository can be downloaded to your computer using one of several clients.
Please see the documentation of your version control software client for more information.

Please select the desired protocol below to get the URL.

This URL has Read-Only access.

Statistics
| Branch: | Revision:

main_repo / deps / v8 / src / conversions.cc @ f230a1cf

History | View | Annotate | Download (15.2 KB)

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.
40
using std::fpclassify;
41
#endif
42

    
43
namespace v8 {
44
namespace internal {
45

    
46

    
47
double 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

    
58
double 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

    
71
double 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

    
81
const 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

    
136
const 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

    
156
char* 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

    
227
static 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

    
260
char* 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

    
305
char* 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

    
375
char* 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
    integer_buffer[integer_pos--] =
405
        chars[static_cast<int>(fmod(integer_part, radix))];
406
    integer_part /= radix;
407
  } while (integer_part >= 1.0);
408
  // Sanity check.
409
  ASSERT(integer_pos > 0);
410
  // Add sign if needed.
411
  if (is_negative) integer_buffer[integer_pos--] = '-';
412

    
413
  // Convert the decimal part.  Repeatedly multiply by the radix to
414
  // generate the next char.  Never generate more than kBufferSize - 1
415
  // chars.
416
  //
417
  // TODO(1093998): We will often generate a full decimal_buffer of
418
  // chars because hitting zero will often not happen.  The right
419
  // solution would be to continue until the string representation can
420
  // be read back and yield the original value.  To implement this
421
  // efficiently, we probably have to modify dtoa.
422
  int decimal_pos = 0;
423
  while ((decimal_part > 0.0) && (decimal_pos < kBufferSize - 1)) {
424
    decimal_part *= radix;
425
    decimal_buffer[decimal_pos++] =
426
        chars[static_cast<int>(floor(decimal_part))];
427
    decimal_part -= floor(decimal_part);
428
  }
429
  decimal_buffer[decimal_pos] = '\0';
430

    
431
  // Compute the result size.
432
  int integer_part_size = kBufferSize - 2 - integer_pos;
433
  // Make room for zero termination.
434
  unsigned result_size = integer_part_size + decimal_pos;
435
  // If the number has a decimal part, leave room for the period.
436
  if (decimal_pos > 0) result_size++;
437
  // Allocate result and fill in the parts.
438
  SimpleStringBuilder builder(result_size + 1);
439
  builder.AddSubstring(integer_buffer + integer_pos + 1, integer_part_size);
440
  if (decimal_pos > 0) builder.AddCharacter('.');
441
  builder.AddSubstring(decimal_buffer, decimal_pos);
442
  return builder.Finalize();
443
}
444

    
445
} }  // namespace v8::internal