#![allow(improper_ctypes)]
use ll::limb::Limb;
use ll::limb_ptr::{Limbs, LimbsMut};
use super::{copy_rest, same_or_separate};
#[allow(dead_code)]
unsafe fn add_n_generic(mut wp: LimbsMut, mut xp: Limbs, mut yp: Limbs,
mut n: i32) -> Limb {
let mut carry = Limb(0);
loop {
let xl = *xp;
let yl = *yp;
let (sl, c1) = xl.add_overflow(yl);
let (rl, c2) = sl.add_overflow(carry);
carry = if c1 || c2 { Limb(1) } else { Limb(0) };
*wp = rl;
n -= 1;
if n == 0 { break; }
wp = wp.offset(1);
xp = xp.offset(1);
yp = yp.offset(1);
}
carry
}
#[inline]
#[cfg(asm)]
pub unsafe fn add_n(mut wp: LimbsMut, xp: Limbs, yp: Limbs,
n: i32) -> Limb {
#[cfg(all(not(feature="fallbacks"),target_arch="x86_64"))]
extern "C" { fn ramp_add_n(wp: *mut Limb, xp: *const Limb, yp: *const Limb,
n: i32) -> Limb; }
debug_assert!(n >= 1);
debug_assert!(same_or_separate(wp, n, xp, n));
debug_assert!(same_or_separate(wp, n, yp, n));
return ramp_add_n(&mut *wp, &*xp, &*yp, n);
}
#[cfg(any(feature="fallbacks",not(asm)))]
#[inline]
pub unsafe fn add_n(wp: LimbsMut, xp: Limbs, yp: Limbs,
n: i32) -> Limb {
debug_assert!(n >= 1);
debug_assert!(same_or_separate(wp, n, xp, n));
debug_assert!(same_or_separate(wp, n, yp, n));
add_n_generic(wp, xp, yp, n)
}
#[allow(dead_code)]
unsafe fn sub_n_generic(mut wp: LimbsMut, mut xp: Limbs, mut yp: Limbs,
mut n: i32) -> Limb {
let mut carry = Limb(0);
debug_assert!(n >= 1);
debug_assert!(same_or_separate(wp, n, xp, n));
debug_assert!(same_or_separate(wp, n, yp, n));
loop {
let xl = *xp;
let yl = *yp;
let (sl, c1) = xl.sub_overflow(yl);
let (rl, c2) = sl.sub_overflow(carry);
carry = if c1 || c2 { Limb(1) } else { Limb(0) };
*wp = rl;
n -= 1;
if n == 0 { break; }
wp = wp.offset(1);
xp = xp.offset(1);
yp = yp.offset(1);
}
carry
}
#[cfg(asm)]
#[inline]
pub unsafe fn sub_n(mut wp: LimbsMut, xp: Limbs, yp: Limbs,
n: i32) -> Limb {
extern "C" {
fn ramp_sub_n(wp: *mut Limb, xp: *const Limb, yp: *const Limb,
n: i32) -> Limb;
}
ramp_sub_n(&mut *wp, &*xp, &*yp, n)
}
#[cfg(not(asm))]
#[inline]
pub unsafe fn sub_n(wp: LimbsMut, xp: Limbs, yp: Limbs,
n: i32) -> Limb {
sub_n_generic(wp, xp, yp, n)
}
macro_rules! aors {
($op:ident, $lop:ident, $f:ident) => {
#[inline]
pub unsafe fn $op(wp: LimbsMut,
xp: Limbs, xs: i32,
yp: Limbs, ys: i32) -> Limb {
debug_assert!(xs >= ys);
debug_assert!(ys >= 0);
let mut i = ys;
let carry = $f(wp, xp, yp, ys);
if carry == 1 {
loop {
if i >= xs { return Limb(1); }
let (x, carry) = Limb::$lop(*xp.offset(i as isize), Limb(1));
*wp.offset(i as isize) = x;
i += 1;
if !carry {
break;
}
}
}
if wp.as_const() != xp && i < xs {
copy_rest(xp, wp, xs, i);
}
return Limb(0);
}
}
}
aors!(add, add_overflow, add_n);
aors!(sub, sub_overflow, sub_n);
macro_rules! aors_1 {
($op:ident, $f:ident) => {
#[inline]
pub unsafe fn $op(mut wp: LimbsMut,
xp: Limbs, xs: i32,
y: Limb) -> Limb {
if xs > 0 {
let (v, mut carry) = Limb::$f(*xp, y);
*wp = v;
let mut i = 1;
while carry {
if i >= xs { return Limb(1); }
let (v, c) = Limb::$f(*xp.offset(i as isize), Limb(1));
carry = c;
*wp.offset(i as isize) = v;
i += 1;
}
}
return Limb(0);
}
}
}
aors_1!(add_1, add_overflow);
aors_1!(sub_1, sub_overflow);
#[inline(always)]
pub unsafe fn incr(mut ptr: LimbsMut, incr: Limb) {
let (x, mut carry) = (*ptr).add_overflow(incr);
*ptr = x;
while carry {
ptr = ptr.offset(1);
let (x, c) = (*ptr).add_overflow(Limb(1));
*ptr = x;
carry = c;
}
}
#[inline(always)]
pub unsafe fn decr(mut ptr: LimbsMut, decr: Limb) {
let x = *ptr;
*ptr = x - decr;
if x < decr {
loop {
ptr = ptr.offset(1);
let x = *ptr;
*ptr = x - 1;
if x != 0 { break; }
}
}
}