use super::{delta, EDGE_ROW0};
use crate::{lcs_len, lcs_step, LargeCtx};
#[cfg_attr(any(target_arch = "aarch64", target_arch = "x86_64"), allow(dead_code))]
#[inline(always)]
pub(crate) fn myers_step(eq: u64, vp: u64, vn: u64) -> (u64, u64) {
let sum = (eq & vp).wrapping_add(vp);
let ph = vn | !(sum | (vp | eq));
let mh = vp & (eq | !sum);
let xv = eq | vn;
let ph_s = (ph << 1) | 1;
((mh << 1) | !(xv | ph_s), ph_s & xv)
}
#[cfg_attr(target_arch = "aarch64", allow(dead_code))]
#[inline(always)]
pub(crate) fn multiword<const W: usize, I: Iterator<Item = [u64; W]>>(
m: usize,
pm_iter: I,
mut edges: Option<&mut [u8]>,
) -> isize {
let mut vp = [!0u64; W];
let mut vn = [0u64; W];
for (j, pm_row) in pm_iter.enumerate() {
let e = edges.as_ref().map_or(EDGE_ROW0, |e| e[j]);
let mut carry = e & 1 != 0;
let (mut prev_hp, mut prev_hn) = ((e >> 1 & 1) as u64, (e >> 2) as u64);
for k in 0..W {
let (pm, v_p, v_n) = (pm_row[k], vp[k], vn[k]);
let x = pm | v_n;
let (sum, nc) = (x & v_p).carrying_add(v_p, carry);
carry = nc;
let d0 = (sum ^ v_p) | x;
let hp = v_n | !(d0 | v_p);
let hn = v_p & d0;
let (hp_s, hn_s) = (hp << 1 | prev_hp, hn << 1 | prev_hn);
vp[k] = hn_s | !(d0 | hp_s);
vn[k] = hp_s & d0;
(prev_hp, prev_hn) = (hp >> 63, hn >> 63);
}
if let Some(e) = edges.as_deref_mut() {
e[j] = carry as u8 | (prev_hp as u8) << 1 | (prev_hn as u8) << 2;
}
}
delta(vp, vn, m)
}
pub(crate) fn full<F: Fn(usize) -> usize>(ctx: &LargeCtx<'_, F>) -> usize {
let (m, w) = (ctx.m, ctx.w);
let (mut vp, mut vn) = (vec![!0u64; w], vec![0u64; w]);
ctx.for_each_base(|base| {
let (mut carry, mut prev_hp, mut prev_hn) = (false, 1u64, 0u64);
for (k, (vp_k, vn_k)) in vp.iter_mut().zip(vn.iter_mut()).enumerate() {
let (pm, v_p, v_n) = (ctx.peq(base, k), *vp_k, *vn_k);
let x = pm | v_n;
let (sum, nc) = (x & v_p).carrying_add(v_p, carry);
carry = nc;
let d0 = (sum ^ v_p) | x;
let hp = v_n | !(d0 | v_p);
let hn = v_p & d0;
let (hp_s, hn_s) = (hp << 1 | prev_hp, hn << 1 | prev_hn);
*vp_k = hn_s | !(d0 | hp_s);
*vn_k = hp_s & d0;
(prev_hp, prev_hn) = (hp >> 63, hn >> 63);
}
});
vp[w - 1] &= u64::MAX >> (64 * w - m);
vn[w - 1] &= u64::MAX >> (64 * w - m);
let count = |v: &[u64]| v.iter().map(|x| x.count_ones() as usize).sum::<usize>();
ctx.n + count(&vp) - count(&vn)
}
#[cfg_attr(target_arch = "aarch64", allow(dead_code))]
pub(crate) fn lcs_full<F: Fn(usize) -> usize>(ctx: &LargeCtx<'_, F>) -> usize {
let mut s = vec![!0u64; ctx.w];
ctx.for_each_base(|base| {
lcs_step(&mut s, false, |k| ctx.peq(base, k));
});
lcs_len(&s)
}