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