use crate::classify::{CONT, in_mask};
use crate::{AUX_NONE, Blk, CODE_CONT, Out, Span, blocks, build_block, emit};
const fn lut<const DROP: u16, const ISOLATE: u16, const KEEP_A: u16>() -> [u8; 64] {
let mut t = [0u8; 64];
let mut i = 0;
while i < 64 {
t[i] = if in_mask(i as u8, DROP) {
3
} else if in_mask(i as u8, ISOLATE) {
2
} else if in_mask(i as u8, KEEP_A) {
1
} else {
0
};
i += 1;
}
t[CONT as usize] = CODE_CONT;
t
}
streams!(
Cls { lead, cont, dropped, isolate, keep_a, other }
);
fn cls(text: &[u8], tags: &[u8], base: usize, len: usize, lut: &[u8; 64], code: u8) -> (Cls, u8) {
let valid = if len == 64 { !0u64 } else { (1u64 << len) - 1 };
let (Blk { p0, p1, cont, .. }, last) =
build_block::<{ AUX_NONE }, false>(text, tags, base, len, lut, code, false);
let c = Cls {
lead: valid & !cont,
cont,
dropped: p1 & p0,
isolate: p1 & !p0,
keep_a: !p1 & p0,
other: !p1 & !p0 & valid,
};
(c, last)
}
#[must_use]
pub fn class_runs_into<const DROP: u16, const ISOLATE: u16, const KEEP_A: u16>(
text: &[u8],
tags: &[u8],
starts: &mut [u64],
fake: &mut [u64],
out: &mut [Span],
) -> usize {
let ntext = text.len();
if ntext == 0 {
return 0;
}
let nblk = ntext.div_ceil(64);
assert!(
tags.len() >= ntext && starts.len() >= nblk && fake.len() >= nblk && out.len() >= ntext
);
let l = lut::<DROP, ISOLATE, KEEP_A>();
blocks(
ntext,
&mut *starts,
Some(fake),
CODE_CONT,
|base, len, seed| cls(text, tags, base, len, &l, seed),
|x, _| {
let (cur, bk) = (&x.cur, &x.bk);
Out {
st: (cur.keep_a & !bk.keep_a)
| (cur.other & !bk.other)
| (cur.dropped & !bk.dropped)
| cur.isolate,
patch: 0,
flag: cur.dropped,
}
},
);
emit(starts, fake, nblk, ntext, out)
}
pub struct CharDelimiterSplit(pub char);
impl CharDelimiterSplit {
#[inline]
#[must_use]
pub fn pre_tokenize(&self, text: &[u8], _tags: &mut [u8], out: &mut [Span]) -> usize {
debug_assert!(out.len() >= text.len());
let mut buf = [0u8; 4];
let delim = self.0.encode_utf8(&mut buf).as_bytes();
let Ok(lit) = crate::literal::Literal::new(delim) else {
return 0;
};
let (n, dl) = (text.len(), delim.len());
let (mut start, mut w) = (0usize, 0usize);
for m in lit.matches(text) {
if m > start {
out[w] = Span::new(start as u32, m as u32);
w += 1;
}
start = m + dl;
}
if start < n {
out[w] = Span::new(start as u32, n as u32);
w += 1;
}
w
}
}