Stable-key map containers for MoonBit with slot reuse and self-invalidating secondary maps.
| Scenario | Fastest | Notes |
|---|---|---|
| Churn (insert + remove + get) | SlotMap (59.74 µs) | @hashmap.HashMap (84.38 µs) beats builtin Map (107.68 µs), but both trail stable-slot reuse. |
| Iterate after holes | builtin Map (2.64 µs) | DenseSlotMap (4.04 µs) is much better than SlotMap (10.17 µs) once iteration dominates. |
| Dense sidecar probe | SecondaryMap (25.29 µs) | Direct index lookup is far ahead of sparse hash-based sidecars. |
| Sparse sidecar iterate | builtin Map (15.76 µs) | SparseSecondaryMap (21.08 µs) is better than SecondaryMap (33.02 µs) for sparse metadata scans. |
///|
struct UserKey(@slotmap.KeyData) derive(Eq, Compare, Hash, Debug)
///|
impl @slotmap.Key for UserKey with null() {
UserKey(@slotmap.KeyData::null())
}
///|
impl @slotmap.Key for UserKey with is_null(self) {
self.0.is_null()
}
///|
impl @slotmap.Key for UserKey with index(self) {
self.0.index()
}
///|
impl @slotmap.Key for UserKey with version(self) {
self.0.version()
}
///|
impl @slotmap.Key for UserKey with from_raw_parts(index, version) {
UserKey(@slotmap.KeyData::from_raw_parts(index, version))
}
///|
impl @slotmap.Key for UserKey with into_raw_parts(self) {
self.0.into_raw_parts()
}
///|
impl Show for UserKey with output(self, logger) {
logger.write_object(self.0)
}
///|
test {
let sm : @slotmap.SlotMap[UserKey, String] = @slotmap.SlotMap::new()
let sec : @slotmap.SecondaryMap[UserKey, String] = @slotmap.SecondaryMap::new()
let foo = sm.insert("foo")
let bar = sm.insert("bar")
sec[foo] = "noun"
sec[bar] = "verb"
debug_inspect(sm.get(foo), content="Some(\"foo\")")
debug_inspect(sm.get(bar), content="Some(\"bar\")")
debug_inspect(sec.get(foo), content="Some(\"noun\")")
ignore(sm.remove(bar))
let reuse = sm.insert("reuse")
debug_inspect(sm.contains_key(bar), content="false")
debug_inspect(sec.get(bar), content="Some(\"verb\")")
sec[reuse] = "adjective"
debug_inspect(sec.get(bar), content="None")
debug_inspect(sm.get(reuse), content="Some(\"reuse\")")
debug_inspect(sec.get(reuse), content="Some(\"adjective\")")
}pub struct DenseSlotMap[K, V] {
slots : Array[DenseSlotEntry]
dense_keys : Array[K]
dense_values : Array[V]
free_head : Int?
}fn[K : Key + Eq + Show, V] DenseSlotMap::insert_with_key(self : DenseSlotMap[K, V], create : (K) -> V) -> K#alias(iterator2, deprecated="`iterator2` is deprecated, use `iter2` instead")
fn[K, V] DenseSlotMap::iter2(self : DenseSlotMap[K, V]) -> Iter2[K, V]fn[K : Key + Eq + Show, V] DenseSlotMap::reattach(self : DenseSlotMap[K, V], detached_key : K, value : V) -> Unitfn[K : Key + Eq + Show, V] DenseSlotMap::replace(self : DenseSlotMap[K, V], key : K, value : V) -> Boolfn[K : Key + Eq + Show, V] DenseSlotMap::retain(self : DenseSlotMap[K, V], predicate : (K, V) -> Bool) -> Unit#alias("_[_]=_")
fn[K : Key + Eq + Show, V] DenseSlotMap::set(self : DenseSlotMap[K, V], key : K, value : V) -> Unitfn[K : Key + Eq + Show, V] DenseSlotMap::update(self : DenseSlotMap[K, V], key : K, updater : (V?) -> V?) -> Unitfn[K : Key + Eq + Show, V] SecondaryMap::each(self : SecondaryMap[K, V], visit : (K, V) -> Unit) -> Unitfn[K : Key + Eq + Show, V] SecondaryMap::get_or_default(self : SecondaryMap[K, V], key : K, default : V) -> V?fn[K : Key + Eq + Show, V] SecondaryMap::get_or_init(self : SecondaryMap[K, V], key : K, init : () -> V) -> V?fn[K : Key + Eq + Show, V] SecondaryMap::insert(self : SecondaryMap[K, V], key : K, value : V) -> V?#alias(iterator2, deprecated="`iterator2` is deprecated, use `iter2` instead")
fn[K : Key + Eq + Show, V] SecondaryMap::iter2(self : SecondaryMap[K, V]) -> Iter2[K, V]fn[K : Key + Eq + Show, V] SecondaryMap::retain(self : SecondaryMap[K, V], predicate : (K, V) -> Bool) -> Unit#alias("_[_]=_")
fn[K : Key + Eq + Show, V] SecondaryMap::set(self : SecondaryMap[K, V], key : K, value : V) -> Unitfn[K : Key + Eq + Show, V] SecondaryMap::update(self : SecondaryMap[K, V], key : K, updater : (V?) -> V?) -> Unit#alias("_[_]")
fn[K : Key + Eq + Show, V] SparseSecondaryMap::at(self : SparseSecondaryMap[K, V], key : K) -> Vfn[K : Key + Eq + Show, V] SparseSecondaryMap::contains(self : SparseSecondaryMap[K, V], key : K) -> Boolfn[K : Key + Eq + Show, V] SparseSecondaryMap::contains_key(self : SparseSecondaryMap[K, V], key : K) -> Boolfn[K : Key + Eq + Show, V] SparseSecondaryMap::drain(self : SparseSecondaryMap[K, V]) -> Array[(K, V)]fn[K : Key + Eq + Show, V] SparseSecondaryMap::each(self : SparseSecondaryMap[K, V], visit : (K, V) -> Unit) -> Unitfn[K : Key + Eq + Show, V] SparseSecondaryMap::get_or_default(self : SparseSecondaryMap[K, V], key : K, default : V) -> V?fn[K : Key + Eq + Show, V] SparseSecondaryMap::get_or_init(self : SparseSecondaryMap[K, V], key : K, init : () -> V) -> V?fn[K : Key + Eq + Show, V] SparseSecondaryMap::insert(self : SparseSecondaryMap[K, V], key : K, value : V) -> V?fn[K : Key + Eq + Show, V] SparseSecondaryMap::iter(self : SparseSecondaryMap[K, V]) -> Array[(K, V)]#alias(iterator2, deprecated="`iterator2` is deprecated, use `iter2` instead")
fn[K : Key + Eq + Show, V] SparseSecondaryMap::iter2(self : SparseSecondaryMap[K, V]) -> Iter2[K, V]fn[K : Key + Eq + Show, V] SparseSecondaryMap::remove(self : SparseSecondaryMap[K, V], key : K) -> V?fn[K : Key + Eq + Show, V] SparseSecondaryMap::retain(self : SparseSecondaryMap[K, V], predicate : (K, V) -> Bool) -> Unit#alias("_[_]=_")
fn[K : Key + Eq + Show, V] SparseSecondaryMap::set(self : SparseSecondaryMap[K, V], key : K, value : V) -> Unitfn[K : Key + Eq + Show, V] SparseSecondaryMap::to_array(self : SparseSecondaryMap[K, V]) -> Array[(K, V)]fn[K : Key + Eq + Show, V] SparseSecondaryMap::update(self : SparseSecondaryMap[K, V], key : K, updater : (V?) -> V?) -> UnitStable-key map containers for MoonBit with slot reuse and self-invalidating secondary maps.