dashu_int/
shift.rs

1//! Bit shift functions.
2
3use crate::{
4    arch::word::Word,
5    math::shr_word,
6    primitive::{extend_word, split_dword, WORD_BITS},
7};
8
9/// Shift left by less than WORD_BITS in place.
10/// Returns carry.
11pub fn shl_in_place(words: &mut [Word], shift: u32) -> Word {
12    debug_assert!(shift < WORD_BITS);
13    if shift == 0 {
14        return 0;
15    }
16    let mut carry = 0;
17    for word in words {
18        let (new_word, new_carry) = split_dword(extend_word(*word) << shift);
19        *word = new_word | carry;
20        carry = new_carry;
21    }
22    carry
23}
24
25/// Shift right by at most WORD_BITS in place.
26/// Returns shifted bits in the high bits of a Word.
27#[inline]
28pub fn shr_in_place(words: &mut [Word], shift: u32) -> Word {
29    debug_assert!(shift <= WORD_BITS);
30    if shift == WORD_BITS {
31        shr_in_place_one_word(words)
32    } else {
33        shr_in_place_with_carry(words, shift, 0)
34    }
35}
36
37/// Shift right by less than WORD_BITS in place.
38/// An optional carry could be provided from a higher word.
39/// Returns shifted bits in the high bits of a Word.
40pub fn shr_in_place_with_carry(words: &mut [Word], shift: u32, mut carry: Word) -> Word {
41    debug_assert!(shift < WORD_BITS);
42    if shift == 0 {
43        debug_assert_eq!(carry, 0);
44        return 0;
45    }
46    for word in words.iter_mut().rev() {
47        let (new_word, new_carry) = shr_word(*word, shift);
48        *word = new_word | carry;
49        carry = new_carry;
50    }
51    carry
52}
53
54/// Shift right by WORD_BITS in place
55pub fn shr_in_place_one_word(words: &mut [Word]) -> Word {
56    // SAFETY: the ptr and len all comes from the slice, so it's safe
57    unsafe {
58        let ptr = words.as_mut_ptr();
59        let rem = ptr.read();
60        ptr.copy_from(ptr.add(1), words.len() - 1);
61        ptr.add(words.len() - 1).write(0);
62        rem
63    }
64}