1use crate::{
4 arch::word::Word,
5 buffer::Buffer,
6 ibig::IBig,
7 primitive::{double_word, extend_word, split_double_word, WORD_BITS_USIZE},
8 shift,
9 sign::Sign::*,
10 ubig::{Repr::*, UBig},
11};
12use core::{
13 mem,
14 ops::{Shl, ShlAssign, Shr, ShrAssign},
15};
16
17macro_rules! impl_shifts {
18 ($t:ty) => {
19 impl Shl<&usize> for $t {
20 type Output = $t;
21
22 #[inline]
23 fn shl(self, rhs: &usize) -> $t {
24 self.shl(*rhs)
25 }
26 }
27
28 impl Shl<&usize> for &$t {
29 type Output = $t;
30
31 #[inline]
32 fn shl(self, rhs: &usize) -> $t {
33 self.shl(*rhs)
34 }
35 }
36
37 impl ShlAssign<usize> for $t {
38 #[inline]
39 fn shl_assign(&mut self, rhs: usize) {
40 *self = mem::take(self) << rhs;
41 }
42 }
43
44 impl ShlAssign<&usize> for $t {
45 #[inline]
46 fn shl_assign(&mut self, rhs: &usize) {
47 *self = mem::take(self) << rhs;
48 }
49 }
50
51 impl Shr<&usize> for $t {
52 type Output = $t;
53
54 #[inline]
55 fn shr(self, rhs: &usize) -> $t {
56 self.shr(*rhs)
57 }
58 }
59
60 impl Shr<&usize> for &$t {
61 type Output = $t;
62
63 #[inline]
64 fn shr(self, rhs: &usize) -> $t {
65 self.shr(*rhs)
66 }
67 }
68
69 impl ShrAssign<usize> for $t {
70 #[inline]
71 fn shr_assign(&mut self, rhs: usize) {
72 *self = mem::take(self).shr(rhs);
73 }
74 }
75
76 impl ShrAssign<&usize> for $t {
77 #[inline]
78 fn shr_assign(&mut self, rhs: &usize) {
79 *self = mem::take(self).shr(rhs);
80 }
81 }
82 };
83}
84
85impl_shifts!(UBig);
86impl_shifts!(IBig);
87
88impl Shl<usize> for UBig {
89 type Output = UBig;
90
91 #[inline]
92 fn shl(self, rhs: usize) -> UBig {
93 match self.into_repr() {
94 Small(0) => UBig::from_word(0),
95 Small(word) => UBig::shl_word(word, rhs),
96 Large(buffer) => UBig::shl_large(buffer, rhs),
97 }
98 }
99}
100
101impl Shl<usize> for &UBig {
102 type Output = UBig;
103
104 #[inline]
105 fn shl(self, rhs: usize) -> UBig {
106 match self.repr() {
107 Small(0) => UBig::from_word(0),
108 Small(word) => UBig::shl_word(*word, rhs),
109 Large(buffer) => UBig::shl_ref_large(buffer, rhs),
110 }
111 }
112}
113
114impl Shr<usize> for UBig {
115 type Output = UBig;
116
117 #[inline]
118 fn shr(self, rhs: usize) -> UBig {
119 match self.into_repr() {
120 Small(word) => UBig::shr_word(word, rhs),
121 Large(buffer) => UBig::shr_large(buffer, rhs),
122 }
123 }
124}
125
126impl Shr<usize> for &UBig {
127 type Output = UBig;
128
129 #[inline]
130 fn shr(self, rhs: usize) -> UBig {
131 match self.repr() {
132 Small(word) => UBig::shr_word(*word, rhs),
133 Large(buffer) => UBig::shr_large_ref(buffer, rhs),
134 }
135 }
136}
137
138impl Shl<usize> for IBig {
139 type Output = IBig;
140
141 #[inline]
142 fn shl(self, rhs: usize) -> IBig {
143 let (sign, mag) = self.into_sign_magnitude();
144 IBig::from_sign_magnitude(sign, mag.shl(rhs))
145 }
146}
147
148impl Shl<usize> for &IBig {
149 type Output = IBig;
150
151 #[inline]
152 fn shl(self, rhs: usize) -> IBig {
153 let (sign, mag) = (self.sign(), self.magnitude());
154 IBig::from_sign_magnitude(sign, mag.shl(rhs))
155 }
156}
157
158impl Shr<usize> for IBig {
159 type Output = IBig;
160
161 #[inline]
162 fn shr(self, rhs: usize) -> IBig {
163 let (sign, mag) = self.into_sign_magnitude();
164 match sign {
165 Positive => IBig::from(mag.shr(rhs)),
166 Negative => {
167 let b = mag.are_low_bits_nonzero(rhs);
168 -IBig::from(mag.shr(rhs)) - IBig::from(b)
169 }
170 }
171 }
172}
173
174impl Shr<usize> for &IBig {
175 type Output = IBig;
176
177 #[inline]
178 fn shr(self, rhs: usize) -> IBig {
179 let (sign, mag) = (self.sign(), self.magnitude());
180 match sign {
181 Positive => IBig::from(mag.shr(rhs)),
182 Negative => {
183 let b = mag.are_low_bits_nonzero(rhs);
184 -IBig::from(mag.shr(rhs)) - IBig::from(b)
185 }
186 }
187 }
188}
189
190impl UBig {
191 #[inline]
193 fn shl_word(word: Word, rhs: usize) -> UBig {
194 debug_assert!(word != 0);
195
196 if rhs <= WORD_BITS_USIZE {
197 UBig::from(extend_word(word) << rhs)
198 } else {
199 UBig::shl_word_slow(word, rhs)
200 }
201 }
202
203 fn shl_word_slow(word: Word, rhs: usize) -> UBig {
205 let shift_words = rhs / WORD_BITS_USIZE;
206 let shift_bits = (rhs % WORD_BITS_USIZE) as u32;
207 let (lo, hi) = split_double_word(extend_word(word) << shift_bits);
208 let mut buffer = Buffer::allocate(shift_words + 2);
209 buffer.push_zeros(shift_words);
210 buffer.push(lo);
211 buffer.push(hi);
212 buffer.into()
213 }
214
215 fn shl_large(mut buffer: Buffer, rhs: usize) -> UBig {
217 let shift_words = rhs / WORD_BITS_USIZE;
218
219 if buffer.capacity() < buffer.len() + shift_words + 1 {
220 return UBig::shl_ref_large(&buffer, rhs);
221 }
222
223 let shift_bits = (rhs % WORD_BITS_USIZE) as u32;
224 let carry = shift::shl_in_place(&mut buffer, shift_bits);
225 buffer.push(carry);
226 buffer.push_zeros_front(shift_words);
227 buffer.into()
228 }
229
230 fn shl_ref_large(words: &[Word], rhs: usize) -> UBig {
232 let shift_words = rhs / WORD_BITS_USIZE;
233 let shift_bits = (rhs % WORD_BITS_USIZE) as u32;
234
235 let mut buffer = Buffer::allocate(shift_words + words.len() + 1);
236 buffer.push_zeros(shift_words);
237 buffer.extend(words);
238 let carry = shift::shl_in_place(&mut buffer[shift_words..], shift_bits);
239 buffer.push(carry);
240 buffer.into()
241 }
242
243 #[inline]
245 fn shr_word(word: Word, rhs: usize) -> UBig {
246 let word = if rhs < WORD_BITS_USIZE {
247 word >> rhs
248 } else {
249 0
250 };
251 UBig::from_word(word)
252 }
253
254 fn shr_large(mut buffer: Buffer, rhs: usize) -> UBig {
256 let shift_words = rhs / WORD_BITS_USIZE;
257 if shift_words >= buffer.len() {
258 return UBig::from_word(0);
259 }
260 let shift_bits = (rhs % WORD_BITS_USIZE) as u32;
261 buffer.erase_front(shift_words);
262 shift::shr_in_place(&mut buffer, shift_bits);
263 buffer.into()
264 }
265
266 fn shr_large_ref(words: &[Word], rhs: usize) -> UBig {
268 let shift_words = rhs / WORD_BITS_USIZE;
269 let shift_bits = (rhs % WORD_BITS_USIZE) as u32;
270
271 let words = &words[shift_words.min(words.len())..];
272
273 match words {
274 [] => UBig::from_word(0),
275 &[w] => UBig::from_word(w >> shift_bits),
276 &[lo, hi] => UBig::from(double_word(lo, hi) >> shift_bits),
277 _ => {
278 let mut buffer = Buffer::allocate(words.len());
279 buffer.extend(words);
280 shift::shr_in_place(&mut buffer, shift_bits);
281 buffer.into()
282 }
283 }
284 }
285}