pub struct KevyMap<K, V> { /* private fields */ }Expand description
An open-addressing Swiss-style hashtable keyed by KevyHash.
Power-of-two capacity (mask = cap - 1); 7/8 load factor; linear probing
over the metadata array; full slots’ (K, V) live AoS in a parallel slot
array of MaybeUninit<(K, V)> co-allocated with the metadata.
When cap == 0 both pointers are dangling and no allocation is held.
§Examples
Keys are byte strings or integers — whatever implements KevyHash.
There is deliberately no &str impl: the keyspace deals in bytes, and a
key that exists only as UTF-8 would need validating on every lookup.
let mut m: kevy_map::KevyMap<Vec<u8>, u32> = kevy_map::KevyMap::new();
assert_eq!(m.insert(b"k".to_vec(), 1), None, "insert returns what it displaced");
assert_eq!(m.insert(b"k".to_vec(), 2), Some(1));
assert_eq!(m.get(b"k".as_slice()), Some(&2));
assert_eq!(m.remove(b"k".as_slice()), Some(2));
assert_eq!(m.get(b"k".as_slice()), None);
assert!(m.is_empty());Implementations§
Source§impl<K, V> KevyMap<K, V>
impl<K, V> KevyMap<K, V>
Sourcepub fn new() -> Self
pub fn new() -> Self
Construct an empty map without allocating.
§Examples
// The key must implement `KevyHash`, which is deliberately a small
// set: byte strings and integers, the things a KV engine keys on.
let m: kevy_map::KevyMap<Vec<u8>, u32> = kevy_map::KevyMap::new();
assert!(m.is_empty());
assert_eq!(m.len(), 0);Sourcepub fn with_capacity(cap_hint: usize) -> Self
pub fn with_capacity(cap_hint: usize) -> Self
Construct a map sized to hold cap_hint entries without growing
(accounting for the 7/8 load factor).
§Examples
// A hint, not a promise: capacity is rounded to the table's own
// shape, and `len` still starts at zero.
let m: kevy_map::KevyMap<u32, u32> = kevy_map::KevyMap::with_capacity(100);
assert_eq!(m.len(), 0);Sourcepub fn len(&self) -> usize
pub fn len(&self) -> usize
Live entry count.
§Examples
let mut m = kevy_map::KevyMap::new();
m.insert(1u32, "a");
m.insert(1u32, "b");
assert_eq!(m.len(), 1, "the second insert REPLACED the first");Sourcepub fn clear(&mut self)
pub fn clear(&mut self)
Drop every live entry and reset the metadata. Keeps the allocation.
§Examples
let mut m = kevy_map::KevyMap::new();
for i in 0..8u32 { m.insert(i, i); }
m.clear();
assert!(m.is_empty());
assert_eq!(m.get(&0), None);Sourcepub fn iter(&self) -> Iter<'_, K, V> ⓘ
pub fn iter(&self) -> Iter<'_, K, V> ⓘ
(&K, &V) over all live entries; order is unspecified.
§Examples
let mut m = kevy_map::KevyMap::new();
for i in 0..4u32 { m.insert(i, i * 10); }
// Unordered, like any hash table: sort before comparing.
let mut got: Vec<_> = m.iter().map(|(k, v)| (*k, *v)).collect();
got.sort_unstable();
assert_eq!(got, vec![(0, 0), (1, 10), (2, 20), (3, 30)]);Sourcepub fn iter_from_bucket(&self, start: usize) -> Iter<'_, K, V> ⓘ
pub fn iter_from_bucket(&self, start: usize) -> Iter<'_, K, V> ⓘ
iter that begins at bucket start (clamped to capacity()) and
walks to the end. To sweep the full ring beginning at a random offset
— the pattern the kevy-store eviction sampler uses — chain it with a
second iter_from_bucket(0) and take(start).
Sourcepub fn iter_mut(&mut self) -> IterMut<'_, K, V> ⓘ
pub fn iter_mut(&mut self) -> IterMut<'_, K, V> ⓘ
(&K, &mut V) over all live entries; order is unspecified. Keys stay
shared (mutating a key in place would corrupt its bucket).
Sourcepub fn keys(&self) -> Keys<'_, K, V> ⓘ
pub fn keys(&self) -> Keys<'_, K, V> ⓘ
&K over all live entries.
§Examples
let mut m = kevy_map::KevyMap::new();
m.insert(b"a".to_vec(), 1u32);
m.insert(b"b".to_vec(), 2);
let mut ks: Vec<_> = m.keys().cloned().collect();
ks.sort_unstable();
assert_eq!(ks, vec![b"a".to_vec(), b"b".to_vec()]);Sourcepub fn prefetch_for_hash(&self, hash: u64)
pub fn prefetch_for_hash(&self, hash: u64)
Hint the CPU to fetch the bucket cache line that a probe at hash
would start at. The prefetch lever against the bucket-probe DRAM
miss: the command-batch driver calls this for command N+1 while
finishing command N, so by the time N+1 actually probes the
metadata, the line is in L1.
No-op when the table is empty. Cheap when not empty (a single
prefetcht0 on x86_64 / prfm pldl1keep on aarch64; a regular
volatile load on other arches via std::intrinsics — but we
only use stable intrinsics here, so non-x86/aarch64 architectures
degrade to a no-op rather than a fake hint).
inline(always) is the point — see the prefetch_t0 rationale.
Source§impl<K: KevyHash + Eq, V> KevyMap<K, V>
impl<K: KevyHash + Eq, V> KevyMap<K, V>
Sourcepub fn insert(&mut self, key: K, value: V) -> Option<V>
pub fn insert(&mut self, key: K, value: V) -> Option<V>
Insert (key, value). Returns the old value if key was already
present. Following std::HashMap semantics, the existing K is kept on
overwrite — only V is replaced.
§Examples
let mut m = kevy_map::KevyMap::new();
assert_eq!(m.insert(b"k".to_vec(), 1u32), None, "no previous value");
assert_eq!(m.insert(b"k".to_vec(), 2), Some(1), "the OLD value comes back");
assert_eq!(m.get(b"k".as_slice()), Some(&2));Source§impl<K, V> KevyMap<K, V>
impl<K, V> KevyMap<K, V>
Sourcepub fn get<Q>(&self, key: &Q) -> Option<&V>
pub fn get<Q>(&self, key: &Q) -> Option<&V>
Borrow the value for key, or None if absent.
§Examples
let mut m = kevy_map::KevyMap::new();
m.insert(b"k".to_vec(), 1u32);
// Borrowed lookup: a `&[u8]` finds a `Vec<u8>` key without allocating.
assert_eq!(m.get(b"k".as_slice()), Some(&1));
assert_eq!(m.get(b"nope".as_slice()), None);Sourcepub fn get_mut<Q>(&mut self, key: &Q) -> Option<&mut V>
pub fn get_mut<Q>(&mut self, key: &Q) -> Option<&mut V>
Mutably borrow the value for key, or None if absent.
§Examples
let mut m = kevy_map::KevyMap::new();
m.insert(b"k".to_vec(), 1u32);
if let Some(v) = m.get_mut(b"k".as_slice()) { *v += 41; }
assert_eq!(m.get(b"k".as_slice()), Some(&42));Sourcepub fn contains_key<Q>(&self, key: &Q) -> bool
pub fn contains_key<Q>(&self, key: &Q) -> bool
Whether key is present in the map.
§Examples
let mut m = kevy_map::KevyMap::new();
m.insert(b"k".to_vec(), ());
assert!(m.contains_key(b"k".as_slice()));
assert!(!m.contains_key(b"j".as_slice()));Sourcepub fn remove<Q>(&mut self, key: &Q) -> Option<V>
pub fn remove<Q>(&mut self, key: &Q) -> Option<V>
Remove key’s entry; returns the previous value if present.
§Examples
let mut m = kevy_map::KevyMap::new();
m.insert(b"k".to_vec(), 7u32);
assert_eq!(m.remove(b"k".as_slice()), Some(7), "the value comes back");
assert_eq!(m.remove(b"k".as_slice()), None, "absent — None, not a panic");
assert!(m.is_empty());Source§impl<K, V> KevyMap<K, V>
impl<K, V> KevyMap<K, V>
Sourcepub fn raw_entry_mut<Q>(&mut self, key: &Q) -> RawEntryMut<'_, K, V>
pub fn raw_entry_mut<Q>(&mut self, key: &Q) -> RawEntryMut<'_, K, V>
Look up key; return an RawEntryMut giving single-probe
access to the located (or vacant) slot.
One full probe. The returned handle borrows self mutably; the
borrow is released only when the handle is dropped (or consumed
via RawOccupiedEntryMut::remove / RawOccupiedEntryMut::into_mut).
Source§impl<K: KevyHash + Eq, V> KevyMap<K, V>
impl<K: KevyHash + Eq, V> KevyMap<K, V>
Sourcepub fn scan_step(&self, cursor: u64, f: impl FnMut(&K, &V)) -> u64
pub fn scan_step(&self, cursor: u64, f: impl FnMut(&K, &V)) -> u64
Visit one bucket-group’s worth of the map and return the next
cursor. Start a sweep with cursor = 0; a returned 0 means the
sweep is complete. Grows between calls never skip a key that was
present throughout (see the module docs); shrinks don’t exist
(KevyMap never shrinks in place).
f is called once per entry whose home group is the cursor’s
group — at most once per entry per call, in unspecified order.
Bounded work: one call touches one 16-bucket home group plus its probe-run overhang (short at the 7/8 load factor).
§Examples
let mut m = kevy_map::KevyMap::new();
for i in 0..64u32 { m.insert(i, i); }
// A SCAN-style cursor: bounded work per call, 0 both starts and
// ends the walk, and every key is seen at least once across it.
let mut seen = Vec::new();
let mut cur = 0u64;
loop {
cur = m.scan_step(cur, |k, _| seen.push(*k));
if cur == 0 { break; }
}
seen.sort_unstable();
seen.dedup();
assert_eq!(seen.len(), 64);Trait Implementations§
Source§impl<K: KevyHash + Eq, V> Extend<(K, V)> for KevyMap<K, V>
impl<K: KevyHash + Eq, V> Extend<(K, V)> for KevyMap<K, V>
Source§fn extend<I: IntoIterator<Item = (K, V)>>(&mut self, iter: I)
fn extend<I: IntoIterator<Item = (K, V)>>(&mut self, iter: I)
Source§fn extend_one(&mut self, item: A)
fn extend_one(&mut self, item: A)
extend_one)Source§fn extend_reserve(&mut self, additional: usize)
fn extend_reserve(&mut self, additional: usize)
extend_one)Source§impl<K, Q, V> Index<&Q> for KevyMap<K, V>
m[&q] panics on missing key (matches std::HashMap::Index semantics).
impl<K, Q, V> Index<&Q> for KevyMap<K, V>
m[&q] panics on missing key (matches std::HashMap::Index semantics).