use proc_macro2::TokenStream;
use quote::quote;
use crate::graph::{ByteClass, State};
use super::Generator;
impl<'a> Generator<'a> {
pub fn maybe_impl_fast_loop(&mut self, state: State) -> TokenStream {
let state_data = self.graph.get_state(state);
let self_edge = state_data
.normal
.iter()
.filter(|(_bc, next_state)| next_state == &state)
.collect::<Vec<_>>();
assert!(
self_edge.len() <= 1,
"There should only be one edge going to any given state"
);
if let Some((bc, _)) = self_edge.first() {
self.impl_fast_loop(bc)
} else {
TokenStream::new()
}
}
pub fn impl_fast_loop(&mut self, self_edge: &ByteClass) -> TokenStream {
let (ident, loop_mask) = self.add_test_to_lut(self_edge);
quote! {
#[inline]
fn loop_test(byte: u8) -> bool {
#ident[byte as usize] & #loop_mask == 0
}
_fast_loop!(lex, loop_test, offset);
}
}
}
pub fn fast_loop_macro(unroll_factor: usize) -> TokenStream {
let index = (0..unroll_factor).collect::<Vec<_>>();
quote! {
macro_rules! _fast_loop {
($lex:ident, $test:ident, $offset:ident) => {
'fast_loop: {
while let Some(arr) = $lex.read::<&[u8; #unroll_factor]>($offset) {
#(if $test(arr[#index]) { $offset += #index; break 'fast_loop; })*
$offset += #unroll_factor;
}
while let Some(byte) = $lex.read::<u8>($offset) {
if $test(byte) { break 'fast_loop; }
$offset += 1;
}
}
};
}
}
}