| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282 |
- //! Bit shift operators.
- use crate::arch::word::Word;
- use crate::buffer::Buffer;
- use crate::ibig::IBig;
- use crate::primitive::{double_word, extend_word, split_double_word, WORD_BITS_USIZE};
- use crate::shift;
- use crate::sign::Sign::*;
- use crate::ubig::Repr::*;
- use crate::ubig::UBig;
- use core::mem;
- use core::ops::{Shl, ShlAssign, Shr, ShrAssign};
- macro_rules! impl_shifts {
- ($t:ty) => {
- impl Shl<&usize> for $t {
- type Output = $t;
- #[inline]
- fn shl(self, rhs: &usize) -> $t {
- self.shl(*rhs)
- }
- }
- impl Shl<&usize> for &$t {
- type Output = $t;
- #[inline]
- fn shl(self, rhs: &usize) -> $t {
- self.shl(*rhs)
- }
- }
- impl ShlAssign<usize> for $t {
- #[inline]
- fn shl_assign(&mut self, rhs: usize) {
- *self = mem::take(self) << rhs;
- }
- }
- impl ShlAssign<&usize> for $t {
- #[inline]
- fn shl_assign(&mut self, rhs: &usize) {
- *self = mem::take(self) << rhs;
- }
- }
- impl Shr<&usize> for $t {
- type Output = $t;
- #[inline]
- fn shr(self, rhs: &usize) -> $t {
- self.shr(*rhs)
- }
- }
- impl Shr<&usize> for &$t {
- type Output = $t;
- #[inline]
- fn shr(self, rhs: &usize) -> $t {
- self.shr(*rhs)
- }
- }
- impl ShrAssign<usize> for $t {
- #[inline]
- fn shr_assign(&mut self, rhs: usize) {
- *self = mem::take(self).shr(rhs);
- }
- }
- impl ShrAssign<&usize> for $t {
- #[inline]
- fn shr_assign(&mut self, rhs: &usize) {
- *self = mem::take(self).shr(rhs);
- }
- }
- };
- }
- impl_shifts!(UBig);
- impl_shifts!(IBig);
- impl Shl<usize> for UBig {
- type Output = UBig;
- #[inline]
- fn shl(self, rhs: usize) -> UBig {
- match self.into_repr() {
- Small(0) => UBig::from_word(0),
- Small(word) => UBig::shl_word(word, rhs),
- Large(buffer) => UBig::shl_large(buffer, rhs),
- }
- }
- }
- impl Shl<usize> for &UBig {
- type Output = UBig;
- #[inline]
- fn shl(self, rhs: usize) -> UBig {
- match self.repr() {
- Small(0) => UBig::from_word(0),
- Small(word) => UBig::shl_word(*word, rhs),
- Large(buffer) => UBig::shl_ref_large(buffer, rhs),
- }
- }
- }
- impl Shr<usize> for UBig {
- type Output = UBig;
- #[inline]
- fn shr(self, rhs: usize) -> UBig {
- match self.into_repr() {
- Small(word) => UBig::shr_word(word, rhs),
- Large(buffer) => UBig::shr_large(buffer, rhs),
- }
- }
- }
- impl Shr<usize> for &UBig {
- type Output = UBig;
- #[inline]
- fn shr(self, rhs: usize) -> UBig {
- match self.repr() {
- Small(word) => UBig::shr_word(*word, rhs),
- Large(buffer) => UBig::shr_large_ref(buffer, rhs),
- }
- }
- }
- impl Shl<usize> for IBig {
- type Output = IBig;
- #[inline]
- fn shl(self, rhs: usize) -> IBig {
- let (sign, mag) = self.into_sign_magnitude();
- IBig::from_sign_magnitude(sign, mag.shl(rhs))
- }
- }
- impl Shl<usize> for &IBig {
- type Output = IBig;
- #[inline]
- fn shl(self, rhs: usize) -> IBig {
- let (sign, mag) = (self.sign(), self.magnitude());
- IBig::from_sign_magnitude(sign, mag.shl(rhs))
- }
- }
- impl Shr<usize> for IBig {
- type Output = IBig;
- #[inline]
- fn shr(self, rhs: usize) -> IBig {
- let (sign, mag) = self.into_sign_magnitude();
- match sign {
- Positive => IBig::from(mag.shr(rhs)),
- Negative => {
- let b = mag.are_low_bits_nonzero(rhs);
- -IBig::from(mag.shr(rhs)) - IBig::from(b)
- }
- }
- }
- }
- impl Shr<usize> for &IBig {
- type Output = IBig;
- #[inline]
- fn shr(self, rhs: usize) -> IBig {
- let (sign, mag) = (self.sign(), self.magnitude());
- match sign {
- Positive => IBig::from(mag.shr(rhs)),
- Negative => {
- let b = mag.are_low_bits_nonzero(rhs);
- -IBig::from(mag.shr(rhs)) - IBig::from(b)
- }
- }
- }
- }
- impl UBig {
- /// Shift left one non-zero `Word` by `rhs` bits.
- #[inline]
- fn shl_word(word: Word, rhs: usize) -> UBig {
- debug_assert!(word != 0);
- if rhs <= WORD_BITS_USIZE {
- UBig::from(extend_word(word) << rhs)
- } else {
- UBig::shl_word_slow(word, rhs)
- }
- }
- /// Shift left one non-zero `Word` by `rhs` bits.
- fn shl_word_slow(word: Word, rhs: usize) -> UBig {
- let shift_words = rhs / WORD_BITS_USIZE;
- let shift_bits = (rhs % WORD_BITS_USIZE) as u32;
- let (lo, hi) = split_double_word(extend_word(word) << shift_bits);
- let mut buffer = Buffer::allocate(shift_words + 2);
- buffer.push_zeros(shift_words);
- buffer.push(lo);
- buffer.push(hi);
- buffer.into()
- }
- /// Shift left `buffer` by `rhs` bits.
- fn shl_large(mut buffer: Buffer, rhs: usize) -> UBig {
- let shift_words = rhs / WORD_BITS_USIZE;
- if buffer.capacity() < buffer.len() + shift_words + 1 {
- return UBig::shl_ref_large(&buffer, rhs);
- }
- let shift_bits = (rhs % WORD_BITS_USIZE) as u32;
- let carry = shift::shl_in_place(&mut buffer, shift_bits);
- buffer.push(carry);
- buffer.push_zeros_front(shift_words);
- buffer.into()
- }
- /// Shift left large number of words by `rhs` bits.
- fn shl_ref_large(words: &[Word], rhs: usize) -> UBig {
- let shift_words = rhs / WORD_BITS_USIZE;
- let shift_bits = (rhs % WORD_BITS_USIZE) as u32;
- let mut buffer = Buffer::allocate(shift_words + words.len() + 1);
- buffer.push_zeros(shift_words);
- buffer.extend(words);
- let carry = shift::shl_in_place(&mut buffer[shift_words..], shift_bits);
- buffer.push(carry);
- buffer.into()
- }
- /// Shift right one `Word` by `rhs` bits.
- #[inline]
- fn shr_word(word: Word, rhs: usize) -> UBig {
- let word = if rhs < WORD_BITS_USIZE {
- word >> rhs
- } else {
- 0
- };
- UBig::from_word(word)
- }
- /// Shift right `buffer` by `rhs` bits.
- fn shr_large(mut buffer: Buffer, rhs: usize) -> UBig {
- let shift_words = rhs / WORD_BITS_USIZE;
- if shift_words >= buffer.len() {
- return UBig::from_word(0);
- }
- let shift_bits = (rhs % WORD_BITS_USIZE) as u32;
- buffer.erase_front(shift_words);
- shift::shr_in_place(&mut buffer, shift_bits);
- buffer.into()
- }
- /// Shift right large number of words by `rhs` bits.
- fn shr_large_ref(words: &[Word], rhs: usize) -> UBig {
- let shift_words = rhs / WORD_BITS_USIZE;
- let shift_bits = (rhs % WORD_BITS_USIZE) as u32;
- let words = &words[shift_words.min(words.len())..];
- match words {
- [] => UBig::from_word(0),
- &[w] => UBig::from_word(w >> shift_bits),
- &[lo, hi] => UBig::from(double_word(lo, hi) >> shift_bits),
- _ => {
- let mut buffer = Buffer::allocate(words.len());
- buffer.extend(words);
- shift::shr_in_place(&mut buffer, shift_bits);
- buffer.into()
- }
- }
- }
- }
|