Skip to main content

KeyInterner

Struct KeyInterner 

Source
pub struct KeyInterner<K> { /* private fields */ }
Expand description

Monotonic key interner that assigns a u64 handle to each unique key.

Maps external keys to compact u64 handles for efficient storage and lookup. Handles are assigned sequentially starting from 0 and never reused.

§Type Parameters

  • K: Key type, must be Eq + Hash + Clone

§Example

use cachekit::ds::KeyInterner;

let mut interner = KeyInterner::new();

// Intern returns a handle
let handle = interner.intern(&"my_key");
assert_eq!(handle, 0);  // First key gets handle 0

// Same key returns same handle
assert_eq!(interner.intern(&"my_key"), 0);

// Different key gets next handle
assert_eq!(interner.intern(&"other_key"), 1);

// Resolve handle back to key
assert_eq!(interner.resolve(0), Some(&"my_key"));

§Use Case: Frequency Tracking

use cachekit::ds::KeyInterner;
use std::collections::HashMap;

let mut interner = KeyInterner::new();
let mut freq: HashMap<u64, u32> = HashMap::new();

// Track access frequency using handles (cheaper than cloning keys)
fn access(interner: &mut KeyInterner<String>, freq: &mut HashMap<u64, u32>, key: &str) {
    let handle = interner.intern(&key.to_string());
    *freq.entry(handle).or_insert(0) += 1;
}

access(&mut interner, &mut freq, "page_a");
access(&mut interner, &mut freq, "page_a");
access(&mut interner, &mut freq, "page_b");

let handle_a = interner.get_handle(&"page_a".to_string()).unwrap();
assert_eq!(freq[&handle_a], 2);

Implementations§

Source§

impl<K> KeyInterner<K>
where K: Eq + Hash + Clone,

Source

pub fn new() -> Self

Creates an empty interner.

§Example
use cachekit::ds::KeyInterner;

let interner: KeyInterner<String> = KeyInterner::new();
assert!(interner.is_empty());
Source

pub fn with_capacity(capacity: usize) -> Self

Creates an interner with pre-allocated capacity.

Pre-allocates space for capacity keys to avoid rehashing during growth.

§Example
use cachekit::ds::KeyInterner;

let interner: KeyInterner<String> = KeyInterner::with_capacity(1000);
assert!(interner.is_empty());
Source

pub fn intern(&mut self, key: &K) -> u64

Returns the handle for key, inserting it if missing.

If the key is already interned, returns the existing handle. Otherwise, assigns the next sequential handle and stores the key.

§Example
use cachekit::ds::KeyInterner;

let mut interner = KeyInterner::new();

// First key gets handle 0
let h1 = interner.intern(&"key_a");
assert_eq!(h1, 0);

// Second key gets handle 1
let h2 = interner.intern(&"key_b");
assert_eq!(h2, 1);

// Same key returns same handle (no new entry)
let h1_again = interner.intern(&"key_a");
assert_eq!(h1_again, 0);
assert_eq!(interner.len(), 2);  // Still only 2 keys
Source

pub fn get_handle(&self, key: &K) -> Option<u64>

Returns the handle for key if it exists.

Does not insert the key if missing.

§Example
use cachekit::ds::KeyInterner;

let mut interner = KeyInterner::new();
let handle = interner.intern(&"existing");

assert_eq!(interner.get_handle(&"existing"), Some(handle));
assert_eq!(interner.get_handle(&"missing"), None);
Source

pub fn resolve(&self, handle: u64) -> Option<&K>

Resolves a handle to its original key.

Returns None if the handle is out of bounds.

§Example
use cachekit::ds::KeyInterner;

let mut interner = KeyInterner::new();
let handle = interner.intern(&"my_key");

assert_eq!(interner.resolve(handle), Some(&"my_key"));
assert_eq!(interner.resolve(999), None);  // Invalid handle
Source

pub fn len(&self) -> usize

Returns the number of interned keys.

§Example
use cachekit::ds::KeyInterner;

let mut interner = KeyInterner::new();
assert_eq!(interner.len(), 0);

interner.intern(&"a");
interner.intern(&"b");
assert_eq!(interner.len(), 2);

// Re-interning same key doesn't increase count
interner.intern(&"a");
assert_eq!(interner.len(), 2);
Source

pub fn is_empty(&self) -> bool

Returns true if no keys are interned.

§Example
use cachekit::ds::KeyInterner;

let mut interner: KeyInterner<&str> = KeyInterner::new();
assert!(interner.is_empty());

interner.intern(&"key");
assert!(!interner.is_empty());
Source

pub fn clear_shrink(&mut self)

Clears all interned keys and shrinks internal storage.

After calling this, all previously returned handles become invalid.

§Example
use cachekit::ds::KeyInterner;

let mut interner = KeyInterner::new();
let handle = interner.intern(&"key");
assert_eq!(interner.resolve(handle), Some(&"key"));

interner.clear_shrink();
assert!(interner.is_empty());
assert_eq!(interner.resolve(handle), None);  // Handle now invalid
Source

pub fn approx_bytes(&self) -> usize

Returns an approximate memory footprint in bytes.

§Example
use cachekit::ds::KeyInterner;

let mut interner: KeyInterner<String> = KeyInterner::new();
let base_bytes = interner.approx_bytes();

// Add some keys
for i in 0..100 {
    interner.intern(&format!("key_{}", i));
}

assert!(interner.approx_bytes() > base_bytes);

Trait Implementations§

Source§

impl<K: Debug> Debug for KeyInterner<K>

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
Source§

impl<K: Default> Default for KeyInterner<K>

Source§

fn default() -> KeyInterner<K>

Returns the “default value” for a type. Read more

Auto Trait Implementations§

§

impl<K> Freeze for KeyInterner<K>

§

impl<K> RefUnwindSafe for KeyInterner<K>
where K: RefUnwindSafe,

§

impl<K> Send for KeyInterner<K>
where K: Send,

§

impl<K> Sync for KeyInterner<K>
where K: Sync,

§

impl<K> Unpin for KeyInterner<K>
where K: Unpin,

§

impl<K> UnsafeUnpin for KeyInterner<K>

§

impl<K> UnwindSafe for KeyInterner<K>
where K: UnwindSafe,

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.