use std::collections::HashMap;
use std::sync::{Arc, LazyLock, Mutex};
pub const INTERN_THRESHOLD: usize = 32;
pub const INTERN_CAP: usize = 8192;
static POOL: LazyLock<Mutex<HashMap<Arc<String>, Arc<String>>>> =
LazyLock::new(|| Mutex::new(HashMap::with_capacity(256)));
#[inline]
pub fn intern_short_string(s: Arc<String>) -> Arc<String> {
if s.len() > INTERN_THRESHOLD {
return s;
}
let mut pool = match POOL.lock() {
Ok(guard) => guard,
Err(_) => return s,
};
if let Some(existing) = pool.get(&s) {
return existing.clone();
}
if pool.len() >= INTERN_CAP {
return s;
}
pool.insert(s.clone(), s.clone());
s
}
#[cfg(test)]
pub(crate) fn __test_pool_len() -> usize {
POOL.lock().map(|p| p.len()).unwrap_or(0)
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_intern_short_strings_share_allocation() {
let a = intern_short_string(Arc::new("intern_test_share_name".to_string()));
let b = intern_short_string(Arc::new("intern_test_share_name".to_string()));
assert!(Arc::ptr_eq(&a, &b), "interned short strings must share allocation");
assert_eq!(&*a, "intern_test_share_name");
}
#[test]
fn test_intern_long_strings_bypass_pool() {
let long = format!("intern_test_long_{}", "x".repeat(INTERN_THRESHOLD + 1));
assert!(long.len() > INTERN_THRESHOLD);
let a = intern_short_string(Arc::new(long.clone()));
let b = intern_short_string(Arc::new(long.clone()));
assert!(!Arc::ptr_eq(&a, &b), "long strings must not be interned");
assert_eq!(&*a, &*b);
}
#[test]
fn test_intern_threshold_boundary() {
let at: String = std::iter::repeat('a').take(INTERN_THRESHOLD).collect();
let a1 = intern_short_string(Arc::new(at.clone()));
let a2 = intern_short_string(Arc::new(at.clone()));
assert!(Arc::ptr_eq(&a1, &a2), "len == threshold must intern");
let over: String = std::iter::repeat('b').take(INTERN_THRESHOLD + 1).collect();
let b1 = intern_short_string(Arc::new(over.clone()));
let b2 = intern_short_string(Arc::new(over.clone()));
assert!(!Arc::ptr_eq(&b1, &b2), "len > threshold must not intern");
}
#[test]
fn test_intern_preserves_content_across_many_calls() {
let inputs = [
"intern_test_many_a",
"intern_test_many_b",
"intern_test_many_c",
"intern_test_many_a", "intern_test_many_b", ];
let mut results = Vec::new();
for s in inputs {
results.push(intern_short_string(Arc::new(s.to_string())));
}
for (r, s) in results.iter().zip(inputs.iter()) {
assert_eq!(&***r, *s);
}
assert!(Arc::ptr_eq(&results[0], &results[3]), "dup 'a' must share Arc");
assert!(Arc::ptr_eq(&results[1], &results[4]), "dup 'b' must share Arc");
}
}