use std::time::Instant;
fn build_synthetic_ifc(target_len: usize) -> Vec<u8> {
let mut out = Vec::with_capacity(target_len + 4096);
out.extend_from_slice(b"ISO-10303-21;\nHEADER;\nFILE_DESCRIPTION((''),'2;1');\nFILE_NAME('','',(''),(''),'','','');\nFILE_SCHEMA(('IFC2X3'));\nENDSEC;\nDATA;\n");
let mut id = 1u64;
let guid_alphabet: &[u8] = b"0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz_$";
while out.len() < target_len {
let g0 = guid_alphabet[(id as usize * 7) % guid_alphabet.len()];
let g1 = guid_alphabet[(id as usize * 13) % guid_alphabet.len()];
out.extend_from_slice(
format!(
"#{id}=IFCWALLSTANDARDCASE('{g0}IIIIIIIIIIIIIIIIIII{g1}',#2,'Wall',$,$,#100,#101,'Tag',$);\n"
)
.as_bytes(),
);
id += 1;
}
out.extend_from_slice(b"ENDSEC;\nEND-ISO-10303-21;\n");
out
}
fn case_sensitive_memmem(content: &[u8]) -> Option<usize> {
memchr::memmem::find(content, b"IFC4")
}
fn naive_i_anchored(content: &[u8]) -> Option<usize> {
let mut from = 0usize;
loop {
let rel = memchr::memchr2(b'I', b'i', content.get(from..)?)?;
let hit = from + rel;
from = hit + 1;
let end = hit + 4;
if end <= content.len() && content[hit..end].eq_ignore_ascii_case(b"IFC4") {
return Some(hit);
}
}
}
fn time_it<F: Fn(&[u8]) -> Option<usize>>(name: &str, content: &[u8], f: F, iters: u32) {
for _ in 0..3 {
std::hint::black_box(f(std::hint::black_box(content)));
}
let start = Instant::now();
for _ in 0..iters {
std::hint::black_box(f(std::hint::black_box(content)));
}
let elapsed = start.elapsed();
println!(
"{name:32} {:>10.3} ms/iter ({:>4} iters, total {:.1} ms)",
elapsed.as_secs_f64() * 1000.0 / iters as f64,
iters,
elapsed.as_secs_f64() * 1000.0
);
}
fn main() {
for &size_mb in &[20usize, 60, 120] {
let content = build_synthetic_ifc(size_mb * 1024 * 1024);
println!("\n--- synthetic file: {} MB, {} bytes ---", size_mb, content.len());
let iters = if size_mb <= 20 { 30 } else { 10 };
time_it("case-sensitive memmem (old)", &content, case_sensitive_memmem, iters);
time_it("naive I-anchored (worst case)", &content, naive_i_anchored, iters);
time_it(
"find_keyword, F-anchored (new)",
&content,
|c| ifc_lite_core::parser::find_keyword(c, b"IFC4"),
iters,
);
}
}