OLD | NEW |
---|---|
1 // Copyright 2012 Google Inc. All Rights Reserved. | 1 // Copyright 2012 Google Inc. All Rights Reserved. |
2 | 2 |
3 #include "vm/bigint_operations.h" | 3 #include "vm/bigint_operations.h" |
4 | 4 |
5 #include "platform/utils.h" | 5 #include "platform/utils.h" |
6 | 6 |
7 #include "vm/double_internals.h" | 7 #include "vm/double_internals.h" |
8 #include "vm/exceptions.h" | 8 #include "vm/exceptions.h" |
9 #include "vm/object_store.h" | 9 #include "vm/object_store.h" |
10 #include "vm/zone.h" | 10 #include "vm/zone.h" |
(...skipping 101 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
112 ((str[1] == 'x') || (str[1] == 'X'))) { | 112 ((str[1] == 'x') || (str[1] == 'X'))) { |
113 const Bigint& result = Bigint::Handle(FromHexCString(&str[2], space)); | 113 const Bigint& result = Bigint::Handle(FromHexCString(&str[2], space)); |
114 ASSERT(IsClamped(result)); | 114 ASSERT(IsClamped(result)); |
115 return result.raw(); | 115 return result.raw(); |
116 } else { | 116 } else { |
117 return FromDecimalCString(str); | 117 return FromDecimalCString(str); |
118 } | 118 } |
119 } | 119 } |
120 | 120 |
121 | 121 |
122 intptr_t BigintOperations::ComputeLength(const char* hex_string) { | |
123 ASSERT(kDigitBitSize % 4 == 0); | |
124 intptr_t hex_length = strlen(hex_string); | |
125 // Round up. | |
126 intptr_t bigint_length = ((hex_length - 1) / kHexCharsPerDigit) + 1; | |
cshapiro
2012/03/24 01:48:07
Utils::RoundUp ?
siva
2012/03/24 02:25:03
The current Roundup implementation doesn't quite w
| |
127 return bigint_length; | |
128 } | |
129 | |
130 | |
122 RawBigint* BigintOperations::FromHexCString(const char* hex_string, | 131 RawBigint* BigintOperations::FromHexCString(const char* hex_string, |
123 Heap::Space space) { | 132 Heap::Space space) { |
124 // If the string starts with '-' recursively restart the whole operation | 133 // If the string starts with '-' recursively restart the whole operation |
125 // without the character and then toggle the sign. | 134 // without the character and then toggle the sign. |
126 // This allows multiple leading '-' (which will cancel each other out), but | 135 // This allows multiple leading '-' (which will cancel each other out), but |
127 // we have added an assert, to make sure that the returned result of the | 136 // we have added an assert, to make sure that the returned result of the |
128 // recursive call is not negative. | 137 // recursive call is not negative. |
129 // We don't catch leading '-'s for zero. Ex: "--0", or "---". | 138 // We don't catch leading '-'s for zero. Ex: "--0", or "---". |
130 if (hex_string[0] == '-') { | 139 if (hex_string[0] == '-') { |
131 const Bigint& value = Bigint::Handle(FromHexCString(&hex_string[1], space)); | 140 const Bigint& value = Bigint::Handle(FromHexCString(&hex_string[1], space)); |
132 value.ToggleSign(); | 141 value.ToggleSign(); |
133 ASSERT(value.IsZero() || value.IsNegative()); | 142 ASSERT(value.IsZero() || value.IsNegative()); |
134 ASSERT(IsClamped(value)); | 143 ASSERT(IsClamped(value)); |
135 return value.raw(); | 144 return value.raw(); |
136 } | 145 } |
137 | 146 intptr_t bigint_length = ComputeLength(hex_string); |
138 ASSERT(kDigitBitSize % 4 == 0); | 147 const Bigint& result = Bigint::Handle(Bigint::Allocate(bigint_length, space)); |
139 const int kHexCharsPerDigit = kDigitBitSize / 4; | 148 FromHexCString(hex_string, result); |
140 | |
141 intptr_t hex_length = strlen(hex_string); | |
142 // Round up. | |
143 intptr_t bigint_length = ((hex_length - 1) / kHexCharsPerDigit) + 1; | |
144 const Bigint& result = | |
145 Bigint::Handle(Bigint::Allocate(bigint_length, space)); | |
146 // The bigint's least significant digit (lsd) is at position 0, whereas the | |
147 // given string has it's lsd at the last position. | |
148 // The hex_i index, pointing into the string, starts therefore at the end, | |
149 // whereas the bigint-index (i) starts at 0. | |
150 intptr_t hex_i = hex_length - 1; | |
151 for (intptr_t i = 0; i < bigint_length; i++) { | |
152 Chunk digit = 0; | |
153 int shift = 0; | |
154 for (int j = 0; j < kHexCharsPerDigit; j++) { | |
155 // Reads a block of hexadecimal digits and stores it in 'digit'. | |
156 // Ex: "0123456" with kHexCharsPerDigit == 3, hex_i == 6, reads "456". | |
157 if (hex_i < 0) { | |
158 break; | |
159 } | |
160 ASSERT(hex_i >= 0); | |
161 char c = hex_string[hex_i--]; | |
162 ASSERT(Utils::IsHexDigit(c)); | |
163 digit += static_cast<Chunk>(Utils::HexDigitToInt(c)) << shift; | |
164 shift += 4; | |
165 } | |
166 result.SetChunkAt(i, digit); | |
167 } | |
168 ASSERT(hex_i == -1); | |
169 Clamp(result); | |
170 return result.raw(); | 149 return result.raw(); |
171 } | 150 } |
172 | 151 |
173 | 152 |
174 RawBigint* BigintOperations::FromDecimalCString(const char* str, | 153 RawBigint* BigintOperations::FromDecimalCString(const char* str, |
175 Heap::Space space) { | 154 Heap::Space space) { |
176 // Read 8 digits a time. 10^8 < 2^27. | 155 // Read 8 digits a time. 10^8 < 2^27. |
177 const int kDigitsPerIteration = 8; | 156 const int kDigitsPerIteration = 8; |
178 const Chunk kTenMultiplier = 100000000; | 157 const Chunk kTenMultiplier = 100000000; |
179 ASSERT(kDigitBitSize >= 27); | 158 ASSERT(kDigitBitSize >= 27); |
(...skipping 75 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
255 } | 234 } |
256 | 235 |
257 | 236 |
258 const char* BigintOperations::ToHexCString(intptr_t length, | 237 const char* BigintOperations::ToHexCString(intptr_t length, |
259 bool is_negative, | 238 bool is_negative, |
260 void* data, | 239 void* data, |
261 uword (*allocator)(intptr_t size)) { | 240 uword (*allocator)(intptr_t size)) { |
262 NoGCScope no_gc; | 241 NoGCScope no_gc; |
263 | 242 |
264 ASSERT(kDigitBitSize % 4 == 0); | 243 ASSERT(kDigitBitSize % 4 == 0); |
265 const int kHexCharsPerDigit = kDigitBitSize / 4; | |
266 | 244 |
267 intptr_t chunk_length = length; | 245 intptr_t chunk_length = length; |
268 Chunk* chunk_data = reinterpret_cast<Chunk*>(data); | 246 Chunk* chunk_data = reinterpret_cast<Chunk*>(data); |
269 if (length == 0) { | 247 if (length == 0) { |
270 const char* zero = "0x0"; | 248 const char* zero = "0x0"; |
271 const int kLength = strlen(zero); | 249 const int kLength = strlen(zero); |
272 char* result = reinterpret_cast<char*>(allocator(kLength + 1)); | 250 char* result = reinterpret_cast<char*>(allocator(kLength + 1)); |
273 ASSERT(result != NULL); | 251 ASSERT(result != NULL); |
274 memmove(result, zero, kLength); | 252 memmove(result, zero, kLength); |
275 result[kLength] = '\0'; | 253 result[kLength] = '\0'; |
(...skipping 858 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1134 return a_is_negative ? -1 : 1; | 1112 return a_is_negative ? -1 : 1; |
1135 } | 1113 } |
1136 | 1114 |
1137 if (a_is_negative) { | 1115 if (a_is_negative) { |
1138 return -UnsignedCompare(a, b); | 1116 return -UnsignedCompare(a, b); |
1139 } | 1117 } |
1140 return UnsignedCompare(a, b); | 1118 return UnsignedCompare(a, b); |
1141 } | 1119 } |
1142 | 1120 |
1143 | 1121 |
1122 void BigintOperations::FromHexCString(const char* hex_string, | |
1123 const Bigint& value) { | |
1124 ASSERT(hex_string[0] != '-'); | |
1125 intptr_t bigint_length = ComputeLength(hex_string); | |
1126 // The bigint's least significant digit (lsd) is at position 0, whereas the | |
1127 // given string has it's lsd at the last position. | |
1128 // The hex_i index, pointing into the string, starts therefore at the end, | |
1129 // whereas the bigint-index (i) starts at 0. | |
1130 intptr_t hex_length = strlen(hex_string); | |
1131 intptr_t hex_i = hex_length - 1; | |
1132 for (intptr_t i = 0; i < bigint_length; i++) { | |
1133 Chunk digit = 0; | |
1134 int shift = 0; | |
1135 for (int j = 0; j < kHexCharsPerDigit; j++) { | |
1136 // Reads a block of hexadecimal digits and stores it in 'digit'. | |
1137 // Ex: "0123456" with kHexCharsPerDigit == 3, hex_i == 6, reads "456". | |
1138 if (hex_i < 0) { | |
1139 break; | |
1140 } | |
1141 ASSERT(hex_i >= 0); | |
1142 char c = hex_string[hex_i--]; | |
1143 ASSERT(Utils::IsHexDigit(c)); | |
1144 digit += static_cast<Chunk>(Utils::HexDigitToInt(c)) << shift; | |
1145 shift += 4; | |
1146 } | |
1147 value.SetChunkAt(i, digit); | |
1148 } | |
1149 ASSERT(hex_i == -1); | |
1150 Clamp(value); | |
1151 } | |
1152 | |
1153 | |
1144 RawBigint* BigintOperations::AddSubtract(const Bigint& a, | 1154 RawBigint* BigintOperations::AddSubtract(const Bigint& a, |
1145 const Bigint& b, | 1155 const Bigint& b, |
1146 bool negate_b) { | 1156 bool negate_b) { |
1147 ASSERT(IsClamped(a)); | 1157 ASSERT(IsClamped(a)); |
1148 ASSERT(IsClamped(b)); | 1158 ASSERT(IsClamped(b)); |
1149 Bigint& result = Bigint::Handle(); | 1159 Bigint& result = Bigint::Handle(); |
1150 // We perform the subtraction by simulating a negation of the b-argument. | 1160 // We perform the subtraction by simulating a negation of the b-argument. |
1151 bool b_is_negative = negate_b ? !b.IsNegative() : b.IsNegative(); | 1161 bool b_is_negative = negate_b ? !b.IsNegative() : b.IsNegative(); |
1152 | 1162 |
1153 // If both are of the same sign, then we can compute the unsigned addition | 1163 // If both are of the same sign, then we can compute the unsigned addition |
(...skipping 353 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1507 int BigintOperations::CountBits(Chunk digit) { | 1517 int BigintOperations::CountBits(Chunk digit) { |
1508 int result = 0; | 1518 int result = 0; |
1509 while (digit != 0) { | 1519 while (digit != 0) { |
1510 digit >>= 1; | 1520 digit >>= 1; |
1511 result++; | 1521 result++; |
1512 } | 1522 } |
1513 return result; | 1523 return result; |
1514 } | 1524 } |
1515 | 1525 |
1516 } // namespace dart | 1526 } // namespace dart |
OLD | NEW |