use regexr::{Regex as RegexrRegex, RegexBuilder};
#[cfg(feature = "pcre2")]
use pcre2::bytes::Regex as Pcre2Regex;
use super::error::TokenizerError;
pub(super) enum RegexBackend {
Regexr(Box<RegexrRegex>),
Scanner(super::scanner::SpanScanner),
#[cfg(feature = "pcre2")]
Pcre2(Pcre2Regex),
}
impl RegexBackend {
pub(super) fn find_iter(&self, text: &str) -> Vec<(usize, usize)> {
let mut out = Vec::with_capacity(crate::core::pretokenizer::estimated_pieces(text));
self.find_into(text, &mut out);
out
}
pub(super) fn find_into(&self, text: &str, out: &mut Vec<(usize, usize)>) {
match self {
RegexBackend::Scanner(scan) => {
out.reserve(crate::core::pretokenizer::estimated_pieces(text));
scan(text, out);
}
RegexBackend::Regexr(regex) => {
out.extend(regex.find_iter(text).map(|m| (m.start(), m.end())))
}
#[cfg(feature = "pcre2")]
RegexBackend::Pcre2(regex) => out.extend(
regex
.find_iter(text.as_bytes())
.filter_map(|m| m.ok())
.map(|m| (m.start(), m.end())),
),
}
}
}
pub(super) fn compile_pattern(
pattern: &str,
use_pcre2: bool,
use_jit: bool,
) -> Result<RegexBackend, TokenizerError> {
#[cfg(feature = "pcre2")]
if use_pcre2 {
let mut regex_builder = pcre2::bytes::RegexBuilder::new();
if use_jit {
regex_builder.jit_if_available(true);
}
regex_builder.utf(true);
regex_builder.ucp(true);
return Ok(RegexBackend::Pcre2(regex_builder.build(pattern)?));
}
#[cfg(not(feature = "pcre2"))]
let _ = use_pcre2;
if let Some(scan) = super::scanner::for_pattern(pattern) {
return Ok(RegexBackend::Scanner(scan));
}
let regex = RegexBuilder::new(pattern).jit(use_jit).build()?;
Ok(RegexBackend::Regexr(Box::new(regex)))
}
pub(super) fn subdivide(
re: &RegexBackend,
text: &str,
spans: &[(usize, usize)],
) -> Vec<(usize, usize)> {
let mut out = Vec::with_capacity(spans.len());
for &(span_start, span_end) in spans {
let Some(piece) = text.get(span_start..span_end) else {
continue;
};
let mut last = 0;
for (start, end) in re.find_iter(piece) {
if start > last {
out.push((span_start + last, span_start + start));
}
if end > start {
out.push((span_start + start, span_start + end));
}
last = end;
}
if last < piece.len() {
out.push((span_start + last, span_end));
}
}
out
}