#[doc(hidden)]
pub mod scalar;
#[cfg(target_arch = "aarch64")]
pub mod neon;
#[cfg(target_arch = "x86_64")]
#[doc(hidden)]
pub mod sse42;
#[cfg(target_arch = "x86_64")]
#[doc(hidden)]
pub mod avx2;
pub struct StructuralIndex {
pub lt_bits: Vec<u64>,
pub gt_bits: Vec<u64>,
#[allow(dead_code)]
pub len: usize,
}
impl StructuralIndex {
#[inline]
pub fn lt_positions(&self) -> BitPositionIter<'_> {
BitPositionIter { bits: &self.lt_bits, chunk: 0, current: 0 }
}
#[inline]
pub fn gt_positions(&self) -> BitPositionIter<'_> {
BitPositionIter { bits: &self.gt_bits, chunk: 0, current: 0 }
}
}
pub struct BitPositionIter<'a> {
bits: &'a [u64],
chunk: usize,
current: u64,
}
impl<'a> Iterator for BitPositionIter<'a> {
type Item = usize;
#[inline]
fn next(&mut self) -> Option<usize> {
loop {
if self.current != 0 {
let pos = self.current.trailing_zeros() as usize;
self.current &= self.current - 1; return Some((self.chunk - 1) * 64 + pos);
}
if self.chunk >= self.bits.len() {
return None;
}
self.current = self.bits[self.chunk];
self.chunk += 1;
}
}
}
pub fn classify_structural(input: &[u8]) -> StructuralIndex {
#[cfg(target_arch = "aarch64")]
{
return neon::classify_neon(input);
}
#[cfg(target_arch = "x86_64")]
{
if is_x86_feature_detected!("avx2") {
return unsafe { avx2::classify_avx2(input) };
}
if is_x86_feature_detected!("sse4.2") {
return unsafe { sse42::classify_sse42(input) };
}
return scalar::classify_scalar(input);
}
#[cfg(not(any(target_arch = "aarch64", target_arch = "x86_64")))]
{
scalar::classify_scalar(input)
}
}