ktrs_syntax/tree/
kind_scan.rs1use super::ElementId;
4
5const CHUNK: usize = 64;
6pub(super) const MAX_WANTED: usize = 12;
8pub(super) const NEVER: u16 = u16::MAX;
10
11pub struct KindScan<'t> {
13 kinds: &'t [u16],
14 base: usize,
16 chunk: usize,
18 mask: u64,
19 wanted: [u16; MAX_WANTED],
20}
21
22impl<'t> KindScan<'t> {
23 pub(super) fn new(kinds: &'t [u16], base: usize, wanted: [u16; MAX_WANTED]) -> Self {
24 let mut scan = KindScan { kinds, base, chunk: 0, mask: 0, wanted };
25 scan.mask = scan.chunk_mask(0);
26 scan
27 }
28
29 fn chunk_mask(&self, start: usize) -> u64 {
30 let wanted = self.wanted;
31 let is_wanted = |k: u16| wanted.iter().fold(false, |a, &w| a | (w == k)) as u8;
32 let mut hits = [0u8; CHUNK];
33 match self.kinds.get(start..start + CHUNK) {
34 Some(chunk) => {
35 let chunk: &[u16; CHUNK] = chunk.try_into().unwrap();
36 for (hit, &k) in hits.iter_mut().zip(chunk) {
37 *hit = is_wanted(k);
38 }
39 }
40 None => {
41 for (hit, &k) in hits.iter_mut().zip(self.kinds.get(start..).unwrap_or(&[])) {
42 *hit = is_wanted(k);
43 }
44 }
45 }
46 let mut mask = 0;
47 for (g, bytes) in hits.chunks_exact(8).enumerate() {
48 let packed = u64::from_le_bytes(bytes.try_into().unwrap()).wrapping_mul(0x0102_0408_1020_4080) >> 56;
50 mask |= packed << (g * 8);
51 }
52 mask
53 }
54}
55
56impl Iterator for KindScan<'_> {
57 type Item = ElementId;
58
59 fn next(&mut self) -> Option<ElementId> {
60 while self.mask == 0 {
61 self.chunk += CHUNK;
62 if self.chunk >= self.kinds.len() {
63 return None;
64 }
65 self.mask = self.chunk_mask(self.chunk);
66 }
67 let bit = self.mask.trailing_zeros() as usize;
68 self.mask &= self.mask - 1;
69 Some((self.base + self.chunk + bit) as ElementId)
70 }
71}