use super::family_gpt::{cls, contractions};
use crate::{
Anl, CODE_CONT, Digits, Out, Span, blocks, emit, fill_to_last, later_in_run, scanthru, to_lead,
trail_run, was, will,
};
#[must_use]
pub fn bitcannon_cl100k(
text: &[u8],
tags: &[u8],
starts: &mut [u64],
flag: &mut [u64],
out: &mut [Span],
) -> usize {
cl100k(text, tags, starts, flag, out, 3)
}
#[must_use]
pub fn bitcannon_qwen(
text: &[u8],
tags: &[u8],
starts: &mut [u64],
flag: &mut [u64],
out: &mut [Span],
) -> usize {
cl100k(text, tags, starts, flag, out, 1)
}
fn cl100k(
text: &[u8],
tags: &[u8],
starts: &mut [u64],
_flag: &mut [u64],
out: &mut [Span],
digit_cap: usize,
) -> usize {
let ntext = text.len();
if ntext == 0 {
return 0;
}
let nblk = ntext.div_ceil(64);
assert!(tags.len() >= ntext && starts.len() >= nblk && out.len() >= ntext);
let mut nl_run = false;
let mut dig = Digits::default();
let mut prev_osf = false; let mut anl = Anl::default();
let mut carry = (0u64, 0u64);
blocks(
ntext,
&mut *starts,
None,
CODE_CONT,
|base, len, seed| cls(text, tags, base, len, seed),
|x, starts| {
let (pv, cur, bk, fw) = (&x.pv, &x.cur, &x.bk, &x.fw);
let (valid, len, lead) = (x.valid, x.len, x.cur.lead);
let o_start = cur.other & lead & !bk.other & !bk.sp; let ws_start = cur.ws & lead & !bk.ws;
let (steal, steal_patch) =
to_lead(cur.ws & !cur.nl & x.lb & !x.eof & !fw.ws, cur.cont, pv.cont);
let after_nl = bk.nl & cur.ws & lead & !later_in_run(cur.nl, cur.ws);
let osf =
fill_to_last(((o_start << 1) | u64::from(prev_osf)) & cur.cont, cur.cont) | o_start;
let l_start =
cur.l & lead & !bk.l & !(bk.ws & !bk.nl) & !((osf << 1) | u64::from(prev_osf));
let groups = dig.starts(digit_cap, cur.n, lead, cur.cont, was(pv.n));
let nl_m = ((bk.other & cur.nl & lead) as u128) | u128::from(nl_run);
let nl_e = scanthru(nl_m, cur.nl as u128);
let nl_span = nl_e.wrapping_sub(nl_m);
anl.retract(starts, was(pv.ws), cur.ws, cur.nl, valid);
let mut st = groups | l_start | o_start | ws_start | after_nl | steal;
st &= !(nl_span as u64);
st |= nl_e as u64;
nl_run = nl_e >> 64 != 0;
dig.commit(digit_cap, groups, cur.n, lead, valid, len, will(x.nx.n));
let tws = trail_run(cur.ws, valid, len);
anl.commit(
x.base,
after_nl,
tws,
nl_e as u64,
will(x.nx.ws),
was(pv.ws),
);
prev_osf = osf >> (len - 1) & 1 != 0;
st &= lead;
if x.bi == 0 {
st |= 1;
}
let (opens, inner) = contractions(text, st, cur.apo, x.base, ntext, true, &mut carry);
st = (st & !inner) | opens;
Out {
st,
patch: steal_patch,
flag: 0,
}
},
);
emit(starts, &[], nblk, ntext, out)
}