use crate::{
AUX_CJK, Anl, CODE_CONT, Digits, Out, Span, blocks, build_block, emit, later_in_run, scanthru,
to_lead, trail_run, was, will,
};
pub(crate) const LUT: [u8; 64] = {
let mut t = [6u8; 64]; t[0x00] = 0;
t[0x10] = 0;
t[0x20] = 0;
t[0x06] = 0; t[0x30] = 0; t[0x01] = 1;
t[0x02] = 1;
t[0x31] = 1; t[0x07] = 2;
t[0x08] = 2;
t[0x09] = 2;
t[0x0A] = 2;
t[0x16] = 2;
t[0x3A] = 2; t[0x03] = 3;
t[0x04] = 4;
t[0x05] = 5; t[0x0F] = CODE_CONT;
t
};
streams!(
Cls {
lead,
cont,
cjk,
cjk_l,
cjk_p,
num,
n_raw,
lm,
lm_raw,
ps,
ws,
nl,
sp,
gap,
prefix,
}
);
#[derive(Default)]
struct Carry {
aa_run: bool, nl_run: bool, dig: Digits,
anl: Anl,
}
fn cls(
text: &[u8],
tags: &[u8],
base: usize,
len: usize,
code: u8,
cjk_in: bool,
) -> (Cls, u8, bool) {
let valid = if len == 64 { !0u64 } else { (1u64 << len) - 1 };
let (b, last_code) =
build_block::<{ AUX_CJK }, false>(text, tags, base, len, &LUT, code, cjk_in);
let (pa, pc, pd) = (!b.p2 & !b.p1, !b.p2 & b.p1, b.p2 & !b.p1);
let (lm_raw, n_raw) = (pa & !b.p0 & valid, pa & b.p0);
let (ps, nl) = (pc & !b.p0, pc & b.p0);
let (sp, ws) = (pd & !b.p0, pd | (pc & b.p0));
let cjk = b.aux;
let gap = valid & !(n_raw | lm_raw | ps | ws | cjk);
let c = Cls {
lead: valid & !b.cont,
cont: b.cont,
cjk,
cjk_l: cjk & lm_raw, cjk_p: cjk & !lm_raw,
num: n_raw & !cjk,
n_raw,
lm: lm_raw & !cjk,
lm_raw,
ps: ps & !cjk,
ws,
nl,
sp,
gap,
prefix: (ws & !nl) | gap,
};
(c, last_code, cjk >> (len - 1) & 1 != 0)
}
#[must_use]
pub fn bitcannon_deepseek(text: &[u8], tags: &[u8], starts: &mut [u64], out: &mut [Span]) -> usize {
let ntext = text.len();
if ntext == 0 {
return 0;
}
assert!(tags.len() >= ntext && starts.len() >= ntext.div_ceil(64) && out.len() >= ntext);
let nblk = ntext.div_ceil(64);
let mut cy = Carry::default();
blocks(
ntext,
&mut *starts,
None,
(CODE_CONT, false),
|base, len, (code, cjk_in)| {
let (c, last, last_cjk) = cls(text, tags, base, len, code, cjk_in);
(c, (last, last_cjk))
},
|x, starts| {
let (pv, cur, bk, fw) = (&x.pv, &x.cur, &x.bk, &x.fw);
let (valid, len) = (x.valid, x.len);
let ascii = cur.lead & x.lb;
let aa = cur.lm_raw & ascii;
let lm_start = cur.lm & cur.lead & !bk.lm & !bk.prefix;
let ws_start = cur.ws & cur.lead & !bk.ws;
let gap_start = cur.gap & cur.lead & !bk.gap;
let ps_start = cur.ps & cur.lead & !bk.ps & !bk.sp;
let cjk_start = (cur.cjk_l & cur.lead & !bk.cjk_l) | (cur.cjk_p & cur.lead & !bk.cjk_p);
let groups = cy.dig.starts(3, cur.num, cur.lead, cur.cont, was(pv.num));
let anl = bk.nl & cur.ws & cur.lead;
let later_nl = later_in_run(cur.nl, cur.ws);
let after_nl = anl & !later_nl;
let steal_lb = cur.ws & !cur.nl & x.lb & !x.eof & !fw.ws & !(fw.n_raw | fw.cjk);
let (steal, steal_patch) = to_lead(steal_lb, cur.cont, pv.cont);
let (gap_steal, gap_patch) = to_lead(cur.gap & x.lb & fw.lm, cur.cont, pv.cont);
let nb_aa = !x.last_blk && text[x.base + len].is_ascii_alphabetic();
let alt1 = ps_start & ascii & ((aa >> 1) | (u64::from(nb_aa) << 63));
let aa_m = ((alt1 as u128) << 1) | u128::from(cy.aa_run);
let aa_e = scanthru(aa_m, aa as u128);
let aa_span = aa_e.wrapping_sub(aa_m);
let nl_m = ((bk.ps & cur.nl & cur.lead) as u128) | u128::from(cy.nl_run);
let nl_e = scanthru(nl_m, cur.nl as u128);
let nl_span = nl_e.wrapping_sub(nl_m);
cy.anl.retract(starts, was(pv.ws), cur.ws, cur.nl, valid);
let mut st = groups
| lm_start
| ws_start
| gap_start
| ps_start
| cjk_start
| after_nl
| steal
| gap_steal;
st &= !(aa_span as u64) & !(nl_span as u64);
st |= aa_e as u64 | nl_e as u64;
cy.aa_run = aa_e >> 64 != 0;
cy.nl_run = nl_e >> 64 != 0;
cy.dig
.commit(3, groups, cur.num, cur.lead, valid, len, will(x.nx.num));
let tws = trail_run(cur.ws, valid, len);
cy.anl.commit(
x.base,
after_nl,
tws,
nl_e as u64,
will(x.nx.ws),
was(pv.ws),
);
Out {
st,
patch: steal_patch | gap_patch,
flag: 0,
}
},
);
emit(starts, &[], nblk, ntext, out)
}