#[cfg(any(target_arch = "aarch64", target_arch = "x86_64"))]
#[cfg(target_arch = "aarch64")]
use super::cl100k_family::batch_masks;
#[cfg(target_arch = "x86_64")]
use super::cl100k_family::batch_masks_x86;
use super::mask::{MaskScheme, MaskState};
use super::{
decode_cp, is_ascii_ws, is_digit, is_letter, letter_end_at, scan_letters_from, scan_newlines,
scan_numbers_max3, scan_other_from,
};
use crate::pretokenize::Pretoken;
use crate::pretokenize::unicode::{self, CharClass};
pub(crate) struct Olmo3Scheme;
impl MaskScheme for Olmo3Scheme {
#[inline(always)]
fn advance(bytes: &[u8], pos: usize) -> usize {
advance_pos(bytes, pos)
}
#[cfg(target_arch = "aarch64")]
#[inline(always)]
fn batch_masks(bytes: &[u8], scan: usize) -> (u64, u64) {
let ct = unicode::ClassTable::get();
batch_masks(bytes, scan, true, move |cp| ct.class_of(cp))
}
#[cfg(target_arch = "x86_64")]
#[inline(always)]
unsafe fn batch_masks_x86<const AVX512: bool>(bytes: &[u8], scan: usize) -> (u64, u64) {
let ct = unicode::ClassTable::get();
unsafe { batch_masks_x86::<AVX512>(bytes, scan, true, move |cp| ct.class_of(cp)) }
}
}
pub struct FastOlmo3Pretokenizer<'a> {
bytes: &'a [u8],
state: MaskState,
}
impl<'a> FastOlmo3Pretokenizer<'a> {
#[inline]
pub fn new(bytes: &'a [u8]) -> Self {
Self::with_pos(bytes, 0)
}
#[inline]
pub fn with_pos(bytes: &'a [u8], pos: usize) -> Self {
Self {
bytes,
state: MaskState::new(pos),
}
}
#[inline]
pub fn pos(&self) -> usize {
self.state.pos
}
}
impl<'a> Iterator for FastOlmo3Pretokenizer<'a> {
type Item = Pretoken<'a>;
#[inline]
fn next(&mut self) -> Option<Pretoken<'a>> {
let (start, end) = self.state.next_span::<Olmo3Scheme>(self.bytes)?;
Some(Pretoken(&self.bytes[start..end]))
}
}
super::impl_mask_pretoken_spans!(FastOlmo3Pretokenizer, Olmo3Scheme);
#[inline(always)]
fn ws_token_end(bytes: &[u8], start: usize) -> usize {
let len = bytes.len();
let mut p = start;
let mut last_nl_end = 0usize; let mut last_char_start = start;
while p < len {
let b = unsafe { *bytes.get_unchecked(p) };
if b == b'\r' || b == b'\n' {
last_char_start = p;
p += 1;
last_nl_end = p;
} else if is_ascii_ws(b) {
last_char_start = p;
p += 1;
} else if b >= 0x80 {
let (cp, l) = unsafe { decode_cp(bytes, p) };
if unicode::class_of(cp) == CharClass::Whitespace {
last_char_start = p;
p += l;
} else {
break;
}
} else {
break;
}
}
if last_nl_end != 0 {
return last_nl_end; }
if p >= len {
return p; }
if last_char_start > start {
return last_char_start; }
p }
#[inline(always)]
fn advance_pos(bytes: &[u8], pos: usize) -> usize {
let b0 = unsafe { *bytes.get_unchecked(pos) };
if is_letter(b0) {
return scan_letters_from(bytes, pos + 1);
}
if b0 == b' ' {
let Some(&b1) = bytes.get(pos + 1) else {
return pos + 1; };
if is_letter(b1) {
return scan_letters_from(bytes, pos + 2); }
if b1 < 0x80 {
if is_digit(b1) {
return pos + 1; }
if is_ascii_ws(b1) {
return ws_token_end(bytes, pos);
}
let p = scan_other_from(bytes, pos + 2);
return scan_newlines(bytes, p);
}
let (cp, l) = unsafe { decode_cp(bytes, pos + 1) };
let p1 = pos + 1 + l;
match unicode::class_of(cp) {
CharClass::Letter => return scan_letters_from(bytes, p1),
CharClass::Whitespace => return ws_token_end(bytes, pos),
CharClass::Number => return pos + 1,
CharClass::Other => {
let p = scan_other_from(bytes, p1);
return scan_newlines(bytes, p);
}
}
}
if b0 >= 0x80 {
let (cp, l) = unsafe { decode_cp(bytes, pos) };
let p0 = pos + l;
let class = unicode::class_of(cp);
if class == CharClass::Letter {
return scan_letters_from(bytes, p0);
}
if class == CharClass::Number {
return scan_numbers_max3(bytes, p0, 1);
}
if let Some(p) = letter_end_at(bytes, p0) {
return scan_letters_from(bytes, p);
}
if class == CharClass::Whitespace {
return ws_token_end(bytes, pos);
}
let p = scan_other_from(bytes, p0);
return scan_newlines(bytes, p);
}
if is_digit(b0) {
return scan_numbers_max3(bytes, pos + 1, 1);
}
if b0 == b'\'' {
match bytes.get(pos + 1).map(u8::to_ascii_lowercase) {
Some(b's' | b'd' | b'm' | b't') => return pos + 2,
Some(b'l') if bytes.get(pos + 2).map(u8::to_ascii_lowercase) == Some(b'l') => {
return pos + 3;
}
Some(b'v') if bytes.get(pos + 2).map(u8::to_ascii_lowercase) == Some(b'e') => {
return pos + 3;
}
Some(b'r') if bytes.get(pos + 2).map(u8::to_ascii_lowercase) == Some(b'e') => {
return pos + 3;
}
_ => {}
}
if bytes.get(pos + 1) == Some(&0xC5) && bytes.get(pos + 2) == Some(&0xBF) {
return pos + 3;
}
if let Some(p) = letter_end_at(bytes, pos + 1) {
return scan_letters_from(bytes, p);
}
let p = scan_other_from(bytes, pos + 1);
return scan_newlines(bytes, p);
}
if b0 == b'\r' || b0 == b'\n' {
return ws_token_end(bytes, pos);
}
if is_ascii_ws(b0) {
if let Some(p) = letter_end_at(bytes, pos + 1) {
return scan_letters_from(bytes, p);
}
return ws_token_end(bytes, pos);
}
if let Some(p) = letter_end_at(bytes, pos + 1) {
return scan_letters_from(bytes, p);
}
let p = scan_other_from(bytes, pos + 1);
scan_newlines(bytes, p)
}