Coverage Report

Created: 2026-07-16 07:16

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/rust/registry/src/index.crates.io-1949cf8c6b5b557f/num-bigint-0.4.8/src/biguint/subtraction.rs
Line
Count
Source
1
use super::BigUint;
2
3
use crate::big_digit::{self, BigDigit};
4
use crate::UsizePromotion;
5
6
use core::cmp::Ordering::{Equal, Greater, Less};
7
use core::ops::{Sub, SubAssign};
8
use num_traits::CheckedSub;
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
// Subtract with borrow:
17
#[cfg(target_arch = "x86_64")]
18
cfg_64!(
19
    #[inline]
20
    #[allow(unused_unsafe)] // TODO(MSRV 1.93): the intrinsic became safe
21
0
    fn sbb(borrow: u8, a: u64, b: u64, out: &mut u64) -> u8 {
22
        // SAFETY: There are absolutely no safety concerns with calling `_subborrow_u64`.
23
        // It's just unsafe for API consistency with other intrinsics.
24
0
        unsafe { arch::_subborrow_u64(borrow, a, b, out) }
25
0
    }
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 sbb(borrow: u8, a: u32, b: u32, out: &mut u32) -> u8 {
33
        // SAFETY: There are absolutely no safety concerns with calling `_subborrow_u32`.
34
        // It's just unsafe for API consistency with other intrinsics.
35
        unsafe { arch::_subborrow_u32(borrow, a, b, out) }
36
    }
37
);
38
39
// fallback for environments where we don't have a subborrow intrinsic
40
// (copied from the standard library's `borrowing_sub`)
41
#[cfg(not(any(target_arch = "x86", target_arch = "x86_64")))]
42
#[inline]
43
fn sbb(borrow: u8, lhs: BigDigit, rhs: BigDigit, out: &mut BigDigit) -> u8 {
44
    let (a, b) = lhs.overflowing_sub(rhs);
45
    let (c, d) = a.overflowing_sub(borrow as BigDigit);
46
    *out = c;
47
    u8::from(b || d)
48
}
49
50
0
pub(super) fn sub2(a: &mut [BigDigit], b: &[BigDigit]) {
51
0
    let mut borrow = 0;
52
53
0
    let len = Ord::min(a.len(), b.len());
54
0
    let (a_lo, a_hi) = a.split_at_mut(len);
55
0
    let (b_lo, b_hi) = b.split_at(len);
56
57
0
    for (a, b) in a_lo.iter_mut().zip(b_lo) {
58
0
        borrow = sbb(borrow, *a, *b, a);
59
0
    }
60
61
0
    if borrow != 0 {
62
0
        for a in a_hi {
63
0
            borrow = sbb(borrow, *a, 0, a);
64
0
            if borrow == 0 {
65
0
                break;
66
0
            }
67
        }
68
0
    }
69
70
    // note: we're _required_ to fail on underflow
71
0
    assert!(
72
0
        borrow == 0 && b_hi.iter().all(|x| *x == 0),
73
0
        "Cannot subtract b from a because b is larger than a."
74
    );
75
0
}
76
77
// Only for the Sub impl. `a` and `b` must have same length.
78
#[inline]
79
0
fn __sub2rev(a: &[BigDigit], b: &mut [BigDigit]) -> u8 {
80
0
    debug_assert!(b.len() == a.len());
81
82
0
    let mut borrow = 0;
83
84
0
    for (ai, bi) in a.iter().zip(b) {
85
0
        borrow = sbb(borrow, *ai, *bi, bi);
86
0
    }
87
88
0
    borrow
89
0
}
90
91
0
fn sub2rev(a: &[BigDigit], b: &mut [BigDigit]) {
92
0
    debug_assert!(b.len() >= a.len());
93
94
0
    let len = Ord::min(a.len(), b.len());
95
0
    let (a_lo, a_hi) = a.split_at(len);
96
0
    let (b_lo, b_hi) = b.split_at_mut(len);
97
98
0
    let borrow = __sub2rev(a_lo, b_lo);
99
100
0
    assert!(a_hi.is_empty());
101
102
    // note: we're _required_ to fail on underflow
103
0
    assert!(
104
0
        borrow == 0 && b_hi.iter().all(|x| *x == 0),
105
0
        "Cannot subtract b from a because b is larger than a."
106
    );
107
0
}
108
109
forward_val_val_binop!(impl Sub for BigUint, sub);
110
forward_ref_ref_binop!(impl Sub for BigUint, sub);
111
forward_val_assign!(impl SubAssign for BigUint, sub_assign);
112
113
impl Sub<&BigUint> for BigUint {
114
    type Output = BigUint;
115
116
0
    fn sub(mut self, other: &BigUint) -> BigUint {
117
0
        self -= other;
118
0
        self
119
0
    }
120
}
121
impl SubAssign<&BigUint> for BigUint {
122
0
    fn sub_assign(&mut self, other: &BigUint) {
123
0
        sub2(&mut self.data, &other.data);
124
0
        self.data.normalize();
125
0
    }
126
}
127
128
impl Sub<BigUint> for &BigUint {
129
    type Output = BigUint;
130
131
0
    fn sub(self, mut other: BigUint) -> BigUint {
132
0
        let other_len = other.data.len();
133
0
        if other_len < self.data.len() {
134
0
            let (lo, hi) = self.data.split_at(other_len);
135
0
            let lo_borrow = __sub2rev(lo, &mut other.data);
136
0
            other.data.extend_from_slice(hi);
137
0
            if lo_borrow != 0 {
138
0
                sub2(&mut other.data[other_len..], &[1])
139
0
            }
140
0
        } else {
141
0
            sub2rev(&self.data, &mut other.data);
142
0
        }
143
0
        other.data.normalize();
144
0
        other
145
0
    }
146
}
147
148
promote_unsigned_scalars!(impl Sub for BigUint, sub);
149
promote_unsigned_scalars_assign!(impl SubAssign for BigUint, sub_assign);
150
forward_all_scalar_binop_to_val_val!(impl Sub<u32> for BigUint, sub);
151
forward_all_scalar_binop_to_val_val!(impl Sub<u64> for BigUint, sub);
152
forward_all_scalar_binop_to_val_val!(impl Sub<u128> for BigUint, sub);
153
154
impl Sub<u32> for BigUint {
155
    type Output = BigUint;
156
157
    #[inline]
158
0
    fn sub(mut self, other: u32) -> BigUint {
159
0
        self -= other;
160
0
        self
161
0
    }
162
}
163
164
impl SubAssign<u32> for BigUint {
165
0
    fn sub_assign(&mut self, other: u32) {
166
0
        sub2(&mut self.data, &[other as BigDigit]);
167
0
        self.data.normalize();
168
0
    }
169
}
170
171
impl Sub<BigUint> for u32 {
172
    type Output = BigUint;
173
174
    cfg_digit!(
175
        #[inline]
176
        fn sub(self, mut other: BigUint) -> BigUint {
177
            if other.data.is_empty() {
178
                other.data.push(self);
179
            } else {
180
                sub2rev(&[self], &mut other.data);
181
            }
182
            other.data.normalize();
183
            other
184
        }
185
186
        #[inline]
187
0
        fn sub(self, mut other: BigUint) -> BigUint {
188
0
            if other.data.is_empty() {
189
0
                other.data.push(self as BigDigit);
190
0
            } else {
191
0
                sub2rev(&[self as BigDigit], &mut other.data);
192
0
            }
193
0
            other.data.normalize();
194
0
            other
195
0
        }
196
    );
197
}
198
199
impl Sub<u64> for BigUint {
200
    type Output = BigUint;
201
202
    #[inline]
203
0
    fn sub(mut self, other: u64) -> BigUint {
204
0
        self -= other;
205
0
        self
206
0
    }
207
}
208
209
impl SubAssign<u64> for BigUint {
210
    cfg_digit!(
211
        #[inline]
212
        fn sub_assign(&mut self, other: u64) {
213
            let (hi, lo) = big_digit::from_doublebigdigit(other);
214
            sub2(&mut self.data, &[lo, hi]);
215
            self.data.normalize();
216
        }
217
218
        #[inline]
219
0
        fn sub_assign(&mut self, other: u64) {
220
0
            sub2(&mut self.data, &[other as BigDigit]);
221
0
            self.data.normalize();
222
0
        }
223
    );
224
}
225
226
impl Sub<BigUint> for u64 {
227
    type Output = BigUint;
228
229
    cfg_digit!(
230
        #[inline]
231
        fn sub(self, mut other: BigUint) -> BigUint {
232
            while other.data.len() < 2 {
233
                other.data.push(0);
234
            }
235
236
            let (hi, lo) = big_digit::from_doublebigdigit(self);
237
            sub2rev(&[lo, hi], &mut other.data);
238
            other.data.normalize();
239
            other
240
        }
241
242
        #[inline]
243
0
        fn sub(self, mut other: BigUint) -> BigUint {
244
0
            if other.data.is_empty() {
245
0
                other.data.push(self);
246
0
            } else {
247
0
                sub2rev(&[self], &mut other.data);
248
0
            }
249
0
            other.data.normalize();
250
0
            other
251
0
        }
252
    );
253
}
254
255
impl Sub<u128> for BigUint {
256
    type Output = BigUint;
257
258
    #[inline]
259
0
    fn sub(mut self, other: u128) -> BigUint {
260
0
        self -= other;
261
0
        self
262
0
    }
263
}
264
265
impl SubAssign<u128> for BigUint {
266
    cfg_digit!(
267
        #[inline]
268
        fn sub_assign(&mut self, other: u128) {
269
            let (a, b, c, d) = super::u32_from_u128(other);
270
            sub2(&mut self.data, &[d, c, b, a]);
271
            self.data.normalize();
272
        }
273
274
        #[inline]
275
0
        fn sub_assign(&mut self, other: u128) {
276
0
            let (hi, lo) = big_digit::from_doublebigdigit(other);
277
0
            sub2(&mut self.data, &[lo, hi]);
278
0
            self.data.normalize();
279
0
        }
280
    );
281
}
282
283
impl Sub<BigUint> for u128 {
284
    type Output = BigUint;
285
286
    cfg_digit!(
287
        #[inline]
288
        fn sub(self, mut other: BigUint) -> BigUint {
289
            while other.data.len() < 4 {
290
                other.data.push(0);
291
            }
292
293
            let (a, b, c, d) = super::u32_from_u128(self);
294
            sub2rev(&[d, c, b, a], &mut other.data);
295
            other.data.normalize();
296
            other
297
        }
298
299
        #[inline]
300
0
        fn sub(self, mut other: BigUint) -> BigUint {
301
0
            while other.data.len() < 2 {
302
0
                other.data.push(0);
303
0
            }
304
305
0
            let (hi, lo) = big_digit::from_doublebigdigit(self);
306
0
            sub2rev(&[lo, hi], &mut other.data);
307
0
            other.data.normalize();
308
0
            other
309
0
        }
310
    );
311
}
312
313
impl CheckedSub for BigUint {
314
    #[inline]
315
0
    fn checked_sub(&self, v: &BigUint) -> Option<BigUint> {
316
0
        match self.cmp(v) {
317
0
            Less => None,
318
0
            Equal => Some(Self::ZERO),
319
0
            Greater => Some(self.sub(v)),
320
        }
321
0
    }
322
}