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
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
76macro_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 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 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 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 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 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 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
354trait 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}