Chromium Code Reviews| Index: runtime/vm/bigint_operations.cc |
| diff --git a/runtime/vm/bigint_operations.cc b/runtime/vm/bigint_operations.cc |
| index d46e78513244b24b6067289a067e70dde5a3a93a..d58cad7de6581fe0156478bdb5a111307981f095 100644 |
| --- a/runtime/vm/bigint_operations.cc |
| +++ b/runtime/vm/bigint_operations.cc |
| @@ -336,6 +336,76 @@ const char* BigintOperations::ToHexCString(const Bigint& bigint, |
| } |
| +const char* BigintOperations::ToDecimalCString( |
| + const Bigint& bigint, uword (*allocator)(intptr_t size)) { |
| + intptr_t length = bigint.Length(); |
| + // We guard against overflows by using 64 bit computations. |
|
siva
2012/03/02 19:31:45
On 64 bit machines the signed_length is actually a
floitsch
2012/03/05 14:28:17
Refactored.
|
| + int64_t bit_length = length * kDigitBitSize; |
| + // Approximate the size of the resulting string. We prefer overestimating |
| + // to not allocating enough. |
| + // log10(2) ~= 0.30102999566398114. |
| + int64_t decimal_length = (bit_length * 30103 / 100000) + 1; |
| + // Add one byte for the trailing \0 character. |
| + int64_t required_size = decimal_length + 1; |
| + if (bigint.IsNegative()) { |
| + required_size++; |
| + } |
| + // TODO(floitsch): what to do if we had an overflow? |
| + if (required_size != static_cast<intptr_t>(required_size)) { |
|
siva
2012/03/02 19:31:45
I think we should assert here instead of silently
floitsch
2012/03/05 14:28:17
That's why there was a TODO. Now throwing an OOM-e
|
| + return ""; |
| + } |
| + // We will fill the result in the inverse order and then exchange at the end. |
| + char* result = |
| + reinterpret_cast<char*>(allocator(static_cast<intptr_t>(required_size))); |
|
siva
2012/03/02 19:31:45
ASSERT(result != NULL);
floitsch
2012/03/05 14:28:17
Done.
|
| + int result_pos = 0; |
| + |
| + // We divide the input into pieces of ~27 bits which can be efficiently |
| + // handled. |
| + const intptr_t kDivisorValue = 100000000; |
| + const int kPowerOfTen = 8; |
| + ASSERT(pow(10, kPowerOfTen) == kDivisorValue); |
| + ASSERT(static_cast<Chunk>(kDivisorValue) < kDigitMaxValue); |
| + ASSERT(Smi::IsValid(kDivisorValue)); |
| + const Smi& divisor_smi = Smi::Handle(Smi::New(kDivisorValue)); |
| + const Bigint& divisor = Bigint::Handle(NewFromSmi(divisor_smi)); |
| + |
| + // Rest contains the remaining bigint that needs to be printed. |
| + Bigint& rest = Bigint::Handle(bigint.raw()); |
| + Bigint& quotient = Bigint::Handle(); |
| + Bigint& remainder = Bigint::Handle(); |
| + while (!rest.IsZero()) { |
| + DivideRemainder(rest, divisor, "ient, &remainder); |
| + ASSERT(remainder.Length() == 1); |
| + intptr_t part = static_cast<intptr_t>(remainder.GetChunkAt(0)); |
| + for (int i = 0; i < kPowerOfTen; i++) { |
| + result[result_pos++] = '0' + part % 10; |
|
siva
2012/03/02 19:31:45
'0' + (part % 10);
to make it clear for operator p
floitsch
2012/03/05 14:28:17
Done.
|
| + part /= 10; |
| + } |
| + ASSERT(part == 0); |
| + rest = quotient.raw(); |
| + } |
| + // Move the resulting position back until we don't have any zeroes anymore. |
|
siva
2012/03/02 19:31:45
// This is done so that we can remove all leading
floitsch
2012/03/05 14:28:17
Done.
|
| + while (result_pos > 1 && result[result_pos - 1] == '0') { |
| + result_pos--; |
| + } |
| + if (bigint.IsNegative()) { |
| + result[result_pos++] = '-'; |
| + } |
| + // Reverse the string. |
| + int i = 0; |
| + int j = result_pos - 1; |
| + while (i < j) { |
| + char tmp = result[i]; |
| + result[i] = result[j]; |
| + result[j] = tmp; |
| + i++; |
| + j--; |
| + } |
|
siva
2012/03/02 19:31:45
ASSERt(result_pos >= 0);
floitsch
2012/03/05 14:28:17
Done.
|
| + result[result_pos] = '\0'; |
| + return result; |
| +} |
| + |
| + |
| bool BigintOperations::FitsIntoSmi(const Bigint& bigint) { |
| intptr_t bigint_length = bigint.Length(); |
| if (bigint_length == 0) { |