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