Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(428)

Side by Side Diff: src/conversions.cc

Issue 2520363002: Reimplement Number.prototype.toString with non-default radix. (Closed)
Patch Set: readd copyright headers Created 4 years ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 // Copyright 2011 the V8 project authors. All rights reserved. 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 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "src/conversions.h" 5 #include "src/conversions.h"
6 6
7 #include <limits.h> 7 #include <limits.h>
8 #include <stdarg.h> 8 #include <stdarg.h>
9 #include <cmath> 9 #include <cmath>
10 10
11 #include "src/allocation.h"
11 #include "src/assert-scope.h" 12 #include "src/assert-scope.h"
12 #include "src/char-predicates-inl.h" 13 #include "src/char-predicates-inl.h"
13 #include "src/codegen.h" 14 #include "src/codegen.h"
14 #include "src/conversions-inl.h" 15 #include "src/conversions-inl.h"
15 #include "src/dtoa.h" 16 #include "src/dtoa.h"
16 #include "src/factory.h" 17 #include "src/factory.h"
17 #include "src/list-inl.h" 18 #include "src/list-inl.h"
18 #include "src/strtod.h" 19 #include "src/strtod.h"
19 #include "src/utils.h" 20 #include "src/utils.h"
20 21
(...skipping 140 matching lines...) Expand 10 before | Expand all | Expand 10 after
161 if (length != 1) { 162 if (length != 1) {
162 builder.AddCharacter('.'); 163 builder.AddCharacter('.');
163 builder.AddString(decimal_rep + 1); 164 builder.AddString(decimal_rep + 1);
164 } 165 }
165 builder.AddCharacter('e'); 166 builder.AddCharacter('e');
166 builder.AddCharacter((decimal_point >= 0) ? '+' : '-'); 167 builder.AddCharacter((decimal_point >= 0) ? '+' : '-');
167 int exponent = decimal_point - 1; 168 int exponent = decimal_point - 1;
168 if (exponent < 0) exponent = -exponent; 169 if (exponent < 0) exponent = -exponent;
169 builder.AddDecimalInteger(exponent); 170 builder.AddDecimalInteger(exponent);
170 } 171 }
171 return builder.Finalize(); 172 return builder.Finalize();
172 } 173 }
173 } 174 }
174 } 175 }
175 176
176 177
177 const char* IntToCString(int n, Vector<char> buffer) { 178 const char* IntToCString(int n, Vector<char> buffer) {
178 bool negative = false; 179 bool negative = false;
179 if (n < 0) { 180 if (n < 0) {
180 // We must not negate the most negative int. 181 // We must not negate the most negative int.
181 if (n == kMinInt) return DoubleToCString(n, buffer); 182 if (n == kMinInt) return DoubleToCString(n, buffer);
(...skipping 222 matching lines...) Expand 10 before | Expand all | Expand 10 after
404 } 405 }
405 builder.AddPadding('0', extra + (p - builder.position())); 406 builder.AddPadding('0', extra + (p - builder.position()));
406 } 407 }
407 } 408 }
408 result = builder.Finalize(); 409 result = builder.Finalize();
409 } 410 }
410 411
411 return result; 412 return result;
412 } 413 }
413 414
415 char* DoubleToRadixCString(double value, int radix) {
416 DCHECK(radix >= 2 && radix <= 36);
417 DCHECK(std::isfinite(value));
418 DCHECK_NE(0.0, value);
419 // Character array used for conversion.
420 static const char chars[] = "0123456789abcdefghijklmnopqrstuvwxyz";
421
422 // Temporary buffer for the result. We start with the decimal point in the
423 // middle and write to the left for the integer part and to the right for the
424 // fractional part. 1024 characters either way with additional space for sign
425 // and decimal point should be sufficient.
426 static const int kBufferSize = 2100;
427 char buffer[kBufferSize];
428 int integer_cursor = kBufferSize / 2;
429 int fraction_cursor = integer_cursor;
430
431 bool negative = value < 0;
432 if (negative) value = -value;
433
434 // Split the value into an integer part and a fractional part.
435 double integer = std::floor(value);
436 double fraction = value - integer;
437 // We only compute fractional digits up to the input double's precision.
438 double delta = 0.5 * (Double(value).NextDouble() - value);
439 if (fraction > delta) {
440 // Insert decimal point.
441 buffer[fraction_cursor++] = '.';
442 do {
443 // Shift up by one digit.
444 fraction *= radix;
445 delta *= radix;
446 // Write digit.
447 int digit = static_cast<int>(fraction);
448 buffer[fraction_cursor++] = chars[digit];
449 // Calculate remainder.
450 fraction -= digit;
451 // Round to even.
452 if (fraction > 0.5 || (fraction == 0.5 && (digit & 1))) {
453 if (fraction + delta > 1) {
454 // We need to back trace already written digits in case of carry-over.
455 while (true) {
456 fraction_cursor--;
457 if (fraction_cursor == kBufferSize / 2) {
458 CHECK_EQ('.', buffer[fraction_cursor]);
459 // Carry over to the integer part.
460 integer += 1;
461 break;
462 }
463 char c = buffer[fraction_cursor];
464 // Reconstruct digit.
465 int digit = c > '9' ? (c - 'a' + 10) : (c - '0');
466 if (digit + 1 < radix) {
467 buffer[fraction_cursor++] = chars[digit + 1];
468 break;
469 }
470 }
471 break;
472 }
473 }
474 } while (fraction > delta);
475 }
476
477 // Compute integer digits.
478 do {
479 double multiple = std::floor(integer / radix);
480 int digit = static_cast<int>(integer - multiple * radix);
481 buffer[--integer_cursor] = chars[digit];
482 integer = multiple;
483 } while (integer > 0);
484
485 // Add sign and terminate string.
486 if (negative) buffer[--integer_cursor] = '-';
487 buffer[fraction_cursor++] = '\0';
488 // Allocate new string as return value.
489 char* result = NewArray<char>(fraction_cursor - integer_cursor);
490 memcpy(result, buffer + integer_cursor, fraction_cursor - integer_cursor);
491 return result;
492 }
493
414 494
415 char* DoubleToRadixCString(double value, int radix) {
416 DCHECK(radix >= 2 && radix <= 36);
417
418 // Character array used for conversion.
419 static const char chars[] = "0123456789abcdefghijklmnopqrstuvwxyz";
420
421 // Buffer for the integer part of the result. 1024 chars is enough
422 // for max integer value in radix 2. We need room for a sign too.
423 static const int kBufferSize = 1100;
424 char integer_buffer[kBufferSize];
425 integer_buffer[kBufferSize - 1] = '\0';
426
427 // Buffer for the decimal part of the result. We only generate up
428 // to kBufferSize - 1 chars for the decimal part.
429 char decimal_buffer[kBufferSize];
430 decimal_buffer[kBufferSize - 1] = '\0';
431
432 // Make sure the value is positive.
433 bool is_negative = value < 0.0;
434 if (is_negative) value = -value;
435
436 // Get the integer part and the decimal part.
437 double integer_part = std::floor(value);
438 double decimal_part = value - integer_part;
439
440 // Convert the integer part starting from the back. Always generate
441 // at least one digit.
442 int integer_pos = kBufferSize - 2;
443 do {
444 double remainder = modulo(integer_part, radix);
445 integer_buffer[integer_pos--] = chars[static_cast<int>(remainder)];
446 integer_part -= remainder;
447 integer_part /= radix;
448 } while (integer_part >= 1.0);
449 // Sanity check.
450 DCHECK(integer_pos > 0);
451 // Add sign if needed.
452 if (is_negative) integer_buffer[integer_pos--] = '-';
453
454 // Convert the decimal part. Repeatedly multiply by the radix to
455 // generate the next char. Never generate more than kBufferSize - 1
456 // chars.
457 //
458 // TODO(1093998): We will often generate a full decimal_buffer of
459 // chars because hitting zero will often not happen. The right
460 // solution would be to continue until the string representation can
461 // be read back and yield the original value. To implement this
462 // efficiently, we probably have to modify dtoa.
463 int decimal_pos = 0;
464 while ((decimal_part > 0.0) && (decimal_pos < kBufferSize - 1)) {
465 decimal_part *= radix;
466 decimal_buffer[decimal_pos++] =
467 chars[static_cast<int>(std::floor(decimal_part))];
468 decimal_part -= std::floor(decimal_part);
469 }
470 decimal_buffer[decimal_pos] = '\0';
471
472 // Compute the result size.
473 int integer_part_size = kBufferSize - 2 - integer_pos;
474 // Make room for zero termination.
475 unsigned result_size = integer_part_size + decimal_pos;
476 // If the number has a decimal part, leave room for the period.
477 if (decimal_pos > 0) result_size++;
478 // Allocate result and fill in the parts.
479 SimpleStringBuilder builder(result_size + 1);
480 builder.AddSubstring(integer_buffer + integer_pos + 1, integer_part_size);
481 if (decimal_pos > 0) builder.AddCharacter('.');
482 builder.AddSubstring(decimal_buffer, decimal_pos);
483 return builder.Finalize();
484 }
485
486
487 // ES6 18.2.4 parseFloat(string) 495 // ES6 18.2.4 parseFloat(string)
488 double StringToDouble(UnicodeCache* unicode_cache, Handle<String> string, 496 double StringToDouble(UnicodeCache* unicode_cache, Handle<String> string,
489 int flags, double empty_string_val) { 497 int flags, double empty_string_val) {
490 Handle<String> flattened = String::Flatten(string); 498 Handle<String> flattened = String::Flatten(string);
491 { 499 {
492 DisallowHeapAllocation no_gc; 500 DisallowHeapAllocation no_gc;
493 String::FlatContent flat = flattened->GetFlatContent(); 501 String::FlatContent flat = flattened->GetFlatContent();
494 DCHECK(flat.IsFlat()); 502 DCHECK(flat.IsFlat());
495 if (flat.IsOneByte()) { 503 if (flat.IsOneByte()) {
496 return StringToDouble(unicode_cache, flat.ToOneByteVector(), flags, 504 return StringToDouble(unicode_cache, flat.ToOneByteVector(), flags,
(...skipping 58 matching lines...) Expand 10 before | Expand all | Expand 10 after
555 char reverse_buffer[kBufferSize + 1]; // Result will be /0 terminated. 563 char reverse_buffer[kBufferSize + 1]; // Result will be /0 terminated.
556 Vector<char> reverse_vector(reverse_buffer, arraysize(reverse_buffer)); 564 Vector<char> reverse_vector(reverse_buffer, arraysize(reverse_buffer));
557 const char* reverse_string = DoubleToCString(d, reverse_vector); 565 const char* reverse_string = DoubleToCString(d, reverse_vector);
558 for (int i = 0; i < length; ++i) { 566 for (int i = 0; i < length; ++i) {
559 if (static_cast<uint16_t>(reverse_string[i]) != buffer[i]) return false; 567 if (static_cast<uint16_t>(reverse_string[i]) != buffer[i]) return false;
560 } 568 }
561 return true; 569 return true;
562 } 570 }
563 } // namespace internal 571 } // namespace internal
564 } // namespace v8 572 } // namespace v8
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698