[bigint] Implement .toString for power-of-2 radixes

Other radixes require Divide/Remainder to be implemented first.

Bug: v8:6791
Change-Id: I95f1fad39a0a4df556a194094805ed93bd46d0db
Reviewed-on: https://chromium-review.googlesource.com/664037
Commit-Queue: Jakob Kummerow <jkummerow@chromium.org>
Reviewed-by: Georg Neis <neis@chromium.org>
Cr-Commit-Position: refs/heads/master@{#48020}
This commit is contained in:
Jakob Kummerow 2017-09-14 13:51:31 -07:00 committed by Commit Bot
parent 0202a040c9
commit a12f05e8fc
2 changed files with 55 additions and 8 deletions

View File

@ -81,14 +81,9 @@ Handle<BigInt> BigInt::BitwiseOr(Handle<BigInt> x, Handle<BigInt> y) {
}
Handle<String> BigInt::ToString(Handle<BigInt> bigint, int radix) {
// TODO(jkummerow): Implement this properly.
Factory* factory = bigint->GetIsolate()->factory();
if (bigint->is_zero()) return factory->NewStringFromStaticChars("0");
DCHECK(bigint->length() == 1);
int value = static_cast<uint32_t>(bigint->digit(0));
if (bigint->sign()) value = -value; // This can overflow. We don't care.
Handle<Object> number = factory->NewNumberFromInt(value);
return factory->NumberToString(number);
// TODO(jkummerow): Support non-power-of-two radixes.
if (!base::bits::IsPowerOfTwo(radix)) radix = 16;
return bigint->ToStringBasePowerOfTwo(bigint, radix);
}
void BigInt::Initialize(int length, bool zero_initialize) {
@ -107,6 +102,55 @@ void BigInt::Initialize(int length, bool zero_initialize) {
}
}
// Private helpers for public methods.
static const char kConversionChars[] = "0123456789abcdefghijklmnopqrstuvwxyz";
// TODO(jkummerow): Add more tests for this when it is exposed on
// BigInt.prototype.
Handle<String> BigInt::ToStringBasePowerOfTwo(Handle<BigInt> x, int radix) {
STATIC_ASSERT(base::bits::IsPowerOfTwo(kDigitBits));
DCHECK(base::bits::IsPowerOfTwo(radix));
DCHECK(radix >= 2 && radix <= 32);
Factory* factory = x->GetIsolate()->factory();
// TODO(jkummerow): check in caller?
if (is_zero()) return factory->NewStringFromStaticChars("0");
const int len = x->length();
const bool sign = x->sign();
const int bits_per_char = base::bits::CountTrailingZeros32(radix);
const int char_mask = radix - 1;
const int chars_per_digit = kDigitBits / bits_per_char;
// Compute the number of chars needed to represent the most significant
// bigint digit.
int chars_for_msd = 0;
for (digit_t msd = x->digit(len - 1); msd != 0; msd >>= bits_per_char) {
chars_for_msd++;
}
// All other digits need chars_per_digit characters; a leading "-" needs one.
const int chars = chars_for_msd + (len - 1) * chars_per_digit + sign;
Handle<SeqOneByteString> result =
factory->NewRawOneByteString(chars).ToHandleChecked();
uint8_t* buffer = result->GetChars();
// Print the number into the string, starting from the last position.
int pos = chars - 1;
for (int i = 0; i < len - 1; i++) {
digit_t digit = x->digit(i);
for (int j = 0; j < chars_per_digit; j++) {
buffer[pos--] = kConversionChars[digit & char_mask];
digit >>= bits_per_char;
}
}
// Print the most significant digit.
for (digit_t msd = x->digit(len - 1); msd != 0; msd >>= bits_per_char) {
buffer[pos--] = kConversionChars[msd & char_mask];
}
if (sign) buffer[pos--] = '-';
DCHECK(pos == -1);
return result;
}
#ifdef OBJECT_PRINT
void BigInt::BigIntPrint(std::ostream& os) {
DisallowHeapAllocation no_gc;

View File

@ -88,6 +88,9 @@ class BigInt : public HeapObject {
static const int kHalfDigitBits = kDigitBits / 2;
static const digit_t kHalfDigitMask = (1ull << kHalfDigitBits) - 1;
// Private helpers for public methods.
Handle<String> ToStringBasePowerOfTwo(Handle<BigInt> x, int radix);
class LengthBits : public BitField<int, 0, kMaxLengthBits> {};
class SignBits : public BitField<bool, LengthBits::kNext, 1> {};