1use core::num::NonZeroU16;
2
3#[cfg(target_arch = "x86")]
4use core::arch::x86;
5#[cfg(target_arch = "x86_64")]
6use core::arch::x86_64 as x86;
7
8pub const GROUP_SIZE: usize = 16;
9
10pub struct GroupQuery {
11 matches: u16,
12 empty: u16,
13}
14
15impl GroupQuery {
16 #[inline]
17 pub fn from(group: &[u8; GROUP_SIZE], h2: u8) -> GroupQuery {
18 assert!(std::mem::size_of::<x86::__m128i>() == GROUP_SIZE);
19
20 unsafe {
21 let group = x86::_mm_loadu_si128(group as *const _ as *const x86::__m128i);
22 let cmp_byte = x86::_mm_cmpeq_epi8(group, x86::_mm_set1_epi8(h2 as i8));
23 let matches = x86::_mm_movemask_epi8(cmp_byte) as u16;
24 let empty = x86::_mm_movemask_epi8(group) as u16;
25
26 GroupQuery { matches, empty }
27 }
28 }
29
30 #[inline]
31 pub fn any_empty(&self) -> bool {
32 self.empty != 0
33 }
34
35 #[inline]
36 pub fn first_empty(&self) -> Option<usize> {
37 Some(NonZeroU16::new(self.empty)?.trailing_zeros() as usize)
38 }
39}
40
41impl Iterator for GroupQuery {
42 type Item = usize;
43
44 #[inline]
45 fn next(&mut self) -> Option<usize> {
46 let index: u32 = NonZeroU16::new(self.matches)?.trailing_zeros();
47
48 // Clear the lowest bit
49 // http://graphics.stanford.edu/~seander/bithacks.html#CountBitsSetKernighan
50 self.matches &= self.matches - 1;
51
52 Some(index as usize)
53 }
54}
55