Coverage Report

Created: 2026-06-03 06:22

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/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
}