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

Side by Side Diff: src/conversions.cc

Issue 2520363002: Reimplement Number.prototype.toString with non-default radix. (Closed)
Patch Set: Created 4 years, 1 month 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 225 matching lines...) Expand 10 before | Expand all | Expand 10 after
407 } 408 }
408 result = builder.Finalize(); 409 result = builder.Finalize();
409 } 410 }
410 411
411 return result; 412 return result;
412 } 413 }
413 414
414 415
415 char* DoubleToRadixCString(double value, int radix) { 416 char* DoubleToRadixCString(double value, int radix) {
416 DCHECK(radix >= 2 && radix <= 36); 417 DCHECK(radix >= 2 && radix <= 36);
418 DCHECK(std::isfinite(value));
419 DCHECK_NE(0.0, value);
417 420
418 // Character array used for conversion. 421 // Character array used for conversion.
419 static const char chars[] = "0123456789abcdefghijklmnopqrstuvwxyz"; 422 static const char chars[] = "0123456789abcdefghijklmnopqrstuvwxyz";
420 423
421 // Buffer for the integer part of the result. 1024 chars is enough 424 // 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. 425 // for max integer value in radix 2. We need room for a sign too.
423 static const int kBufferSize = 1100; 426 static const int kBufferSize = 1100;
424 char integer_buffer[kBufferSize]; 427 char buffer[kBufferSize];
425 integer_buffer[kBufferSize - 1] = '\0'; 428 int cursor = kBufferSize;
429 buffer[--cursor] = '\0';
430 bool negative = value < 0;
431 if (negative) value = -value;
426 432
427 // Buffer for the decimal part of the result. We only generate up 433 // Shift the number by power of the radix until we can represent it
428 // to kBufferSize - 1 chars for the decimal part. 434 // in its full precision as an uint64_t.
429 char decimal_buffer[kBufferSize]; 435 int decimal_point_shift = 0;
430 decimal_buffer[kBufferSize - 1] = '\0'; 436 if (Double(value).Exponent() < 0) {
437 while (Double(value).Exponent() < 0) {
438 value *= radix;
439 decimal_point_shift--;
440 }
441 } else {
442 while (Double(value / radix).Exponent() > 0) {
443 value /= radix;
444 // Insert trailing zeros.
445 buffer[--cursor] = '0';
446 }
447 }
431 448
432 // Make sure the value is positive. 449 // Construct string from right to left (least significant to most).
433 bool is_negative = value < 0.0; 450 uint64_t int_value = static_cast<uint64_t>(value);
Tobias Tebbi 2016/11/22 18:46:54 (2/7).toString(3) gives "0.02120102120102120102120
434 if (is_negative) value = -value; 451 while (decimal_point_shift < 0) {
452 uint64_t multiple = int_value / radix;
453 uint64_t remainder = int_value - multiple * radix;
454 // Skip trailing zeros after the decimal point.
455 if (remainder > 0) {
456 // Compute digits up to decimal point.
457 while (decimal_point_shift < 0) {
458 uint64_t multiple = int_value / radix;
459 uint64_t remainder = int_value - multiple * radix;
460 buffer[--cursor] = chars[remainder];
461 int_value = multiple;
462 decimal_point_shift++;
463 }
464 // Insert decimal point if there have been fractional digits.
465 if (decimal_point_shift == 0) buffer[--cursor] = '.';
466 break;
467 }
468 int_value = multiple;
469 decimal_point_shift++;
470 }
471 // Compute integer digits.
472 do {
473 uint64_t multiple = int_value / radix;
474 uint64_t remainder = int_value - multiple * radix;
475 buffer[--cursor] = chars[remainder];
476 int_value = multiple;
477 } while (int_value > 0);
435 478
436 // Get the integer part and the decimal part. 479 if (negative) buffer[--cursor] = '-';
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. 480 // Allocate result and fill in the parts.
479 SimpleStringBuilder builder(result_size + 1); 481 char* result = NewArray<char>(kBufferSize - cursor);
480 builder.AddSubstring(integer_buffer + integer_pos + 1, integer_part_size); 482 memcpy(result, buffer + cursor, kBufferSize - cursor);
481 if (decimal_pos > 0) builder.AddCharacter('.'); 483 return result;
482 builder.AddSubstring(decimal_buffer, decimal_pos);
483 return builder.Finalize();
484 } 484 }
485 485
486 486
487 // ES6 18.2.4 parseFloat(string) 487 // ES6 18.2.4 parseFloat(string)
488 double StringToDouble(UnicodeCache* unicode_cache, Handle<String> string, 488 double StringToDouble(UnicodeCache* unicode_cache, Handle<String> string,
489 int flags, double empty_string_val) { 489 int flags, double empty_string_val) {
490 Handle<String> flattened = String::Flatten(string); 490 Handle<String> flattened = String::Flatten(string);
491 { 491 {
492 DisallowHeapAllocation no_gc; 492 DisallowHeapAllocation no_gc;
493 String::FlatContent flat = flattened->GetFlatContent(); 493 String::FlatContent flat = flattened->GetFlatContent();
(...skipping 61 matching lines...) Expand 10 before | Expand all | Expand 10 after
555 char reverse_buffer[kBufferSize + 1]; // Result will be /0 terminated. 555 char reverse_buffer[kBufferSize + 1]; // Result will be /0 terminated.
556 Vector<char> reverse_vector(reverse_buffer, arraysize(reverse_buffer)); 556 Vector<char> reverse_vector(reverse_buffer, arraysize(reverse_buffer));
557 const char* reverse_string = DoubleToCString(d, reverse_vector); 557 const char* reverse_string = DoubleToCString(d, reverse_vector);
558 for (int i = 0; i < length; ++i) { 558 for (int i = 0; i < length; ++i) {
559 if (static_cast<uint16_t>(reverse_string[i]) != buffer[i]) return false; 559 if (static_cast<uint16_t>(reverse_string[i]) != buffer[i]) return false;
560 } 560 }
561 return true; 561 return true;
562 } 562 }
563 } // namespace internal 563 } // namespace internal
564 } // namespace v8 564 } // namespace v8
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698