use ll::limb::{Limb, BaseInt};
use ll::{same_or_decr, same_or_incr};
use ll::limb_ptr::{Limbs, LimbsMut};
pub unsafe fn shl(mut rp: LimbsMut, mut xp: Limbs, mut xs: i32, cnt: u32) -> Limb {
debug_assert!(xs >= 1);
debug_assert!(cnt >= 1);
debug_assert!(cnt < Limb::BITS as u32);
debug_assert!(same_or_decr(rp, xs, xp, xs));
let cnt = cnt as usize;
rp = rp.offset((xs - 1) as isize);
xp = xp.offset((xs - 1) as isize);
let inv_cnt = Limb::BITS - cnt;
let l = *xp;
let ret = l >> inv_cnt;
let mut high_limb = l << cnt;
xs -= 1;
while xs != 0 {
xp = xp.offset(-1);
let low = *xp;
*rp = high_limb | (low >> inv_cnt);
high_limb = low << cnt;
rp = rp.offset(-1);
xs -= 1;
}
*rp = high_limb;
return ret;
}
pub unsafe fn shr(mut rp: LimbsMut, mut xp: Limbs, mut xs: i32, cnt: u32) -> Limb {
debug_assert!(xs >= 1);
debug_assert!(cnt >= 1);
debug_assert!(cnt < Limb::BITS as u32);
debug_assert!(same_or_incr(rp, xs, xp, xs));
let cnt = cnt as usize;
let inv_cnt = Limb::BITS - cnt;
let h = *xp;
let ret = h << inv_cnt;
let mut low_limb = h >> cnt;
xp = xp.offset(1);
xs -= 1;
while xs != 0 {
let high = *xp;
xp = xp.offset(1);
*rp = low_limb | (high << inv_cnt);
low_limb = high >> cnt;
rp = rp.offset(1);
xs -= 1;
}
*rp = low_limb;
return ret;
}
#[inline(always)]
unsafe fn bitop<F: Fn(Limb, Limb) -> Limb>(mut wp: LimbsMut,
mut xp: Limbs, mut yp: Limbs,
n: i32, op: F) {
debug_assert!(same_or_incr(wp, n, xp, n));
debug_assert!(same_or_incr(wp, n, yp, n));
let mut i = 0;
while i < n {
*wp = op(*xp, *yp);
wp = wp.offset(1);
xp = xp.offset(1);
yp = yp.offset(1);
i += 1;
}
}
pub unsafe fn and_n(wp: LimbsMut,
xp: Limbs, yp: Limbs,
n: i32) {
bitop(wp, xp, yp, n, |x, y| x & y);
}
pub unsafe fn and_not_n(wp: LimbsMut,
xp: Limbs, yp: Limbs,
n: i32) {
bitop(wp, xp, yp, n, |x, y| x & !y);
}
pub unsafe fn nand_n(wp: LimbsMut,
xp: Limbs, yp: Limbs,
n: i32) {
bitop(wp, xp, yp, n, |x, y| !(x & y));
}
pub unsafe fn or_n(wp: LimbsMut,
xp: Limbs, yp: Limbs,
n: i32) {
bitop(wp, xp, yp, n, |x, y| x | y);
}
pub unsafe fn or_not_n(wp: LimbsMut,
xp: Limbs, yp: Limbs,
n: i32) {
bitop(wp, xp, yp, n, |x, y| x | !y);
}
pub unsafe fn nor_n(wp: LimbsMut,
xp: Limbs, yp: Limbs,
n: i32) {
bitop(wp, xp, yp, n, |x, y| !(x | y));
}
pub unsafe fn xor_n(wp: LimbsMut,
xp: Limbs, yp: Limbs,
n: i32) {
bitop(wp, xp, yp, n, |x, y| x ^ y);
}
pub unsafe fn not(mut wp: LimbsMut, mut xp: Limbs, n: i32) {
debug_assert!(same_or_incr(wp, n, xp, n));
let mut i = 0;
while i < n {
*wp = !*xp;
wp = wp.offset(1);
xp = xp.offset(1);
i += 1;
}
}
pub unsafe fn twos_complement(mut wp: LimbsMut, mut xp: Limbs, xs: i32) -> Limb {
let mut i = 0;
let mut carry = Limb(1);
while i < xs {
let flipped = !*xp;
*wp = flipped + carry;
xp = xp.offset(1);
wp = wp.offset(1);
i += 1;
carry = carry & Limb((flipped == !0) as BaseInt);
}
carry
}
pub unsafe fn scan_1(mut xp: Limbs, mut xs: i32) -> u32 {
debug_assert!(xs > 0);
let mut cnt = 0u32;
while *xp == 0 {
cnt += Limb::BITS as u32;
xp = xp.offset(1);
xs -= 1;
if xs == 0 { return cnt; }
}
cnt += (*xp).trailing_zeros() as u32;
return cnt;
}
pub unsafe fn scan_0(mut xp: Limbs, mut xs: i32) -> u32 {
debug_assert!(xs > 0);
let mut cnt = 0u32;
while *xp == !0 {
cnt += Limb::BITS as u32;
xp = xp.offset(1);
xs -= 1;
if xs == 0 { return cnt; }
}
let mut last = (*xp).0;
while last & 1 != 0 {
cnt += 1;
last >>= 1;
}
return cnt;
}