dashu_int/
add_ops.rs

1//! Addition and subtraction operators.
2
3use crate::{helper_macros, ibig::IBig, ubig::UBig, Sign::*};
4use core::ops::{Add, AddAssign, Sub, SubAssign};
5
6helper_macros::forward_ubig_binop_to_repr!(impl Add, add);
7helper_macros::forward_ubig_binop_to_repr!(impl Sub, sub);
8helper_macros::impl_binop_assign_by_taking!(impl AddAssign<UBig> for UBig, add_assign, add);
9helper_macros::impl_binop_assign_by_taking!(impl SubAssign<UBig> for UBig, sub_assign, sub);
10
11macro_rules! impl_ibig_add {
12    ($sign0:ident, $mag0:ident, $sign1:ident, $mag1:ident) => {
13        match ($sign0, $sign1) {
14            (Positive, Positive) => IBig($mag0.add($mag1)),
15            (Positive, Negative) => IBig($mag0.sub_signed($mag1)),
16            (Negative, Positive) => IBig($mag1.sub_signed($mag0)),
17            (Negative, Negative) => IBig($mag0.add($mag1).with_sign(Negative)),
18        }
19    };
20}
21macro_rules! impl_ibig_sub {
22    ($sign0:ident, $mag0:ident, $sign1:ident, $mag1:ident) => {
23        match ($sign0, $sign1) {
24            (Positive, Positive) => IBig($mag0.sub_signed($mag1)),
25            (Positive, Negative) => IBig($mag0.add($mag1)),
26            (Negative, Positive) => IBig($mag0.add($mag1).with_sign(Negative)),
27            (Negative, Negative) => IBig($mag1.sub_signed($mag0)),
28        }
29    };
30}
31helper_macros::forward_ibig_binop_to_repr!(impl Add, add, Output = IBig, impl_ibig_add);
32helper_macros::forward_ibig_binop_to_repr!(impl Sub, sub, Output = IBig, impl_ibig_sub);
33helper_macros::impl_binop_assign_by_taking!(impl AddAssign<IBig> for IBig, add_assign, add);
34helper_macros::impl_binop_assign_by_taking!(impl SubAssign<IBig> for IBig, sub_assign, sub);
35
36macro_rules! impl_ubig_ibig_add {
37    ($mag0:ident, $sign1:ident, $mag1:ident) => {
38        match ($sign1) {
39            Positive => IBig($mag0.add($mag1)),
40            Negative => IBig($mag0.sub_signed($mag1)),
41        }
42    };
43}
44macro_rules! impl_ubig_ibig_sub {
45    ($mag0:ident, $sign1:ident, $mag1:ident) => {
46        match ($sign1) {
47            Positive => IBig($mag0.sub_signed($mag1)),
48            Negative => IBig($mag0.add($mag1)),
49        }
50    };
51}
52helper_macros::forward_ubig_ibig_binop_to_repr!(impl Add, add, Output = IBig, impl_ubig_ibig_add);
53helper_macros::forward_ubig_ibig_binop_to_repr!(impl Sub, sub, Output = IBig, impl_ubig_ibig_sub);
54
55macro_rules! impl_ibig_ubig_add {
56    ($sign0:ident, $mag0:ident, $mag1:ident) => {
57        match ($sign0) {
58            Positive => IBig($mag0.add($mag1)),
59            Negative => IBig($mag1.sub_signed($mag0)),
60        }
61    };
62}
63macro_rules! impl_ibig_ubig_sub {
64    ($sign0:ident, $mag0:ident, $mag1:ident) => {
65        match ($sign0) {
66            Positive => IBig($mag0.sub_signed($mag1)),
67            Negative => IBig($mag0.add($mag1).with_sign(Negative)),
68        }
69    };
70}
71helper_macros::forward_ibig_ubig_binop_to_repr!(impl Add, add, Output = IBig, impl_ibig_ubig_add);
72helper_macros::forward_ibig_ubig_binop_to_repr!(impl Sub, sub, Output = IBig, impl_ibig_ubig_sub);
73helper_macros::impl_binop_assign_by_taking!(impl AddAssign<UBig> for IBig, add_assign, add);
74helper_macros::impl_binop_assign_by_taking!(impl SubAssign<UBig> for IBig, sub_assign, sub);
75
76// Ops with primitives
77
78macro_rules! impl_add_sub_primitive_with_ubig {
79    ($($t:ty)*) => {$(
80        helper_macros::impl_commutative_binop_with_primitive!(impl Add<$t> for UBig, add);
81        helper_macros::impl_binop_assign_with_primitive!(impl AddAssign<$t> for UBig, add_assign);
82        helper_macros::impl_commutative_binop_with_primitive!(impl Sub<$t> for UBig, sub);
83        helper_macros::impl_binop_assign_with_primitive!(impl SubAssign<$t> for UBig, sub_assign);
84    )*};
85}
86impl_add_sub_primitive_with_ubig!(u8 u16 u32 u64 u128 usize);
87
88macro_rules! impl_add_sub_primitive_with_ibig {
89    ($($t:ty)*) => {$(
90        helper_macros::impl_commutative_binop_with_primitive!(impl Add<$t> for IBig, add);
91        helper_macros::impl_binop_assign_with_primitive!(impl AddAssign<$t> for IBig, add_assign);
92        helper_macros::impl_commutative_binop_with_primitive!(impl Sub<$t> for IBig, sub);
93        helper_macros::impl_binop_assign_with_primitive!(impl SubAssign<$t> for IBig, sub_assign);
94    )*};
95}
96impl_add_sub_primitive_with_ibig!(u8 u16 u32 u64 u128 usize i8 i16 i32 i64 i128 isize);
97
98pub mod repr {
99    use super::*;
100    use crate::{
101        add,
102        arch::word::{DoubleWord, Word},
103        buffer::Buffer,
104        error::panic_negative_ubig,
105        primitive::split_dword,
106        repr::{
107            Repr,
108            TypedRepr::{self, *},
109            TypedReprRef::{self, *},
110        },
111    };
112
113    impl<'l, 'r> Add<TypedReprRef<'r>> for TypedReprRef<'l> {
114        type Output = Repr;
115        #[inline]
116        fn add(self, rhs: TypedReprRef) -> Repr {
117            match (self, rhs) {
118                (RefSmall(dword0), RefSmall(dword1)) => add_dword(dword0, dword1),
119                (RefSmall(dword0), RefLarge(words1)) => add_large_dword(words1.into(), dword0),
120                (RefLarge(words0), RefSmall(dword1)) => add_large_dword(words0.into(), dword1),
121                (RefLarge(words0), RefLarge(words1)) => {
122                    if words0.len() >= words1.len() {
123                        add_large(words0.into(), words1)
124                    } else {
125                        add_large(words1.into(), words0)
126                    }
127                }
128            }
129        }
130    }
131
132    impl<'l> Add<TypedRepr> for TypedReprRef<'l> {
133        type Output = Repr;
134        #[inline]
135        fn add(self, rhs: TypedRepr) -> Repr {
136            match (self, rhs) {
137                (RefSmall(dword0), Small(dword1)) => add_dword(dword0, dword1),
138                (RefSmall(dword0), Large(buffer1)) => add_large_dword(buffer1, dword0),
139                (RefLarge(words0), Small(dword1)) => add_large_dword(words0.into(), dword1),
140                (RefLarge(words0), Large(buffer1)) => add_large(buffer1, words0),
141            }
142        }
143    }
144
145    impl<'r> Add<TypedReprRef<'r>> for TypedRepr {
146        type Output = Repr;
147        #[inline]
148        fn add(self, rhs: TypedReprRef) -> Repr {
149            // add is commutative
150            rhs.add(self)
151        }
152    }
153
154    impl Add<TypedRepr> for TypedRepr {
155        type Output = Repr;
156        #[inline]
157        fn add(self, rhs: TypedRepr) -> Repr {
158            match (self, rhs) {
159                (Small(dword0), Small(dword1)) => add_dword(dword0, dword1),
160                (Small(dword0), Large(buffer1)) => add_large_dword(buffer1, dword0),
161                (Large(buffer0), Small(dword1)) => add_large_dword(buffer0, dword1),
162                (Large(buffer0), Large(buffer1)) => {
163                    if buffer0.len() >= buffer1.len() {
164                        add_large(buffer0, &buffer1)
165                    } else {
166                        add_large(buffer1, &buffer0)
167                    }
168                }
169            }
170        }
171    }
172
173    #[inline]
174    fn add_dword(a: DoubleWord, b: DoubleWord) -> Repr {
175        let (res, overflow) = a.overflowing_add(b);
176        if overflow {
177            // spilled
178            let (lo, hi) = split_dword(res);
179            let mut buffer = Buffer::allocate(3);
180            buffer.push(lo);
181            buffer.push(hi);
182            buffer.push(1);
183            Repr::from_buffer(buffer)
184        } else {
185            Repr::from_dword(res)
186        }
187    }
188
189    #[inline]
190    fn add_large_dword(mut buffer: Buffer, rhs: DoubleWord) -> Repr {
191        debug_assert!(buffer.len() >= 3);
192        if add::add_dword_in_place(&mut buffer, rhs) {
193            buffer.push_resizing(1);
194        }
195        Repr::from_buffer(buffer)
196    }
197
198    #[inline]
199    fn add_large(mut buffer: Buffer, rhs: &[Word]) -> Repr {
200        let n = buffer.len().min(rhs.len());
201        let overflow = add::add_same_len_in_place(&mut buffer[..n], &rhs[..n]);
202        if rhs.len() > n {
203            buffer.ensure_capacity(rhs.len());
204            buffer.push_slice(&rhs[n..]);
205        }
206        if overflow && add::add_one_in_place(&mut buffer[n..]) {
207            buffer.push_resizing(1);
208        }
209        Repr::from_buffer(buffer)
210    }
211
212    impl<'l, 'r> Sub<TypedReprRef<'r>> for TypedReprRef<'l> {
213        type Output = Repr;
214        #[inline]
215        fn sub(self, rhs: TypedReprRef) -> Repr {
216            match (self, rhs) {
217                (RefSmall(dword0), RefSmall(dword1)) => sub_dword(dword0, dword1),
218                (RefSmall(_), RefLarge(_)) => panic_negative_ubig(),
219                (RefLarge(buffer0), RefSmall(dword1)) => sub_large_dword(buffer0.into(), dword1),
220                (RefLarge(buffer0), RefLarge(buffer1)) => sub_large(buffer0.into(), buffer1),
221            }
222        }
223    }
224
225    impl<'r> Sub<TypedReprRef<'r>> for TypedRepr {
226        type Output = Repr;
227        #[inline]
228        fn sub(self, rhs: TypedReprRef) -> Repr {
229            match (self, rhs) {
230                (Small(dword0), RefSmall(dword1)) => sub_dword(dword0, dword1),
231                (Small(_), RefLarge(_)) => panic_negative_ubig(),
232                (Large(buffer0), RefSmall(dword1)) => sub_large_dword(buffer0, dword1),
233                (Large(buffer0), RefLarge(buffer1)) => sub_large(buffer0, buffer1),
234            }
235        }
236    }
237
238    impl<'l> Sub<TypedRepr> for TypedReprRef<'l> {
239        type Output = Repr;
240        #[inline]
241        fn sub(self, rhs: TypedRepr) -> Repr {
242            match (self, rhs) {
243                (RefSmall(dword0), Small(dword1)) => sub_dword(dword0, dword1),
244                (RefSmall(_), Large(_)) => panic_negative_ubig(),
245                (RefLarge(buffer0), Small(dword1)) => sub_large_dword(buffer0.into(), dword1),
246                (RefLarge(buffer0), Large(buffer1)) => sub_large_ref_val(buffer0, buffer1),
247            }
248        }
249    }
250
251    impl Sub<TypedRepr> for TypedRepr {
252        type Output = Repr;
253        #[inline]
254        fn sub(self, rhs: TypedRepr) -> Repr {
255            match (self, rhs) {
256                (Small(dword0), Small(dword1)) => sub_dword(dword0, dword1),
257                (Small(_), Large(_)) => panic_negative_ubig(),
258                (Large(buffer0), Small(dword1)) => sub_large_dword(buffer0, dword1),
259                (Large(buffer0), Large(buffer1)) => sub_large(buffer0, &buffer1),
260            }
261        }
262    }
263
264    #[inline]
265    fn sub_dword(a: DoubleWord, b: DoubleWord) -> Repr {
266        match a.checked_sub(b) {
267            Some(res) => Repr::from_dword(res),
268            None => panic_negative_ubig(),
269        }
270    }
271
272    #[inline]
273    pub(crate) fn sub_large_dword(mut lhs: Buffer, rhs: DoubleWord) -> Repr {
274        let overflow = add::sub_dword_in_place(&mut lhs, rhs);
275        debug_assert!(!overflow);
276        Repr::from_buffer(lhs)
277    }
278
279    #[inline]
280    pub(crate) fn sub_large(mut lhs: Buffer, rhs: &[Word]) -> Repr {
281        if lhs.len() < rhs.len() || add::sub_in_place(&mut lhs, rhs) {
282            panic_negative_ubig();
283        }
284        Repr::from_buffer(lhs)
285    }
286
287    #[inline]
288    pub(crate) fn sub_large_ref_val(lhs: &[Word], mut rhs: Buffer) -> Repr {
289        let n = rhs.len();
290        if lhs.len() < n {
291            panic_negative_ubig();
292        }
293        let borrow = add::sub_same_len_in_place_swap(&lhs[..n], &mut rhs);
294        rhs.ensure_capacity(lhs.len());
295        rhs.push_slice(&lhs[n..]);
296        if borrow && add::sub_one_in_place(&mut rhs[n..]) {
297            panic_negative_ubig();
298        }
299        Repr::from_buffer(rhs)
300    }
301
302    impl<'a> TypedReprRef<'a> {
303        /// Add one to the number
304        pub fn add_one(self) -> Repr {
305            match self {
306                RefSmall(dword) => add_dword(dword, 1),
307                RefLarge(buffer) => add_large_one(buffer.into()),
308            }
309        }
310
311        /// Subtract one from the number
312        pub fn sub_one(self) -> Repr {
313            match self {
314                RefSmall(dword) => Repr::from_dword(dword - 1),
315                RefLarge(buffer) => sub_large_one(buffer.into()),
316            }
317        }
318    }
319
320    impl TypedRepr {
321        /// Add one to the number
322        pub fn add_one(self) -> Repr {
323            match self {
324                Small(dword) => add_dword(dword, 1),
325                Large(buffer) => add_large_one(buffer),
326            }
327        }
328
329        /// Subtract one from the number
330        pub fn sub_one(self) -> Repr {
331            match self {
332                Small(dword) => Repr::from_dword(dword - 1),
333                Large(buffer) => sub_large_one(buffer),
334            }
335        }
336    }
337
338    #[inline]
339    fn add_large_one(mut buffer: Buffer) -> Repr {
340        if add::add_one_in_place(&mut buffer) {
341            buffer.push_resizing(1);
342        }
343        Repr::from_buffer(buffer)
344    }
345
346    #[inline]
347    fn sub_large_one(mut buffer: Buffer) -> Repr {
348        let overflow = add::sub_one_in_place(&mut buffer);
349        debug_assert!(!overflow);
350        Repr::from_buffer(buffer)
351    }
352}
353
354/// This trait is for internal use only, it's used for distinguishing
355/// between subtraction with sign and without sign.
356trait SubSigned<Rhs> {
357    type Output;
358    fn sub_signed(self, rhs: Rhs) -> Self::Output;
359}
360
361mod repr_signed {
362    use super::*;
363    use crate::{
364        add,
365        arch::word::{DoubleWord, Word},
366        buffer::Buffer,
367        repr::{
368            Repr,
369            TypedRepr::{self, *},
370            TypedReprRef::{self, *},
371        },
372    };
373
374    impl<'l, 'r> SubSigned<TypedReprRef<'r>> for TypedReprRef<'l> {
375        type Output = Repr;
376        #[inline]
377        fn sub_signed(self, rhs: TypedReprRef<'r>) -> Repr {
378            match (self, rhs) {
379                (RefSmall(dword0), RefSmall(dword1)) => sub_dword(dword0, dword1),
380                (RefSmall(dword0), RefLarge(buffer1)) => {
381                    sub_large_dword(buffer1.into(), dword0).neg()
382                }
383                (RefLarge(words0), RefSmall(words1)) => sub_large_dword(words0.into(), words1),
384                (RefLarge(words0), RefLarge(words1)) => {
385                    if words0.len() >= words1.len() {
386                        sub_large(words0.into(), words1)
387                    } else {
388                        sub_large(words1.into(), words0).neg()
389                    }
390                }
391            }
392        }
393    }
394
395    impl<'l> SubSigned<TypedRepr> for TypedReprRef<'l> {
396        type Output = Repr;
397        #[inline]
398        fn sub_signed(self, rhs: TypedRepr) -> Self::Output {
399            match (self, rhs) {
400                (RefSmall(dword0), Small(dword1)) => sub_dword(dword0, dword1),
401                (RefSmall(dword0), Large(buffer1)) => sub_large_dword(buffer1, dword0).neg(),
402                (RefLarge(words0), Small(dword1)) => sub_large_dword(words0.into(), dword1),
403                (RefLarge(words0), Large(buffer1)) => sub_large(buffer1, words0).neg(),
404            }
405        }
406    }
407
408    impl<'r> SubSigned<TypedReprRef<'r>> for TypedRepr {
409        type Output = Repr;
410        #[inline]
411        fn sub_signed(self, rhs: TypedReprRef) -> Self::Output {
412            match (self, rhs) {
413                (Small(dword0), RefSmall(dword1)) => sub_dword(dword0, dword1),
414                (Small(dword0), RefLarge(words1)) => sub_large_dword(words1.into(), dword0).neg(),
415                (Large(buffer0), RefSmall(dword1)) => sub_large_dword(buffer0, dword1),
416                (Large(buffer0), RefLarge(words1)) => sub_large(buffer0, words1),
417            }
418        }
419    }
420
421    impl SubSigned<TypedRepr> for TypedRepr {
422        type Output = Repr;
423        #[inline]
424        fn sub_signed(self, rhs: TypedRepr) -> Self::Output {
425            match (self, rhs) {
426                (Small(dword0), Small(dword1)) => sub_dword(dword0, dword1),
427                (Small(dword0), Large(buffer1)) => sub_large_dword(buffer1, dword0).neg(),
428                (Large(buffer0), Small(dword1)) => sub_large_dword(buffer0, dword1),
429                (Large(buffer0), Large(buffer1)) => {
430                    if buffer0.len() >= buffer1.len() {
431                        sub_large(buffer0, &buffer1)
432                    } else {
433                        sub_large(buffer1, &buffer0).neg()
434                    }
435                }
436            }
437        }
438    }
439
440    #[inline]
441    fn sub_dword(lhs: DoubleWord, rhs: DoubleWord) -> Repr {
442        let (val, overflow) = lhs.overflowing_sub(rhs);
443        if !overflow {
444            Repr::from_dword(val)
445        } else {
446            Repr::from_dword(val.wrapping_neg()).neg()
447        }
448    }
449
450    #[inline]
451    fn sub_large_dword(lhs: Buffer, rhs: DoubleWord) -> Repr {
452        super::repr::sub_large_dword(lhs, rhs)
453    }
454
455    #[inline]
456    fn sub_large(mut lhs: Buffer, rhs: &[Word]) -> Repr {
457        if lhs.len() >= rhs.len() {
458            let sign = add::sub_in_place_with_sign(&mut lhs, rhs);
459            Repr::from_buffer(lhs).with_sign(sign)
460        } else {
461            super::repr::sub_large_ref_val(rhs, lhs).with_sign(Negative)
462        }
463    }
464}