use crate::prelude::*;
use rustc_hash::FxHashMap;
#[derive(Debug, Default)]
pub struct KeyInterner {
table: FxHashMap<Arc<str>, ()>,
}
impl KeyInterner {
#[must_use]
pub fn new() -> Self {
KeyInterner {
table: FxHashMap::default(),
}
}
#[must_use]
pub fn with_capacity(capacity: usize) -> Self {
KeyInterner {
table: FxHashMap::with_capacity_and_hasher(capacity, rustc_hash::FxBuildHasher),
}
}
pub fn intern(&mut self, key: &str) -> Arc<str> {
if let Some((existing, _)) = self.table.get_key_value(key) {
return Arc::clone(existing);
}
let arc: Arc<str> = Arc::from(key);
let _ = self.table.insert(Arc::clone(&arc), ());
arc
}
#[must_use]
pub fn get(&self, key: &str) -> Option<Arc<str>> {
self.table
.get_key_value(key)
.map(|(arc, _)| Arc::clone(arc))
}
#[must_use]
pub fn len(&self) -> usize {
self.table.len()
}
#[must_use]
pub fn is_empty(&self) -> bool {
self.table.is_empty()
}
pub fn clear(&mut self) {
self.table.clear();
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn intern_returns_same_arc_for_repeated_key() {
let mut interner = KeyInterner::new();
let a = interner.intern("metadata");
let b = interner.intern("metadata");
assert!(Arc::ptr_eq(&a, &b));
assert_eq!(interner.len(), 1);
}
#[test]
fn intern_distinct_keys_get_distinct_arcs() {
let mut interner = KeyInterner::new();
let a = interner.intern("port");
let b = interner.intern("host");
assert!(!Arc::ptr_eq(&a, &b));
assert_eq!(interner.len(), 2);
}
#[test]
fn empty_string_is_interned() {
let mut interner = KeyInterner::new();
let a = interner.intern("");
let b = interner.intern("");
assert!(Arc::ptr_eq(&a, &b));
assert_eq!(&*a, "");
}
#[test]
fn get_returns_existing_arc_without_inserting() {
let mut interner = KeyInterner::new();
assert!(interner.get("k").is_none());
assert_eq!(interner.len(), 0);
let inserted = interner.intern("k");
let fetched = interner.get("k").unwrap();
assert!(Arc::ptr_eq(&inserted, &fetched));
}
#[test]
fn clear_resets_the_intern_table() {
let mut interner = KeyInterner::new();
let a = interner.intern("k");
interner.clear();
assert!(interner.is_empty());
assert_eq!(&*a, "k");
let b = interner.intern("k");
assert!(!Arc::ptr_eq(&a, &b));
}
#[test]
fn with_capacity_constructs_empty_interner() {
let interner = KeyInterner::with_capacity(128);
assert!(interner.is_empty());
assert_eq!(interner.len(), 0);
}
#[test]
fn dedupes_real_kubernetes_key_set() {
let mut interner = KeyInterner::new();
let keys = [
"apiVersion",
"kind",
"metadata",
"name",
"labels",
"spec",
"selector",
"matchLabels",
"template",
"containers",
"image",
"ports",
"containerPort",
];
for _ in 0..100 {
for &k in &keys {
let _ = interner.intern(k);
}
}
assert_eq!(interner.len(), keys.len());
}
}