Coverage Report

Created: 2025-02-21 07:11

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