use aligners::{alignment::Twice, AlignedBlock, AlignedSlice};
use cfg_if::cfg_if;
use crate::{debug, BlockAlignment};
pub struct QuoteClassifiedBlock<'a> {
pub block: &'a AlignedBlock<Twice<BlockAlignment>>,
pub within_quotes_mask: u64,
}
impl<'a> QuoteClassifiedBlock<'a> {
#[must_use]
#[inline(always)]
pub fn len(&self) -> usize {
self.block.len()
}
#[must_use]
#[inline(always)]
pub fn is_empty(&self) -> bool {
self.block.is_empty()
}
}
pub trait QuoteClassifiedIterator<'a>: Iterator<Item = QuoteClassifiedBlock<'a>> + 'a {
fn block_size() -> usize;
fn is_empty(&self) -> bool;
fn get_offset(&self) -> usize;
fn offset(&mut self, count: isize);
fn flip_quotes_bit(&mut self);
}
pub struct ResumeClassifierState<'a, I: QuoteClassifiedIterator<'a>> {
pub iter: I,
pub block: Option<ResumeClassifierBlockState<'a>>,
}
impl<'a, I: QuoteClassifiedIterator<'a>> ResumeClassifierState<'a, I> {
#[inline(always)]
pub fn get_idx(&self) -> usize {
debug!(
"iter offset: {}, block idx: {:?}",
self.iter.get_offset(),
self.block.as_ref().map(|b| b.idx)
);
self.iter.get_offset() + self.block.as_ref().map_or(0, |b| b.idx)
}
#[inline]
pub fn offset_bytes(&mut self, count: isize) {
debug_assert!(count > 0);
let count = count as usize;
let remaining_in_block = self.block.as_ref().map_or(0, |b| b.block.len() - b.idx);
match self.block.as_mut() {
Some(b) if b.block.len() - b.idx > count => {
b.idx += count;
}
_ => {
let blocks_to_advance = (count - remaining_in_block) / I::block_size();
let remainder = (self.block.as_ref().map_or(0, |b| b.idx) + count
- blocks_to_advance * I::block_size())
% I::block_size();
self.iter.offset(blocks_to_advance as isize);
let next_block = self.iter.next();
self.block = next_block.map(|b| ResumeClassifierBlockState {
block: b,
idx: remainder,
});
}
}
debug!(
"offset_bytes({count}) results in idx moved to {}",
self.get_idx()
);
}
}
pub struct ResumeClassifierBlockState<'a> {
pub block: QuoteClassifiedBlock<'a>,
pub idx: usize,
}
cfg_if! {
if #[cfg(any(doc, not(feature = "simd")))] {
mod nosimd;
use nosimd::SequentialQuoteClassifier;
use aligners::alignment;
#[must_use]
#[inline(always)]
pub fn classify_quoted_sequences(
bytes: &AlignedSlice<alignment::Twice<BlockAlignment>>,
) -> impl QuoteClassifiedIterator {
SequentialQuoteClassifier::new(bytes)
}
}
else if #[cfg(simd = "avx2")] {
mod avx2;
use avx2::Avx2QuoteClassifier;
use aligners::alignment;
#[must_use]
#[inline(always)]
pub fn classify_quoted_sequences(
bytes: &AlignedSlice<alignment::Twice<BlockAlignment>>,
) -> impl QuoteClassifiedIterator {
Avx2QuoteClassifier::new(bytes)
}
}
else {
compile_error!("Target architecture is not supported by SIMD features of this crate. Disable the default `simd` feature.");
}
}