num_bigint/biguint/
shift.rs
1use super::{biguint_from_vec, BigUint};
2
3use crate::big_digit;
4use crate::std_alloc::{Cow, Vec};
5
6use core::mem;
7use core::ops::{Shl, ShlAssign, Shr, ShrAssign};
8use num_traits::{PrimInt, Zero};
9
10#[inline]
11fn biguint_shl<T: PrimInt>(n: Cow<'_, BigUint>, shift: T) -> BigUint {
12 if shift < T::zero() {
13 panic!("attempt to shift left with negative");
14 }
15 if n.is_zero() {
16 return n.into_owned();
17 }
18 let bits = T::from(big_digit::BITS).unwrap();
19 let digits = (shift / bits).to_usize().expect("capacity overflow");
20 let shift = (shift % bits).to_u8().unwrap();
21 biguint_shl2(n, digits, shift)
22}
23
24fn biguint_shl2(n: Cow<'_, BigUint>, digits: usize, shift: u8) -> BigUint {
25 let mut data = match digits {
26 0 => n.into_owned().data,
27 _ => {
28 let len = digits.saturating_add(n.data.len() + 1);
29 let mut data = Vec::with_capacity(len);
30 data.resize(digits, 0);
31 data.extend(n.data.iter());
32 data
33 }
34 };
35
36 if shift > 0 {
37 let mut carry = 0;
38 let carry_shift = big_digit::BITS as u8 - shift;
39 for elem in data[digits..].iter_mut() {
40 let new_carry = *elem >> carry_shift;
41 *elem = (*elem << shift) | carry;
42 carry = new_carry;
43 }
44 if carry != 0 {
45 data.push(carry);
46 }
47 }
48
49 biguint_from_vec(data)
50}
51
52#[inline]
53fn biguint_shr<T: PrimInt>(n: Cow<'_, BigUint>, shift: T) -> BigUint {
54 if shift < T::zero() {
55 panic!("attempt to shift right with negative");
56 }
57 if n.is_zero() {
58 return n.into_owned();
59 }
60 let bits = T::from(big_digit::BITS).unwrap();
61 let digits = (shift / bits).to_usize().unwrap_or(core::usize::MAX);
62 let shift = (shift % bits).to_u8().unwrap();
63 biguint_shr2(n, digits, shift)
64}
65
66fn biguint_shr2(n: Cow<'_, BigUint>, digits: usize, shift: u8) -> BigUint {
67 if digits >= n.data.len() {
68 let mut n = n.into_owned();
69 n.set_zero();
70 return n;
71 }
72 let mut data = match n {
73 Cow::Borrowed(n) => n.data[digits..].to_vec(),
74 Cow::Owned(mut n) => {
75 n.data.drain(..digits);
76 n.data
77 }
78 };
79
80 if shift > 0 {
81 let mut borrow = 0;
82 let borrow_shift = big_digit::BITS as u8 - shift;
83 for elem in data.iter_mut().rev() {
84 let new_borrow = *elem << borrow_shift;
85 *elem = (*elem >> shift) | borrow;
86 borrow = new_borrow;
87 }
88 }
89
90 biguint_from_vec(data)
91}
92
93macro_rules! impl_shift {
94 (@ref $Shx:ident :: $shx:ident, $ShxAssign:ident :: $shx_assign:ident, $rhs:ty) => {
95 impl<'b> $Shx<&'b $rhs> for BigUint {
96 type Output = BigUint;
97
98 #[inline]
99 fn $shx(self, rhs: &'b $rhs) -> BigUint {
100 $Shx::$shx(self, *rhs)
101 }
102 }
103 impl<'a, 'b> $Shx<&'b $rhs> for &'a BigUint {
104 type Output = BigUint;
105
106 #[inline]
107 fn $shx(self, rhs: &'b $rhs) -> BigUint {
108 $Shx::$shx(self, *rhs)
109 }
110 }
111 impl<'b> $ShxAssign<&'b $rhs> for BigUint {
112 #[inline]
113 fn $shx_assign(&mut self, rhs: &'b $rhs) {
114 $ShxAssign::$shx_assign(self, *rhs);
115 }
116 }
117 };
118 ($($rhs:ty),+) => {$(
119 impl Shl<$rhs> for BigUint {
120 type Output = BigUint;
121
122 #[inline]
123 fn shl(self, rhs: $rhs) -> BigUint {
124 biguint_shl(Cow::Owned(self), rhs)
125 }
126 }
127 impl<'a> Shl<$rhs> for &'a BigUint {
128 type Output = BigUint;
129
130 #[inline]
131 fn shl(self, rhs: $rhs) -> BigUint {
132 biguint_shl(Cow::Borrowed(self), rhs)
133 }
134 }
135 impl ShlAssign<$rhs> for BigUint {
136 #[inline]
137 fn shl_assign(&mut self, rhs: $rhs) {
138 let n = mem::replace(self, BigUint::zero());
139 *self = n << rhs;
140 }
141 }
142 impl_shift! { @ref Shl::shl, ShlAssign::shl_assign, $rhs }
143
144 impl Shr<$rhs> for BigUint {
145 type Output = BigUint;
146
147 #[inline]
148 fn shr(self, rhs: $rhs) -> BigUint {
149 biguint_shr(Cow::Owned(self), rhs)
150 }
151 }
152 impl<'a> Shr<$rhs> for &'a BigUint {
153 type Output = BigUint;
154
155 #[inline]
156 fn shr(self, rhs: $rhs) -> BigUint {
157 biguint_shr(Cow::Borrowed(self), rhs)
158 }
159 }
160 impl ShrAssign<$rhs> for BigUint {
161 #[inline]
162 fn shr_assign(&mut self, rhs: $rhs) {
163 let n = mem::replace(self, BigUint::zero());
164 *self = n >> rhs;
165 }
166 }
167 impl_shift! { @ref Shr::shr, ShrAssign::shr_assign, $rhs }
168 )*};
169}
170
171impl_shift! { u8, u16, u32, u64, u128, usize }
172impl_shift! { i8, i16, i32, i64, i128, isize }