xref: /linux/rust/syn/bigint.rs (revision 69942c0a8965f311ed7ddf842f160c9cfdcda73a)
1 // SPDX-License-Identifier: Apache-2.0 OR MIT
2 
3 use std::ops::{AddAssign, MulAssign};
4 
5 // For implementing base10_digits() accessor on LitInt.
6 pub(crate) struct BigInt {
7     digits: Vec<u8>,
8 }
9 
10 impl BigInt {
11     pub(crate) fn new() -> Self {
12         BigInt { digits: Vec::new() }
13     }
14 
15     pub(crate) fn to_string(&self) -> String {
16         let mut repr = String::with_capacity(self.digits.len());
17 
18         let mut has_nonzero = false;
19         for digit in self.digits.iter().rev() {
20             has_nonzero |= *digit != 0;
21             if has_nonzero {
22                 repr.push((*digit + b'0') as char);
23             }
24         }
25 
26         if repr.is_empty() {
27             repr.push('0');
28         }
29 
30         repr
31     }
32 
33     fn reserve_two_digits(&mut self) {
34         let len = self.digits.len();
35         let desired =
36             len + !self.digits.ends_with(&[0, 0]) as usize + !self.digits.ends_with(&[0]) as usize;
37         self.digits.resize(desired, 0);
38     }
39 }
40 
41 impl AddAssign<u8> for BigInt {
42     // Assumes increment <16.
43     fn add_assign(&mut self, mut increment: u8) {
44         self.reserve_two_digits();
45 
46         let mut i = 0;
47         while increment > 0 {
48             let sum = self.digits[i] + increment;
49             self.digits[i] = sum % 10;
50             increment = sum / 10;
51             i += 1;
52         }
53     }
54 }
55 
56 impl MulAssign<u8> for BigInt {
57     // Assumes base <=16.
58     fn mul_assign(&mut self, base: u8) {
59         self.reserve_two_digits();
60 
61         let mut carry = 0;
62         for digit in &mut self.digits {
63             let prod = *digit * base + carry;
64             *digit = prod % 10;
65             carry = prod / 10;
66         }
67     }
68 }
69