152 lines
4.4 KiB
Rust
152 lines
4.4 KiB
Rust
pub(crate) fn shiftl(res: &mut [u64], copy: &[u64], amt: usize) {
|
|
let digits = amt / 64;
|
|
let bits = amt % 64;
|
|
|
|
let mut carry = 0;
|
|
let shift = 64 - bits;
|
|
|
|
for i in 0..res.len() {
|
|
let base = if i >= digits { copy[i-digits] } else { 0 };
|
|
let new_carry = if shift == 64 { 0 } else { base >> shift };
|
|
res[i] = (base << bits) | carry;
|
|
carry = new_carry;
|
|
}
|
|
}
|
|
|
|
pub(crate) fn shiftr(res: &mut [u64], copy: &[u64], amt: usize) {
|
|
let digits = amt / 64;
|
|
let bits = amt % 64;
|
|
|
|
let mut carry = 0;
|
|
let mask = !(0xFFFFFFFFFFFFFFFF << bits);
|
|
let shift = (64 - bits) as u32;
|
|
|
|
for (idx, val) in res.iter_mut().enumerate().rev() {
|
|
let target = idx + digits;
|
|
let base = if target >= copy.len() { 0 } else { copy[target] };
|
|
let (new_carry, _) = (base & mask).overflowing_shl(shift);
|
|
*val = (base >> bits) | carry;
|
|
carry = new_carry;
|
|
}
|
|
}
|
|
|
|
macro_rules! shift_impls
|
|
{
|
|
($name: ident, $size: expr) => {
|
|
impl ShlAssign<usize> for $name {
|
|
fn shl_assign(&mut self, amt: usize) {
|
|
let copy = self.value.clone();
|
|
shiftl(&mut self.value, ©, amt);
|
|
}
|
|
}
|
|
|
|
impl Shl<usize> for $name {
|
|
type Output = $name;
|
|
|
|
fn shl(mut self, amt: usize) -> $name {
|
|
let copy = self.value.clone();
|
|
shiftl(&mut self.value, ©, amt);
|
|
self
|
|
}
|
|
}
|
|
|
|
impl<'a> Shl<usize> for &'a $name {
|
|
type Output = $name;
|
|
|
|
fn shl(self, amt: usize) -> $name {
|
|
let mut res = $name{ value: self.value.clone() };
|
|
shiftl(&mut res.value, &self.value, amt);
|
|
res
|
|
}
|
|
}
|
|
|
|
impl ShrAssign<usize> for $name {
|
|
fn shr_assign(&mut self, amt: usize) {
|
|
let copy = self.value.clone();
|
|
shiftr(&mut self.value, ©, amt);
|
|
}
|
|
}
|
|
|
|
impl Shr<usize> for $name {
|
|
type Output = $name;
|
|
|
|
fn shr(mut self, amt: usize) -> $name {
|
|
let copy = self.value.clone();
|
|
shiftr(&mut self.value, ©, amt);
|
|
self
|
|
}
|
|
}
|
|
|
|
impl<'a> Shr<usize> for &'a $name {
|
|
type Output = $name;
|
|
|
|
fn shr(self, amt: usize) -> $name {
|
|
let mut res = $name{ value: self.value.clone() };
|
|
shiftr(&mut res.value, &self.value, amt);
|
|
res
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
#[cfg(test)]
|
|
macro_rules! generate_shiftl_tests {
|
|
($name: ident, $lname: ident) => {
|
|
#[test]
|
|
fn $lname() {
|
|
generate_shiftl_tests!(body $name, $lname);
|
|
}
|
|
};
|
|
(ignore $name: ident, $lname: ident) => {
|
|
#[test]
|
|
#[ignore]
|
|
fn $lname() {
|
|
generate_shiftl_tests!(body $name, $lname);
|
|
}
|
|
};
|
|
(body $name: ident, $lname: ident) => {
|
|
let fname = build_test_path("shiftl", stringify!($name));
|
|
run_test(fname.to_string(), 3, |case| {
|
|
let (neg0, abytes) = case.get("a").unwrap();
|
|
let (neg1, lbytes) = case.get("l").unwrap();
|
|
let (neg2, rbytes) = case.get("r").unwrap();
|
|
assert!(!neg0 && !neg1 && !neg2);
|
|
|
|
let a = $name::from_bytes(abytes);
|
|
let l = $name::from_bytes(lbytes);
|
|
let r = $name::from_bytes(rbytes);
|
|
assert_eq!(r, a << usize::from(l));
|
|
});
|
|
};
|
|
}
|
|
|
|
#[cfg(test)]
|
|
macro_rules! generate_shiftr_tests {
|
|
($name: ident, $lname: ident) => {
|
|
#[test]
|
|
fn $lname() {
|
|
generate_shiftr_tests!(body $name, $lname);
|
|
}
|
|
};
|
|
(ignore $name: ident, $lname: ident) => {
|
|
#[test]
|
|
#[ignore]
|
|
fn $lname() {
|
|
generate_shiftr_tests!(body $name, $lname);
|
|
}
|
|
};
|
|
(body $name: ident, $lname: ident) => {
|
|
let fname = build_test_path("shiftr", stringify!($name));
|
|
run_test(fname.to_string(), 3, |case| {
|
|
let (neg0, abytes) = case.get("a").unwrap();
|
|
let (neg1, lbytes) = case.get("l").unwrap();
|
|
let (neg2, rbytes) = case.get("r").unwrap();
|
|
assert!(!neg0 && !neg1 && !neg2);
|
|
|
|
let a = $name::from_bytes(abytes);
|
|
let l = $name::from_bytes(lbytes);
|
|
let r = $name::from_bytes(rbytes);
|
|
assert_eq!(r, a >> usize::from(l));
|
|
});
|
|
};
|
|
} |