Coverage Report

Created: 2026-08-13 07:14

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/rust/registry/src/index.crates.io-1949cf8c6b5b557f/num-bigint-0.5.1/src/biguint/addition.rs
Line
Count
Source
1
use super::{BigUint, IntDigits};
2
3
use crate::big_digit::{self, BigDigit};
4
use crate::UsizePromotion;
5
6
use core::iter::Sum;
7
use core::ops::{Add, AddAssign};
8
use num_traits::CheckedAdd;
9
10
#[cfg(target_arch = "x86_64")]
11
use core::arch::x86_64 as arch;
12
13
#[cfg(target_arch = "x86")]
14
use core::arch::x86 as arch;
15
16
// Add with carry:
17
#[cfg(target_arch = "x86_64")]
18
cfg_64!(
19
    #[inline]
20
    #[allow(unused_unsafe)] // TODO(MSRV 1.93): the intrinsic became safe
21
991k
    fn adc(carry: u8, a: u64, b: u64, out: &mut u64) -> u8 {
22
        // SAFETY: There are absolutely no safety concerns with calling `_addcarry_u64`.
23
        // It's just unsafe for API consistency with other intrinsics.
24
991k
        unsafe { arch::_addcarry_u64(carry, a, b, out) }
25
991k
    }
26
);
27
28
#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
29
cfg_32!(
30
    #[inline]
31
    #[allow(unused_unsafe)] // TODO(MSRV 1.93): the intrinsic became safe
32
    fn adc(carry: u8, a: u32, b: u32, out: &mut u32) -> u8 {
33
        // SAFETY: There are absolutely no safety concerns with calling `_addcarry_u32`.
34
        // It's just unsafe for API consistency with other intrinsics.
35
        unsafe { arch::_addcarry_u32(carry, a, b, out) }
36
    }
37
);
38
39
// fallback for environments where we don't have an addcarry intrinsic
40
// (copied from the standard library's `carrying_add`)
41
#[cfg(not(any(target_arch = "x86", target_arch = "x86_64")))]
42
#[inline]
43
fn adc(carry: u8, lhs: BigDigit, rhs: BigDigit, out: &mut BigDigit) -> u8 {
44
    let (a, b) = lhs.overflowing_add(rhs);
45
    let (c, d) = a.overflowing_add(carry as BigDigit);
46
    *out = c;
47
    u8::from(b || d)
48
}
49
50
/// Two argument addition of raw slices, `a += b`, returning the carry.
51
///
52
/// This is used when the data `Vec` might need to resize to push a non-zero carry, so we perform
53
/// the addition first hoping that it will fit.
54
///
55
/// The caller _must_ ensure that `a` is at least as long as `b`.
56
#[inline]
57
984k
pub(super) fn __add2(a: &mut [BigDigit], b: &[BigDigit]) -> BigDigit {
58
984k
    debug_assert!(a.len() >= b.len());
59
60
984k
    let mut carry = 0;
61
984k
    let (a_lo, a_hi) = a.split_at_mut(b.len());
62
63
984k
    for (a, b) in a_lo.iter_mut().zip(b) {
64
984k
        carry = adc(carry, *a, *b, a);
65
984k
    }
66
67
984k
    if carry != 0 {
68
6.59k
        for a in a_hi {
69
6.59k
            carry = adc(carry, *a, 0, a);
70
6.59k
            if carry == 0 {
71
6.32k
                break;
72
271
            }
73
        }
74
978k
    }
75
76
984k
    carry as BigDigit
77
984k
}
78
79
/// Two argument addition of raw slices:
80
/// a += b
81
///
82
/// The caller _must_ ensure that a is big enough to store the result - typically this means
83
/// resizing a to max(a.len(), b.len()) + 1, to fit a possible carry.
84
984k
pub(super) fn add2(a: &mut [BigDigit], b: &[BigDigit]) {
85
984k
    let carry = __add2(a, b);
86
87
984k
    debug_assert!(carry == 0);
88
984k
}
89
90
forward_all_binop_to_val_ref_commutative!(impl Add for BigUint, add);
91
forward_val_assign!(impl AddAssign for BigUint, add_assign);
92
93
impl Add<&BigUint> for BigUint {
94
    type Output = BigUint;
95
96
0
    fn add(mut self, other: &BigUint) -> BigUint {
97
0
        self += other;
98
0
        self
99
0
    }
100
}
101
impl AddAssign<&BigUint> for BigUint {
102
    #[inline]
103
0
    fn add_assign(&mut self, other: &BigUint) {
104
0
        let self_len = self.data.len();
105
0
        let mut other = &*other.data;
106
0
        if self_len < other.len() {
107
0
            let (low, high) = other.split_at(self_len);
108
0
            self.data.extend_from_slice(high);
109
0
            other = low;
110
0
        }
111
0
        let carry = __add2(&mut self.data, other);
112
0
        if carry != 0 {
113
0
            self.data.push(carry);
114
0
        }
115
0
    }
116
}
117
118
promote_unsigned_scalars!(impl Add for BigUint, add);
119
promote_unsigned_scalars_assign!(impl AddAssign for BigUint, add_assign);
120
forward_all_scalar_binop_to_val_val_commutative!(impl Add<u32> for BigUint, add);
121
forward_all_scalar_binop_to_val_val_commutative!(impl Add<u64> for BigUint, add);
122
forward_all_scalar_binop_to_val_val_commutative!(impl Add<u128> for BigUint, add);
123
124
impl Add<u32> for BigUint {
125
    type Output = BigUint;
126
127
    #[inline]
128
0
    fn add(mut self, other: u32) -> BigUint {
129
0
        self += other;
130
0
        self
131
0
    }
132
}
133
134
impl AddAssign<u32> for BigUint {
135
    #[inline]
136
0
    fn add_assign(&mut self, other: u32) {
137
0
        if other != 0 {
138
0
            if self.data.is_empty() {
139
0
                self.data.push(other as BigDigit);
140
0
            } else {
141
0
                let carry = __add2(&mut self.data, &[other as BigDigit]);
142
0
                if carry != 0 {
143
0
                    self.data.push(carry);
144
0
                }
145
            }
146
0
        }
147
0
    }
148
}
149
150
impl Add<u64> for BigUint {
151
    type Output = BigUint;
152
153
    #[inline]
154
0
    fn add(mut self, other: u64) -> BigUint {
155
0
        self += other;
156
0
        self
157
0
    }
158
}
159
160
impl AddAssign<u64> for BigUint {
161
    cfg_digit!(
162
        #[inline]
163
        fn add_assign(&mut self, other: u64) {
164
            let (hi, lo) = big_digit::from_doublebigdigit(other);
165
            if hi == 0 {
166
                *self += lo;
167
            } else {
168
                while self.data.len() < 2 {
169
                    self.data.push(0);
170
                }
171
172
                let carry = __add2(&mut self.data, &[lo, hi]);
173
                if carry != 0 {
174
                    self.data.push(carry);
175
                }
176
            }
177
        }
178
179
        #[inline]
180
0
        fn add_assign(&mut self, other: u64) {
181
0
            if other != 0 {
182
0
                if self.data.is_empty() {
183
0
                    self.data.push(other as BigDigit);
184
0
                } else {
185
0
                    let carry = __add2(&mut self.data, &[other as BigDigit]);
186
0
                    if carry != 0 {
187
0
                        self.data.push(carry);
188
0
                    }
189
                }
190
0
            }
191
0
        }
192
    );
193
}
194
195
impl Add<u128> for BigUint {
196
    type Output = BigUint;
197
198
    #[inline]
199
0
    fn add(mut self, other: u128) -> BigUint {
200
0
        self += other;
201
0
        self
202
0
    }
203
}
204
205
impl AddAssign<u128> for BigUint {
206
    cfg_digit!(
207
        #[inline]
208
        fn add_assign(&mut self, other: u128) {
209
            if other <= u128::from(u64::MAX) {
210
                *self += other as u64
211
            } else {
212
                let (a, b, c, d) = super::u32_from_u128(other);
213
                let carry = if a > 0 {
214
                    while self.data.len() < 4 {
215
                        self.data.push(0);
216
                    }
217
                    __add2(&mut self.data, &[d, c, b, a])
218
                } else {
219
                    debug_assert!(b > 0);
220
                    while self.data.len() < 3 {
221
                        self.data.push(0);
222
                    }
223
                    __add2(&mut self.data, &[d, c, b])
224
                };
225
226
                if carry != 0 {
227
                    self.data.push(carry);
228
                }
229
            }
230
        }
231
232
        #[inline]
233
0
        fn add_assign(&mut self, other: u128) {
234
0
            let (hi, lo) = big_digit::from_doublebigdigit(other);
235
0
            if hi == 0 {
236
0
                *self += lo;
237
0
            } else {
238
0
                while self.data.len() < 2 {
239
0
                    self.data.push(0);
240
0
                }
241
242
0
                let carry = __add2(&mut self.data, &[lo, hi]);
243
0
                if carry != 0 {
244
0
                    self.data.push(carry);
245
0
                }
246
            }
247
0
        }
248
    );
249
}
250
251
impl CheckedAdd for BigUint {
252
    #[inline]
253
0
    fn checked_add(&self, v: &BigUint) -> Option<BigUint> {
254
0
        Some(self.add(v))
255
0
    }
256
}
257
258
impl_sum_iter_type!(BigUint);