/src/ruby/prism/integer.c
Line | Count | Source |
1 | | #include "prism/internal/integer.h" |
2 | | |
3 | | #include "prism/internal/allocator.h" |
4 | | #include "prism/internal/buffer.h" |
5 | | |
6 | | #include <assert.h> |
7 | | #include <inttypes.h> |
8 | | #include <stdbool.h> |
9 | | #include <stddef.h> |
10 | | #include <stdlib.h> |
11 | | #include <string.h> |
12 | | |
13 | | /** |
14 | | * Free the internal memory of an integer. This memory will only be allocated if |
15 | | * the integer exceeds the size of a single uint32_t. |
16 | | */ |
17 | | static void |
18 | 0 | pm_integer_free(pm_integer_t *integer) { |
19 | 0 | if (integer->values) { |
20 | 0 | xfree(integer->values); |
21 | 0 | } |
22 | 0 | } |
23 | | |
24 | | /** |
25 | | * Pull out the length and values from the integer, regardless of the form in |
26 | | * which the length/values are stored. |
27 | | */ |
28 | | #define INTEGER_EXTRACT(integer, length_variable, values_variable) \ |
29 | 0 | if ((integer)->values == NULL) { \ |
30 | 0 | length_variable = 1; \ |
31 | 0 | values_variable = &(integer)->value; \ |
32 | 0 | } else { \ |
33 | 0 | length_variable = (integer)->length; \ |
34 | 0 | values_variable = (integer)->values; \ |
35 | 0 | } |
36 | | |
37 | | /** |
38 | | * Adds two positive pm_integer_t with the given base. |
39 | | * Return pm_integer_t with values allocated. Not normalized. |
40 | | */ |
41 | | static void |
42 | 0 | big_add(pm_integer_t *destination, pm_integer_t *left, pm_integer_t *right, uint64_t base) { |
43 | 0 | size_t left_length; |
44 | 0 | uint32_t *left_values; |
45 | 0 | INTEGER_EXTRACT(left, left_length, left_values) |
46 | |
|
47 | 0 | size_t right_length; |
48 | 0 | uint32_t *right_values; |
49 | 0 | INTEGER_EXTRACT(right, right_length, right_values) |
50 | |
|
51 | 0 | size_t length = left_length < right_length ? right_length : left_length; |
52 | 0 | uint32_t *values = (uint32_t *) xmalloc(sizeof(uint32_t) * (length + 1)); |
53 | 0 | if (values == NULL) return; |
54 | | |
55 | 0 | uint64_t carry = 0; |
56 | 0 | for (size_t index = 0; index < length; index++) { |
57 | 0 | uint64_t sum = carry + (index < left_length ? left_values[index] : 0) + (index < right_length ? right_values[index] : 0); |
58 | 0 | values[index] = (uint32_t) (sum % base); |
59 | 0 | carry = sum / base; |
60 | 0 | } |
61 | |
|
62 | 0 | if (carry > 0) { |
63 | 0 | values[length] = (uint32_t) carry; |
64 | 0 | length++; |
65 | 0 | } |
66 | |
|
67 | 0 | *destination = (pm_integer_t) { length, values, 0, false }; |
68 | 0 | } |
69 | | |
70 | | /** |
71 | | * Internal use for karatsuba_multiply. Calculates `a - b - c` with the given |
72 | | * base. Assume a, b, c, a - b - c all to be positive. |
73 | | * Return pm_integer_t with values allocated. Not normalized. |
74 | | */ |
75 | | static void |
76 | 0 | big_sub2(pm_integer_t *destination, pm_integer_t *a, pm_integer_t *b, pm_integer_t *c, uint64_t base) { |
77 | 0 | size_t a_length; |
78 | 0 | uint32_t *a_values; |
79 | 0 | INTEGER_EXTRACT(a, a_length, a_values) |
80 | |
|
81 | 0 | size_t b_length; |
82 | 0 | uint32_t *b_values; |
83 | 0 | INTEGER_EXTRACT(b, b_length, b_values) |
84 | |
|
85 | 0 | size_t c_length; |
86 | 0 | uint32_t *c_values; |
87 | 0 | INTEGER_EXTRACT(c, c_length, c_values) |
88 | |
|
89 | 0 | uint32_t *values = (uint32_t*) xmalloc(sizeof(uint32_t) * a_length); |
90 | 0 | int64_t carry = 0; |
91 | |
|
92 | 0 | for (size_t index = 0; index < a_length; index++) { |
93 | 0 | int64_t sub = ( |
94 | 0 | carry + |
95 | 0 | a_values[index] - |
96 | 0 | (index < b_length ? b_values[index] : 0) - |
97 | 0 | (index < c_length ? c_values[index] : 0) |
98 | 0 | ); |
99 | |
|
100 | 0 | if (sub >= 0) { |
101 | 0 | values[index] = (uint32_t) sub; |
102 | 0 | carry = 0; |
103 | 0 | } else { |
104 | 0 | sub += 2 * (int64_t) base; |
105 | 0 | values[index] = (uint32_t) ((uint64_t) sub % base); |
106 | 0 | carry = sub / (int64_t) base - 2; |
107 | 0 | } |
108 | 0 | } |
109 | |
|
110 | 0 | while (a_length > 1 && values[a_length - 1] == 0) a_length--; |
111 | 0 | *destination = (pm_integer_t) { a_length, values, 0, false }; |
112 | 0 | } |
113 | | |
114 | | /** |
115 | | * Multiply two positive integers with the given base using karatsuba algorithm. |
116 | | * Return pm_integer_t with values allocated. Not normalized. |
117 | | */ |
118 | | static void |
119 | 0 | karatsuba_multiply(pm_integer_t *destination, pm_integer_t *left, pm_integer_t *right, uint64_t base) { |
120 | 0 | size_t left_length; |
121 | 0 | uint32_t *left_values; |
122 | 0 | INTEGER_EXTRACT(left, left_length, left_values) |
123 | |
|
124 | 0 | size_t right_length; |
125 | 0 | uint32_t *right_values; |
126 | 0 | INTEGER_EXTRACT(right, right_length, right_values) |
127 | |
|
128 | 0 | if (left_length > right_length) { |
129 | 0 | size_t temporary_length = left_length; |
130 | 0 | left_length = right_length; |
131 | 0 | right_length = temporary_length; |
132 | |
|
133 | 0 | uint32_t *temporary_values = left_values; |
134 | 0 | left_values = right_values; |
135 | 0 | right_values = temporary_values; |
136 | 0 | } |
137 | |
|
138 | 0 | if (left_length <= 10) { |
139 | 0 | size_t length = left_length + right_length; |
140 | 0 | uint32_t *values = (uint32_t *) xcalloc(length, sizeof(uint32_t)); |
141 | 0 | if (values == NULL) return; |
142 | | |
143 | 0 | for (size_t left_index = 0; left_index < left_length; left_index++) { |
144 | 0 | uint32_t carry = 0; |
145 | 0 | for (size_t right_index = 0; right_index < right_length; right_index++) { |
146 | 0 | uint64_t product = (uint64_t) left_values[left_index] * right_values[right_index] + values[left_index + right_index] + carry; |
147 | 0 | values[left_index + right_index] = (uint32_t) (product % base); |
148 | 0 | carry = (uint32_t) (product / base); |
149 | 0 | } |
150 | 0 | values[left_index + right_length] = carry; |
151 | 0 | } |
152 | |
|
153 | 0 | while (length > 1 && values[length - 1] == 0) length--; |
154 | 0 | *destination = (pm_integer_t) { length, values, 0, false }; |
155 | 0 | return; |
156 | 0 | } |
157 | | |
158 | 0 | if (left_length * 2 <= right_length) { |
159 | 0 | uint32_t *values = (uint32_t *) xcalloc(left_length + right_length, sizeof(uint32_t)); |
160 | |
|
161 | 0 | for (size_t start_offset = 0; start_offset < right_length; start_offset += left_length) { |
162 | 0 | size_t end_offset = start_offset + left_length; |
163 | 0 | if (end_offset > right_length) end_offset = right_length; |
164 | |
|
165 | 0 | pm_integer_t sliced_left = { |
166 | 0 | .length = left_length, |
167 | 0 | .values = left_values, |
168 | 0 | .value = 0, |
169 | 0 | .negative = false |
170 | 0 | }; |
171 | |
|
172 | 0 | pm_integer_t sliced_right = { |
173 | 0 | .length = end_offset - start_offset, |
174 | 0 | .values = right_values + start_offset, |
175 | 0 | .value = 0, |
176 | 0 | .negative = false |
177 | 0 | }; |
178 | |
|
179 | 0 | pm_integer_t product; |
180 | 0 | karatsuba_multiply(&product, &sliced_left, &sliced_right, base); |
181 | |
|
182 | 0 | uint32_t carry = 0; |
183 | 0 | for (size_t index = 0; index < product.length; index++) { |
184 | 0 | uint64_t sum = (uint64_t) values[start_offset + index] + product.values[index] + carry; |
185 | 0 | values[start_offset + index] = (uint32_t) (sum % base); |
186 | 0 | carry = (uint32_t) (sum / base); |
187 | 0 | } |
188 | |
|
189 | 0 | if (carry > 0) values[start_offset + product.length] += carry; |
190 | 0 | pm_integer_free(&product); |
191 | 0 | } |
192 | |
|
193 | 0 | *destination = (pm_integer_t) { left_length + right_length, values, 0, false }; |
194 | 0 | return; |
195 | 0 | } |
196 | | |
197 | 0 | size_t half = left_length / 2; |
198 | 0 | pm_integer_t x0 = { half, left_values, 0, false }; |
199 | 0 | pm_integer_t x1 = { left_length - half, left_values + half, 0, false }; |
200 | 0 | pm_integer_t y0 = { half, right_values, 0, false }; |
201 | 0 | pm_integer_t y1 = { right_length - half, right_values + half, 0, false }; |
202 | |
|
203 | 0 | pm_integer_t z0 = { 0 }; |
204 | 0 | karatsuba_multiply(&z0, &x0, &y0, base); |
205 | |
|
206 | 0 | pm_integer_t z2 = { 0 }; |
207 | 0 | karatsuba_multiply(&z2, &x1, &y1, base); |
208 | | |
209 | | // For simplicity to avoid considering negative values, |
210 | | // use `z1 = (x0 + x1) * (y0 + y1) - z0 - z2` instead of original karatsuba algorithm. |
211 | 0 | pm_integer_t x01 = { 0 }; |
212 | 0 | big_add(&x01, &x0, &x1, base); |
213 | |
|
214 | 0 | pm_integer_t y01 = { 0 }; |
215 | 0 | big_add(&y01, &y0, &y1, base); |
216 | |
|
217 | 0 | pm_integer_t xy = { 0 }; |
218 | 0 | karatsuba_multiply(&xy, &x01, &y01, base); |
219 | |
|
220 | 0 | pm_integer_t z1; |
221 | 0 | big_sub2(&z1, &xy, &z0, &z2, base); |
222 | |
|
223 | 0 | size_t length = left_length + right_length; |
224 | 0 | uint32_t *values = (uint32_t*) xcalloc(length, sizeof(uint32_t)); |
225 | |
|
226 | 0 | assert(z0.values != NULL); |
227 | 0 | memcpy(values, z0.values, sizeof(uint32_t) * z0.length); |
228 | |
|
229 | 0 | assert(z2.values != NULL); |
230 | 0 | memcpy(values + 2 * half, z2.values, sizeof(uint32_t) * z2.length); |
231 | |
|
232 | 0 | uint32_t carry = 0; |
233 | 0 | for(size_t index = 0; index < z1.length; index++) { |
234 | 0 | uint64_t sum = (uint64_t) carry + values[index + half] + z1.values[index]; |
235 | 0 | values[index + half] = (uint32_t) (sum % base); |
236 | 0 | carry = (uint32_t) (sum / base); |
237 | 0 | } |
238 | |
|
239 | 0 | for(size_t index = half + z1.length; carry > 0; index++) { |
240 | 0 | uint64_t sum = (uint64_t) carry + values[index]; |
241 | 0 | values[index] = (uint32_t) (sum % base); |
242 | 0 | carry = (uint32_t) (sum / base); |
243 | 0 | } |
244 | |
|
245 | 0 | while (length > 1 && values[length - 1] == 0) length--; |
246 | 0 | pm_integer_free(&z0); |
247 | 0 | pm_integer_free(&z1); |
248 | 0 | pm_integer_free(&z2); |
249 | 0 | pm_integer_free(&x01); |
250 | 0 | pm_integer_free(&y01); |
251 | 0 | pm_integer_free(&xy); |
252 | |
|
253 | 0 | *destination = (pm_integer_t) { length, values, 0, false }; |
254 | 0 | } |
255 | | |
256 | | /** |
257 | | * The values of a hexadecimal digit, where the index is the ASCII character. |
258 | | * Note that there's an odd exception here where _ is mapped to 0. This is |
259 | | * because it's possible for us to end up trying to parse a number that has |
260 | | * already had an error attached to it, and we want to provide _something_ to |
261 | | * the user. |
262 | | */ |
263 | | static const int8_t pm_integer_parse_digit_values[256] = { |
264 | | // 0 1 2 3 4 5 6 7 8 9 A B C D E F |
265 | | -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 0x |
266 | | -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 1x |
267 | | -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 2x |
268 | | 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, -1, -1, -1, -1, -1, -1, // 3x |
269 | | -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 4x |
270 | | -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 0, // 5x |
271 | | -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 6x |
272 | | -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 7x |
273 | | -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 8x |
274 | | -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 9x |
275 | | -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // Ax |
276 | | -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // Bx |
277 | | -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // Cx |
278 | | -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // Dx |
279 | | -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // Ex |
280 | | -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // Fx |
281 | | }; |
282 | | |
283 | | /** |
284 | | * Return the value of a hexadecimal digit in a uint8_t. |
285 | | */ |
286 | | static uint8_t |
287 | 0 | pm_integer_parse_digit(const uint8_t character) { |
288 | 0 | int8_t value = pm_integer_parse_digit_values[character]; |
289 | 0 | assert(value != -1 && "invalid digit"); |
290 | |
|
291 | 0 | return (uint8_t) value; |
292 | 0 | } |
293 | | |
294 | | /** |
295 | | * Create a pm_integer_t from uint64_t with the given base. It is assumed that |
296 | | * the memory for the pm_integer_t pointer has been zeroed. |
297 | | */ |
298 | | static void |
299 | 0 | pm_integer_from_uint64(pm_integer_t *integer, uint64_t value, uint64_t base) { |
300 | 0 | if (value < base) { |
301 | 0 | integer->value = (uint32_t) value; |
302 | 0 | return; |
303 | 0 | } |
304 | | |
305 | 0 | size_t length = 0; |
306 | 0 | uint64_t length_value = value; |
307 | 0 | while (length_value > 0) { |
308 | 0 | length++; |
309 | 0 | length_value /= base; |
310 | 0 | } |
311 | |
|
312 | 0 | uint32_t *values = (uint32_t *) xmalloc(sizeof(uint32_t) * length); |
313 | 0 | if (values == NULL) return; |
314 | | |
315 | 0 | for (size_t value_index = 0; value_index < length; value_index++) { |
316 | 0 | values[value_index] = (uint32_t) (value % base); |
317 | 0 | value /= base; |
318 | 0 | } |
319 | |
|
320 | 0 | integer->length = length; |
321 | 0 | integer->values = values; |
322 | 0 | } |
323 | | |
324 | | /** |
325 | | * Normalize pm_integer_t. |
326 | | * Heading zero values will be removed. If the integer fits into uint32_t, |
327 | | * values is set to NULL, length is set to 0, and value field will be used. |
328 | | */ |
329 | | static void |
330 | 0 | pm_integer_normalize(pm_integer_t *integer) { |
331 | 0 | if (integer->values == NULL) { |
332 | 0 | return; |
333 | 0 | } |
334 | | |
335 | 0 | while (integer->length > 1 && integer->values[integer->length - 1] == 0) { |
336 | 0 | integer->length--; |
337 | 0 | } |
338 | |
|
339 | 0 | if (integer->length > 1) { |
340 | 0 | return; |
341 | 0 | } |
342 | | |
343 | 0 | uint32_t value = integer->values[0]; |
344 | 0 | bool negative = integer->negative && value != 0; |
345 | |
|
346 | 0 | pm_integer_free(integer); |
347 | 0 | *integer = (pm_integer_t) { .values = NULL, .value = value, .length = 0, .negative = negative }; |
348 | 0 | } |
349 | | |
350 | | /** |
351 | | * Convert base of the integer. |
352 | | * In practice, it converts 10**9 to 1<<32 or 1<<32 to 10**9. |
353 | | */ |
354 | | static void |
355 | 0 | pm_integer_convert_base(pm_integer_t *destination, const pm_integer_t *source, uint64_t base_from, uint64_t base_to) { |
356 | 0 | size_t source_length; |
357 | 0 | const uint32_t *source_values; |
358 | 0 | INTEGER_EXTRACT(source, source_length, source_values) |
359 | |
|
360 | 0 | size_t bigints_length = (source_length + 1) / 2; |
361 | 0 | assert(bigints_length > 0); |
362 | |
|
363 | 0 | pm_integer_t *bigints = (pm_integer_t *) xcalloc(bigints_length, sizeof(pm_integer_t)); |
364 | 0 | if (bigints == NULL) return; |
365 | | |
366 | 0 | for (size_t index = 0; index < source_length; index += 2) { |
367 | 0 | uint64_t value = source_values[index] + base_from * (index + 1 < source_length ? source_values[index + 1] : 0); |
368 | 0 | pm_integer_from_uint64(&bigints[index / 2], value, base_to); |
369 | 0 | } |
370 | |
|
371 | 0 | pm_integer_t base = { 0 }; |
372 | 0 | pm_integer_from_uint64(&base, base_from, base_to); |
373 | |
|
374 | 0 | while (bigints_length > 1) { |
375 | 0 | pm_integer_t next_base; |
376 | 0 | karatsuba_multiply(&next_base, &base, &base, base_to); |
377 | |
|
378 | 0 | pm_integer_free(&base); |
379 | 0 | base = next_base; |
380 | |
|
381 | 0 | size_t next_length = (bigints_length + 1) / 2; |
382 | 0 | pm_integer_t *next_bigints = (pm_integer_t *) xcalloc(next_length, sizeof(pm_integer_t)); |
383 | |
|
384 | 0 | for (size_t bigints_index = 0; bigints_index < bigints_length; bigints_index += 2) { |
385 | 0 | if (bigints_index + 1 == bigints_length) { |
386 | 0 | next_bigints[bigints_index / 2] = bigints[bigints_index]; |
387 | 0 | } else { |
388 | 0 | pm_integer_t multiplied = { 0 }; |
389 | 0 | karatsuba_multiply(&multiplied, &base, &bigints[bigints_index + 1], base_to); |
390 | |
|
391 | 0 | big_add(&next_bigints[bigints_index / 2], &bigints[bigints_index], &multiplied, base_to); |
392 | 0 | pm_integer_free(&bigints[bigints_index]); |
393 | 0 | pm_integer_free(&bigints[bigints_index + 1]); |
394 | 0 | pm_integer_free(&multiplied); |
395 | 0 | } |
396 | 0 | } |
397 | |
|
398 | 0 | xfree_sized(bigints, bigints_length * sizeof(pm_integer_t)); |
399 | 0 | bigints = next_bigints; |
400 | 0 | bigints_length = next_length; |
401 | 0 | } |
402 | |
|
403 | 0 | *destination = bigints[0]; |
404 | 0 | destination->negative = source->negative; |
405 | 0 | pm_integer_normalize(destination); |
406 | |
|
407 | 0 | xfree_sized(bigints, bigints_length * sizeof(pm_integer_t)); |
408 | 0 | pm_integer_free(&base); |
409 | 0 | } |
410 | | |
411 | | #undef INTEGER_EXTRACT |
412 | | |
413 | | /** |
414 | | * Convert digits to integer with the given power-of-two base. |
415 | | */ |
416 | | static void |
417 | 0 | pm_integer_parse_powof2(pm_integer_t *integer, uint32_t base, const uint8_t *digits, size_t digits_length) { |
418 | 0 | size_t bit = 1; |
419 | 0 | while (base > (uint32_t) (1 << bit)) bit++; |
420 | |
|
421 | 0 | size_t length = (digits_length * bit + 31) / 32; |
422 | 0 | uint32_t *values = (uint32_t *) xcalloc(length, sizeof(uint32_t)); |
423 | |
|
424 | 0 | for (size_t digit_index = 0; digit_index < digits_length; digit_index++) { |
425 | 0 | size_t bit_position = bit * (digits_length - digit_index - 1); |
426 | 0 | uint32_t value = digits[digit_index]; |
427 | |
|
428 | 0 | size_t index = bit_position / 32; |
429 | 0 | size_t shift = bit_position % 32; |
430 | |
|
431 | 0 | values[index] |= value << shift; |
432 | 0 | if (32 - shift < bit) values[index + 1] |= value >> (32 - shift); |
433 | 0 | } |
434 | |
|
435 | 0 | while (length > 1 && values[length - 1] == 0) length--; |
436 | 0 | *integer = (pm_integer_t) { .length = length, .values = values, .value = 0, .negative = false }; |
437 | 0 | pm_integer_normalize(integer); |
438 | 0 | } |
439 | | |
440 | | /** |
441 | | * Convert decimal digits to pm_integer_t. |
442 | | */ |
443 | | static void |
444 | 0 | pm_integer_parse_decimal(pm_integer_t *integer, const uint8_t *digits, size_t digits_length) { |
445 | 0 | const size_t batch = 9; |
446 | 0 | const size_t length = (digits_length + batch - 1) / batch; |
447 | |
|
448 | 0 | uint32_t *values = (uint32_t *) xcalloc(length, sizeof(uint32_t)); |
449 | 0 | uint32_t value = 0; |
450 | |
|
451 | 0 | for (size_t digits_index = 0; digits_index < digits_length; digits_index++) { |
452 | 0 | value = value * 10 + digits[digits_index]; |
453 | |
|
454 | 0 | size_t reverse_index = digits_length - digits_index - 1; |
455 | 0 | if (reverse_index % batch == 0) { |
456 | 0 | values[reverse_index / batch] = value; |
457 | 0 | value = 0; |
458 | 0 | } |
459 | 0 | } |
460 | | |
461 | | // Convert base from 10**9 to 1<<32. |
462 | 0 | pm_integer_convert_base(integer, &((pm_integer_t) { .length = length, .values = values, .value = 0, .negative = false }), 1000000000, ((uint64_t) 1 << 32)); |
463 | 0 | xfree_sized(values, length * sizeof(uint32_t)); |
464 | 0 | } |
465 | | |
466 | | /** |
467 | | * Parse a large integer from a string that does not fit into uint32_t. |
468 | | */ |
469 | | static void |
470 | 0 | pm_integer_parse_big(pm_integer_t *integer, uint32_t multiplier, const uint8_t *start, const uint8_t *end) { |
471 | | // Allocate an array to store digits. |
472 | 0 | const size_t digits_capa = sizeof(uint8_t) * (size_t) (end - start); |
473 | 0 | uint8_t *digits = xmalloc(digits_capa); |
474 | 0 | size_t digits_length = 0; |
475 | |
|
476 | 0 | for (; start < end; start++) { |
477 | 0 | if (*start == '_') continue; |
478 | 0 | digits[digits_length++] = pm_integer_parse_digit(*start); |
479 | 0 | } |
480 | | |
481 | | // Construct pm_integer_t from the digits. |
482 | 0 | if (multiplier == 10) { |
483 | 0 | pm_integer_parse_decimal(integer, digits, digits_length); |
484 | 0 | } else { |
485 | 0 | pm_integer_parse_powof2(integer, multiplier, digits, digits_length); |
486 | 0 | } |
487 | |
|
488 | 0 | xfree_sized(digits, digits_capa); |
489 | 0 | } |
490 | | |
491 | | /** |
492 | | * Parse an integer from a string. This assumes that the format of the integer |
493 | | * has already been validated, as internal validation checks are not performed |
494 | | * here. |
495 | | */ |
496 | | void |
497 | 0 | pm_integer_parse(pm_integer_t *integer, pm_integer_base_t base, const uint8_t *start, const uint8_t *end) { |
498 | | // Ignore unary +. Unary - is parsed differently and will not end up here. |
499 | | // Instead, it will modify the parsed integer later. |
500 | 0 | if (*start == '+') start++; |
501 | | |
502 | | // Determine the multiplier from the base, and skip past any prefixes. |
503 | 0 | uint32_t multiplier = 10; |
504 | 0 | switch (base) { |
505 | 0 | case PM_INTEGER_BASE_DEFAULT: |
506 | 0 | while (*start == '0') start++; // 01 -> 1 |
507 | 0 | break; |
508 | 0 | case PM_INTEGER_BASE_BINARY: |
509 | 0 | start += 2; // 0b |
510 | 0 | multiplier = 2; |
511 | 0 | break; |
512 | 0 | case PM_INTEGER_BASE_OCTAL: |
513 | 0 | start++; // 0 |
514 | 0 | if (*start == '_' || *start == 'o' || *start == 'O') start++; // o |
515 | 0 | multiplier = 8; |
516 | 0 | break; |
517 | 0 | case PM_INTEGER_BASE_DECIMAL: |
518 | 0 | if (*start == '0' && (end - start) > 1) start += 2; // 0d |
519 | 0 | break; |
520 | 0 | case PM_INTEGER_BASE_HEXADECIMAL: |
521 | 0 | start += 2; // 0x |
522 | 0 | multiplier = 16; |
523 | 0 | break; |
524 | 0 | case PM_INTEGER_BASE_UNKNOWN: |
525 | 0 | if (*start == '0' && (end - start) > 1) { |
526 | 0 | switch (start[1]) { |
527 | 0 | case '_': start += 2; multiplier = 8; break; |
528 | 0 | case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': start++; multiplier = 8; break; |
529 | 0 | case 'b': case 'B': start += 2; multiplier = 2; break; |
530 | 0 | case 'o': case 'O': start += 2; multiplier = 8; break; |
531 | 0 | case 'd': case 'D': start += 2; break; |
532 | 0 | case 'x': case 'X': start += 2; multiplier = 16; break; |
533 | 0 | default: assert(false && "unreachable"); break; |
534 | 0 | } |
535 | 0 | } |
536 | 0 | break; |
537 | 0 | } |
538 | | |
539 | | // It's possible that we've consumed everything at this point if there is an |
540 | | // invalid integer. If this is the case, we'll just return 0. |
541 | 0 | if (start >= end) return; |
542 | | |
543 | 0 | const uint8_t *cursor = start; |
544 | 0 | uint64_t value = (uint64_t) pm_integer_parse_digit(*cursor++); |
545 | |
|
546 | 0 | for (; cursor < end; cursor++) { |
547 | 0 | if (*cursor == '_') continue; |
548 | 0 | value = value * multiplier + (uint64_t) pm_integer_parse_digit(*cursor); |
549 | |
|
550 | 0 | if (value > UINT32_MAX) { |
551 | | // If the integer is too large to fit into a single uint32_t, then |
552 | | // we'll parse it as a big integer. |
553 | 0 | pm_integer_parse_big(integer, multiplier, start, end); |
554 | 0 | return; |
555 | 0 | } |
556 | 0 | } |
557 | | |
558 | 0 | integer->value = (uint32_t) value; |
559 | 0 | } |
560 | | |
561 | | /** |
562 | | * Compare two integers. This function returns -1 if the left integer is less |
563 | | * than the right integer, 0 if they are equal, and 1 if the left integer is |
564 | | * greater than the right integer. |
565 | | */ |
566 | | int |
567 | 0 | pm_integer_compare(const pm_integer_t *left, const pm_integer_t *right) { |
568 | 0 | if (left->negative != right->negative) return left->negative ? -1 : 1; |
569 | 0 | int negative = left->negative ? -1 : 1; |
570 | |
|
571 | 0 | if (left->values == NULL && right->values == NULL) { |
572 | 0 | if (left->value < right->value) return -1 * negative; |
573 | 0 | if (left->value > right->value) return 1 * negative; |
574 | 0 | return 0; |
575 | 0 | } |
576 | | |
577 | 0 | if (left->values == NULL || left->length < right->length) return -1 * negative; |
578 | 0 | if (right->values == NULL || left->length > right->length) return 1 * negative; |
579 | | |
580 | 0 | for (size_t index = 0; index < left->length; index++) { |
581 | 0 | size_t value_index = left->length - index - 1; |
582 | 0 | uint32_t left_value = left->values[value_index]; |
583 | 0 | uint32_t right_value = right->values[value_index]; |
584 | |
|
585 | 0 | if (left_value < right_value) return -1 * negative; |
586 | 0 | if (left_value > right_value) return 1 * negative; |
587 | 0 | } |
588 | | |
589 | 0 | return 0; |
590 | 0 | } |
591 | | |
592 | | /** |
593 | | * Reduce a ratio of integers to its simplest form. |
594 | | */ |
595 | 0 | void pm_integers_reduce(pm_integer_t *numerator, pm_integer_t *denominator) { |
596 | | // If either the numerator or denominator do not fit into a 32-bit integer, |
597 | | // then this function is a no-op. In the future, we may consider reducing |
598 | | // even the larger numbers, but for now we're going to keep it simple. |
599 | 0 | if ( |
600 | | // If the numerator doesn't fit into a 32-bit integer, return early. |
601 | 0 | numerator->length != 0 || |
602 | | // If the denominator doesn't fit into a 32-bit integer, return early. |
603 | 0 | denominator->length != 0 || |
604 | | // If the numerator is 0, then return early. |
605 | 0 | numerator->value == 0 || |
606 | | // If the denominator is 1, then return early. |
607 | 0 | denominator->value == 1 |
608 | 0 | ) return; |
609 | | |
610 | | // Find the greatest common divisor of the numerator and denominator. |
611 | 0 | uint32_t divisor = numerator->value; |
612 | 0 | uint32_t remainder = denominator->value; |
613 | |
|
614 | 0 | while (remainder != 0) { |
615 | 0 | uint32_t temporary = remainder; |
616 | 0 | remainder = divisor % remainder; |
617 | 0 | divisor = temporary; |
618 | 0 | } |
619 | | |
620 | | // Divide the numerator and denominator by the greatest common divisor. |
621 | 0 | numerator->value /= divisor; |
622 | 0 | denominator->value /= divisor; |
623 | 0 | } |
624 | | |
625 | | /** |
626 | | * Convert an integer to a decimal string. |
627 | | */ |
628 | | void |
629 | 0 | pm_integer_string(pm_buffer_t *buffer, const pm_integer_t *integer) { |
630 | 0 | if (integer->negative) { |
631 | 0 | pm_buffer_append_byte(buffer, '-'); |
632 | 0 | } |
633 | | |
634 | | // If the integer fits into a single uint32_t, then we can just append the |
635 | | // value directly to the buffer. |
636 | 0 | if (integer->values == NULL) { |
637 | 0 | pm_buffer_append_format(buffer, "%" PRIu32, integer->value); |
638 | 0 | return; |
639 | 0 | } |
640 | | |
641 | | // If the integer is two uint32_t values, then we can | them together and |
642 | | // append the result to the buffer. |
643 | 0 | if (integer->length == 2) { |
644 | 0 | const uint64_t value = ((uint64_t) integer->values[0]) | ((uint64_t) integer->values[1] << 32); |
645 | 0 | pm_buffer_append_format(buffer, "%" PRIu64, value); |
646 | 0 | return; |
647 | 0 | } |
648 | | |
649 | | // Otherwise, first we'll convert the base from 1<<32 to 10**9. |
650 | 0 | pm_integer_t converted = { 0 }; |
651 | 0 | pm_integer_convert_base(&converted, integer, (uint64_t) 1 << 32, 1000000000); |
652 | |
|
653 | 0 | if (converted.values == NULL) { |
654 | 0 | pm_buffer_append_format(buffer, "%" PRIu32, converted.value); |
655 | 0 | pm_integer_free(&converted); |
656 | 0 | return; |
657 | 0 | } |
658 | | |
659 | | // Allocate a buffer that we'll copy the decimal digits into. |
660 | 0 | const size_t digits_length = converted.length * 9; |
661 | 0 | char *digits = xcalloc(digits_length, sizeof(char)); |
662 | 0 | if (digits == NULL) return; |
663 | | |
664 | | // Pack bigdecimal to digits. |
665 | 0 | for (size_t value_index = 0; value_index < converted.length; value_index++) { |
666 | 0 | uint32_t value = converted.values[value_index]; |
667 | |
|
668 | 0 | for (size_t digit_index = 0; digit_index < 9; digit_index++) { |
669 | 0 | digits[digits_length - 9 * value_index - digit_index - 1] = (char) ('0' + value % 10); |
670 | 0 | value /= 10; |
671 | 0 | } |
672 | 0 | } |
673 | |
|
674 | 0 | size_t start_offset = 0; |
675 | 0 | while (start_offset < digits_length - 1 && digits[start_offset] == '0') start_offset++; |
676 | | |
677 | | // Finally, append the string to the buffer and free the digits. |
678 | 0 | pm_buffer_append_string(buffer, digits + start_offset, digits_length - start_offset); |
679 | 0 | xfree_sized(digits, sizeof(char) * digits_length); |
680 | 0 | pm_integer_free(&converted); |
681 | 0 | } |