kevy_map/clone.rs
1//! `Clone` for [`KevyMap`] — a faithful layout copy.
2//!
3//! The clone preserves the source's exact bucket geometry: same capacity,
4//! same slot positions, same tombstones. Tombstones must be carried over —
5//! probe sequences walk *through* `DELETED` bytes and stop at `EMPTY`, so
6//! dropping a tombstone would terminate a probe early and lose every key
7//! that was inserted past it. Copying positions verbatim (instead of
8//! re-inserting) also needs no `KevyHash` bound: only `K: Clone, V: Clone`.
9//!
10//! Panic safety: the new table starts all-`EMPTY` and a slot's metadata
11//! byte is only flipped to occupied *after* the cloned pair is written, so
12//! if a `K`/`V` clone panics mid-way the partially-built map drops exactly
13//! the entries it actually owns.
14
15use crate::map::{DELETED, GROUP_WIDTH, KevyMap};
16
17impl<K: Clone, V: Clone> Clone for KevyMap<K, V> {
18 fn clone(&self) -> Self {
19 if self.cap == 0 {
20 return Self::new();
21 }
22 let mut new = Self::alloc_table(self.cap);
23 debug_assert_eq!(new.cap, self.cap);
24 let _ = GROUP_WIDTH; // mirror bytes are maintained by set_meta below
25 for i in 0..self.cap {
26 // SAFETY: i < cap ⇒ metadata pointer in-bounds.
27 let meta = unsafe { *self.metadata_ptr.as_ptr().add(i) };
28 if meta & 0x80 == 0 {
29 // SAFETY: occupied slot ⇒ initialised; shared borrow of the
30 // source pair for the clones.
31 let (k, v) = unsafe { &*(self.slots_ptr.as_ptr().add(i) as *const (K, V)) };
32 let pair = (k.clone(), v.clone());
33 // SAFETY: i < cap ⇒ slot pointer in-bounds; the target slot
34 // is uninitialised (metadata still EMPTY).
35 unsafe {
36 (*new.slots_ptr.as_ptr().add(i)).write(pair);
37 }
38 new.set_meta(i, meta); // after the write — panic-safe order
39 } else if meta == DELETED {
40 new.set_meta(i, DELETED);
41 }
42 }
43 new.occupied = self.occupied;
44 new.deleted = self.deleted;
45 new
46 }
47}