1use super::add::{read, read_small, write, write_small};
22use super::cmp::parts;
23use super::mul::mul_1_bytes;
24use super::{ByteOrder, Number};
25use core::cell::Cell;
26use core::mem;
27use core::ops::{Add, AddAssign, Div, DivAssign, Mul, MulAssign, Rem, RemAssign, Sub, SubAssign};
28
29thread_local! {
30 static SCRATCH: Cell<Vec<u8>> = const { Cell::new(Vec::new()) };
33}
34
35#[inline(always)]
40fn with_number<R>(negative: bool, m: u128, order: ByteOrder, f: impl FnOnce(&Number) -> R) -> R {
41 let mut value = SCRATCH.take();
42 value.clear();
43 let len = 16 - (m | 1).leading_zeros() as usize / 8;
44 match order {
45 ByteOrder::BigEndian => value.extend_from_slice(&m.to_be_bytes()[16 - len..]),
46 ByteOrder::LittleEndian => value.extend_from_slice(&m.to_le_bytes()[..len]),
47 }
48 let n = Number {
49 value,
50 negative: negative && m != 0,
51 byte_order: order,
52 };
53 let result = f(&n);
54 SCRATCH.set(n.value);
55 result
56}
57
58#[inline(always)]
61fn significant_copy(a: &Number, spare: usize) -> Number {
62 let s = a.significant();
63 let bytes = if a.byte_order == ByteOrder::BigEndian {
64 &a.value[a.value.len() - s..]
65 } else {
66 &a.value[..s]
67 };
68 let mut value = Vec::with_capacity(s + spare);
69 value.extend_from_slice(bytes);
70 Number {
71 value,
72 negative: a.negative && s != 0,
73 byte_order: a.byte_order,
74 }
75}
76
77#[inline(never)]
86fn add_in_place(a: &mut Number, negative: bool, m: u128) {
87 let s = a.significant();
88 let be = a.byte_order == ByteOrder::BigEndian;
89 if s <= 16 {
90 let start = if be { a.value.len() - s } else { 0 };
91 let x = unsafe { read_small(&a.value[start..start + s], a.byte_order) };
93 let negative_a = a.negative && s != 0;
94 let (magnitude, carry, sign) = if negative_a == negative {
95 let (sum, carry) = x.overflowing_add(m);
96 (sum, carry, negative_a)
97 } else if x >= m {
98 (x - m, false, negative_a)
99 } else {
100 (m - x, false, negative)
101 };
102 let len = if carry {
103 17
104 } else {
105 16 - (magnitude | 1).leading_zeros() as usize / 8
106 };
107 a.value.clear();
108 a.value.reserve(len);
109 unsafe {
112 write_small(
113 a.value.as_mut_ptr(),
114 a.byte_order,
115 magnitude as u64,
116 (magnitude >> 64) as u64,
117 len,
118 );
119 a.value.set_len(len);
120 }
121 a.negative = sign && (magnitude != 0 || carry);
122 return;
123 }
124 if s != a.value.len() {
125 super::sign::trim(a);
126 }
127 let subtract = a.negative != negative;
128 let v = &mut a.value;
129 let p = v.as_mut_ptr();
130 let (top_changed, carried) = unsafe {
134 let low = if be { p.add(s - 16) } else { p };
135 let x = if be {
136 u128::from_be_bytes(read(low))
137 } else {
138 u128::from_le_bytes(read(low))
139 };
140 let (y, mut c) = if subtract {
141 x.overflowing_sub(m)
142 } else {
143 x.overflowing_add(m)
144 };
145 write(low, if be { y.to_be_bytes() } else { y.to_le_bytes() });
146 let mut i = 16;
147 while c && i < s {
148 let b = if be { p.add(s - 1 - i) } else { p.add(i) };
149 (*b, c) = if subtract {
150 (*b).overflowing_sub(1)
151 } else {
152 (*b).overflowing_add(1)
153 };
154 i += 1;
155 }
156 (i >= s - 1, c)
157 };
158 if carried {
159 if be {
161 v.insert(0, 1);
162 } else {
163 v.push(1);
164 }
165 } else if subtract && top_changed {
166 super::sign::trim(a);
167 }
168}
169
170#[inline(always)]
177unsafe fn small_product(x: &[u8], order: ByteOrder, m: u64) -> ([u64; 3], usize) {
178 let x = unsafe { read_small(x, order) };
180 let low = u128::from(x as u64) * u128::from(m);
181 let high = u128::from((x >> 64) as u64) * u128::from(m) + (low >> 64);
182 let limbs = [low as u64, high as u64, (high >> 64) as u64];
183 let len = if limbs[2] != 0 {
184 24 - limbs[2].leading_zeros() as usize / 8
185 } else {
186 16 - ((u128::from(limbs[1]) << 64) | u128::from(limbs[0]) | 1).leading_zeros() as usize / 8
187 };
188 (limbs, len)
189}
190
191#[inline(always)]
197unsafe fn write_small_product(p: *mut u8, order: ByteOrder, [l0, l1, l2]: [u64; 3], len: usize) {
198 unsafe {
201 if len <= 16 {
202 write_small(p, order, l0, l1, len);
203 } else if order == ByteOrder::BigEndian {
204 write(p.add(len - 8), l0.to_be_bytes());
205 write(p.add(len - 16), l1.to_be_bytes());
206 write_small(p, order, l2, 0, len - 16);
207 } else {
208 write(p, l0.to_le_bytes());
209 write(p.add(8), l1.to_le_bytes());
210 write_small(p.add(16), order, l2, 0, len - 16);
211 }
212 }
213}
214
215#[inline(always)]
217fn significant_bytes(a: &Number, s: usize) -> &[u8] {
218 if a.byte_order == ByteOrder::BigEndian {
219 &a.value[a.value.len() - s..]
220 } else {
221 &a.value[..s]
222 }
223}
224
225#[inline(always)]
233unsafe fn limbs_le(dst: *mut u8, x: *const u8, s: usize, m: u64) -> u64 {
234 unsafe { mul_1_bytes(dst, x, s / 8, m) }
236}
237
238#[inline(always)]
243fn top_le(x: &[u8], m: u64, carry: u64) -> (u128, usize) {
244 let top = x[x.len() / 8 * 8..]
245 .iter()
246 .rev()
247 .fold(0u64, |t, &b| (t << 8) | u64::from(b));
248 let top = u128::from(top) * u128::from(m) + u128::from(carry);
249 (top, (128 - top.leading_zeros() as usize).div_ceil(8))
250}
251
252#[inline(never)]
264fn mul_in_place(a: &mut Number, negative: bool, m: u64, donor: Option<&mut Vec<u8>>) -> bool {
265 let s = a.significant();
266 let order = a.byte_order;
267 let sign = a.negative != negative;
268 if s == 0 || m == 0 {
269 place(a, donor, 1);
270 a.value.clear();
271 a.value.push(0);
272 a.negative = false;
273 return true;
274 }
275 if s <= 16 {
276 let (limbs, len) = unsafe { small_product(significant_bytes(a, s), order, m) };
278 place(a, donor, len);
279 a.value.clear();
280 unsafe {
283 write_small_product(a.value.as_mut_ptr(), order, limbs, len);
284 a.value.set_len(len);
285 }
286 a.negative = sign;
287 return true;
288 }
289 if order == ByteOrder::BigEndian {
290 return false;
291 }
292 a.value.truncate(s);
293 let p = a.value.as_mut_ptr();
294 let carry = unsafe { limbs_le(p, p, s, m) };
297 let (top, t) = top_le(&a.value, m, carry);
298 let full = s / 8 * 8;
299 place(a, donor, full + t);
300 a.value.truncate(full);
301 a.value.extend_from_slice(&top.to_le_bytes()[..t]);
302 a.negative = sign;
303 true
304}
305
306#[inline(never)]
310fn mul_into(a: &Number, negative: bool, m: u64, donor: Option<&mut Vec<u8>>) -> Option<Number> {
311 let s = a.significant();
312 let order = a.byte_order;
313 if s == 0 || m == 0 || s <= 16 {
314 let (limbs, len) = if s == 0 || m == 0 {
316 ([0; 3], 1)
317 } else {
318 unsafe { small_product(significant_bytes(a, s), order, m) }
320 };
321 let mut value = match donor {
322 Some(d) if d.capacity() >= len => mem::take(d),
323 _ => Vec::with_capacity(len),
324 };
325 value.clear();
326 unsafe {
329 write_small_product(value.as_mut_ptr(), order, limbs, len);
330 value.set_len(len);
331 }
332 return Some(Number {
333 value,
334 negative: (a.negative && s != 0) != negative && len > 0 && limbs != [0; 3],
335 byte_order: order,
336 });
337 }
338 if order == ByteOrder::BigEndian {
339 return None;
340 }
341 let x = significant_bytes(a, s);
342 let most = s + 8 - m.leading_zeros() as usize / 8;
346 let mut value = match donor {
347 Some(d) if d.capacity() >= s => mem::take(d),
348 _ => Vec::with_capacity(most),
349 };
350 value.clear();
351 let full = s / 8 * 8;
352 unsafe {
355 let carry = limbs_le(value.as_mut_ptr(), x.as_ptr(), s, m);
356 value.set_len(full);
357 let (top, t) = top_le(x, m, carry);
358 if value.capacity() < full + t {
359 let mut v = Vec::with_capacity(most);
361 v.extend_from_slice(&value);
362 value = v;
363 }
364 value.extend_from_slice(&top.to_le_bytes()[..t]);
365 }
366 Some(Number {
367 value,
368 negative: (a.negative && s != 0) != negative,
369 byte_order: order,
370 })
371}
372
373#[inline(always)]
377fn place(a: &mut Number, donor: Option<&mut Vec<u8>>, len: usize) {
378 if a.value.capacity() >= len {
379 return;
380 }
381 match donor {
382 Some(d) if d.capacity() >= len => {
383 d.clear();
384 d.extend_from_slice(&a.value);
385 mem::swap(&mut a.value, d);
386 }
387 _ => a.value.reserve_exact(len - a.value.len()),
388 }
389}
390
391#[inline(always)]
394pub(super) fn times_limb(
395 a: &mut Number,
396 negative: bool,
397 m: u64,
398 donor: Option<&mut Vec<u8>>,
399) -> bool {
400 mul_in_place(a, negative, m, donor)
401}
402
403#[inline(always)]
406pub(super) fn copy_times_limb(
407 a: &Number,
408 negative: bool,
409 m: u64,
410 donor: Option<&mut Vec<u8>>,
411) -> Option<Number> {
412 mul_into(a, negative, m, donor)
413}
414
415#[inline(always)]
420fn add_assign(a: &mut Number, negative: bool, m: u128) {
421 add_in_place(a, negative, m);
422}
423
424#[inline(always)]
426fn add_ref(a: &Number, negative: bool, m: u128) -> Number {
427 let mut sum = significant_copy(a, 17);
428 add_in_place(&mut sum, negative, m);
429 sum
430}
431
432#[inline(always)]
434fn sub_assign(a: &mut Number, negative: bool, m: u128) {
435 add_in_place(a, !negative, m);
436}
437
438#[inline(always)]
440fn sub_ref(a: &Number, negative: bool, m: u128) -> Number {
441 add_ref(a, !negative, m)
442}
443
444#[inline(always)]
447fn mul_assign(a: &mut Number, negative: bool, m: u128) {
448 if m >> 64 != 0 || !mul_in_place(a, negative, m as u64, None) {
449 with_number(negative, m, ByteOrder::LittleEndian, |b| *a *= b);
450 }
451}
452
453#[inline(always)]
456fn mul_ref(a: &Number, negative: bool, m: u128) -> Number {
457 if m >> 64 == 0
458 && let Some(product) = mul_into(a, negative, m as u64, None)
459 {
460 return product;
461 }
462 with_number(negative, m, ByteOrder::LittleEndian, |b| a * b)
463}
464
465#[inline(always)]
467#[track_caller]
468fn div_assign(a: &mut Number, negative: bool, m: u128) {
469 with_number(negative, m, ByteOrder::LittleEndian, |b| *a /= b);
470}
471
472#[inline(always)]
474#[track_caller]
475fn div_ref(a: &Number, negative: bool, m: u128) -> Number {
476 with_number(negative, m, ByteOrder::LittleEndian, |b| a / b)
477}
478
479#[inline(always)]
482#[track_caller]
483fn rem_assign(a: &mut Number, negative: bool, m: u128) {
484 with_number(negative, m, ByteOrder::LittleEndian, |b| *a %= b);
485}
486
487#[inline(always)]
489#[track_caller]
490fn rem_ref(a: &Number, negative: bool, m: u128) -> Number {
491 with_number(negative, m, ByteOrder::LittleEndian, |b| a % b)
492}
493
494macro_rules! right {
498 ($op:ident $f:ident $assign:ident $f_assign:ident $sym:literal $assign_f:ident $ref_f:ident: $($t:ident),*) => {$(
499 impl $op<$t> for &Number {
500 type Output = Number;
501
502 #[doc = concat!("Returns `self ", $sym, " rhs`, as with `rhs` a number.")]
503 #[inline]
504 #[track_caller]
505 fn $f(self, rhs: $t) -> Number {
506 let (negative, m) = parts!(rhs, $t);
507 $ref_f(self, negative, m)
508 }
509 }
510
511 impl $op<$t> for Number {
512 type Output = Number;
513
514 #[doc = concat!("Returns `self ", $sym, " rhs`, as with `rhs` a number, in the vector of `self` when it has room.")]
515 #[inline]
516 #[track_caller]
517 fn $f(mut self, rhs: $t) -> Number {
518 let (negative, m) = parts!(rhs, $t);
519 $assign_f(&mut self, negative, m);
520 self
521 }
522 }
523
524 impl $assign<$t> for Number {
525 #[doc = concat!("Makes `self` `self ", $sym, " rhs`, as with `rhs` a number, in the vector of `self` when it has room.")]
526 #[inline]
527 #[track_caller]
528 fn $f_assign(&mut self, rhs: $t) {
529 let (negative, m) = parts!(rhs, $t);
530 $assign_f(self, negative, m);
531 }
532 }
533 )*};
534}
535
536macro_rules! left_commutative {
539 ($op:ident $f:ident $sym:literal: $($t:ident),*) => {$(
540 impl $op<Number> for $t {
541 type Output = Number;
542
543 #[doc = concat!("Returns `self ", $sym, " rhs`, as `rhs ", $sym, " self`, in the vector of `rhs` when it has room.")]
544 #[inline]
545 fn $f(self, rhs: Number) -> Number {
546 rhs.$f(self)
547 }
548 }
549
550 impl $op<&Number> for $t {
551 type Output = Number;
552
553 #[doc = concat!("Returns `self ", $sym, " rhs`, as `rhs ", $sym, " self`.")]
554 #[inline]
555 fn $f(self, rhs: &Number) -> Number {
556 rhs.$f(self)
557 }
558 }
559 )*};
560}
561
562macro_rules! left {
565 ($($t:ident),*) => {$(
566 impl Sub<Number> for $t {
567 type Output = Number;
568
569 #[inline]
571 fn sub(self, rhs: Number) -> Number {
572 -(rhs - self)
573 }
574 }
575
576 impl Sub<&Number> for $t {
577 type Output = Number;
578
579 #[inline]
581 fn sub(self, rhs: &Number) -> Number {
582 -(rhs - self)
583 }
584 }
585
586 impl Div<Number> for $t {
587 type Output = Number;
588
589 #[inline]
592 #[track_caller]
593 fn div(self, rhs: Number) -> Number {
594 let (negative, m) = parts!(self, $t);
595 let order = rhs.byte_order;
596 with_number(negative, m, order, |a| a / rhs)
597 }
598 }
599
600 impl Div<&Number> for $t {
601 type Output = Number;
602
603 #[inline]
605 #[track_caller]
606 fn div(self, rhs: &Number) -> Number {
607 let (negative, m) = parts!(self, $t);
608 with_number(negative, m, rhs.byte_order, |a| a / rhs)
609 }
610 }
611
612 impl Rem<Number> for $t {
613 type Output = Number;
614
615 #[inline]
618 #[track_caller]
619 fn rem(self, rhs: Number) -> Number {
620 let (negative, m) = parts!(self, $t);
621 let order = rhs.byte_order;
622 with_number(negative, m, order, |a| a % rhs)
623 }
624 }
625
626 impl Rem<&Number> for $t {
627 type Output = Number;
628
629 #[inline]
631 #[track_caller]
632 fn rem(self, rhs: &Number) -> Number {
633 let (negative, m) = parts!(self, $t);
634 with_number(negative, m, rhs.byte_order, |a| a % rhs)
635 }
636 }
637 )*};
638}
639
640macro_rules! all {
642 ($($t:ident),*) => {
643 right!(Add add AddAssign add_assign "+" add_assign add_ref: $($t),*);
644 right!(Sub sub SubAssign sub_assign "-" sub_assign sub_ref: $($t),*);
645 right!(Mul mul MulAssign mul_assign "*" mul_assign mul_ref: $($t),*);
646 right!(Div div DivAssign div_assign "/" div_assign div_ref: $($t),*);
647 right!(Rem rem RemAssign rem_assign "%" rem_assign rem_ref: $($t),*);
648 left_commutative!(Add add "+": $($t),*);
649 left_commutative!(Mul mul "*": $($t),*);
650 left!($($t),*);
651 };
652}
653
654all!(
655 u8, u16, u32, u64, u128, usize, i8, i16, i32, i64, i128, isize
656);