Skip to content
CryoCryo home
Stdlibcollections

hashmap

import std::collections::hashmap; · source

HashMap<K, V, A>

type struct HashMap<K, V, A = GlobalAlloc> {
    buckets:      Entry<K, V>**;
    bucket_count: u64;
    length:       u64;
    alloc:        A;
    seed:         u64;

    static new() -> HashMap<K, V, GlobalAlloc>;
    static new_in(alloc: A) -> HashMap<K, V, A>;
    static with_seed(seed: u64) -> HashMap<K, V, GlobalAlloc>;
    static with_seed_in(seed: u64, alloc: A) -> HashMap<K, V, A>;
    static with_capacity(capacity: u64) -> HashMap<K, V, GlobalAlloc>;
    length(&this) -> u64;
    is_empty(&this) -> boolean;
    bucket_count(&this) -> u64;
    get_bucket(&this, index: u64) -> Entry<K, V>*;
    iter(&this) -> implement Iterator<Pair<K, V>>
    where K: Copy, V: Copy;
    keys(&this) -> implement Iterator<K>
    where K: Copy;
    values(&this) -> implement Iterator<V>
    where V: Copy;
    entries(&this) -> implement Iterator<Pair<K*, V*>>;
    keys_ref(&this) -> implement Iterator<K*>;
    values_ref(&this) -> implement Iterator<V*>;
    contains_key(&this, key: &K) -> boolean
    where K: Hash + Eq;
    get(&this, key: &K) -> Option<V>
    where K: Hash + Eq, V: Copy;
    get_ref(&this, key: &K) -> Option<V*>
    where K: Hash + Eq;
    insert(mut &this, key: K, value: V) -> Option<V>
    where K: Hash + Eq;
    try_insert(mut &this, key: K, value: V) -> Result<Option<V>, AllocError>
    where K: Hash + Eq;
    get_or_insert(mut &this, key: K, default: V) -> V*
    where K: Hash + Eq;
    try_get_or_insert(mut &this, key: K, default: V) -> Result<V*, AllocError>
    where K: Hash + Eq;
    remove(mut &this, key: &K) -> Option<V>
    where K: Hash + Eq + Drop;
    clear(mut &this) -> void
    where K: Drop, V: Drop;
    resize_buckets(mut &this, new_count: u64) -> Result<(), AllocError>;
}

Separate chaining over a bucket array: each bucket holds a linked list of Entry nodes. Keys must implement Hash + Eq; the bound sits on each method rather than the type, so a map of un-hashable keys is spellable but unusable.

import std::collections::hashmap;

mut counts: HashMap<Str, u64> = HashMap<Str, u64>::new();
mut slot: u64* = counts.get_or_insert(word, 0);
*slot = *slot + 1;
MethodReturnsNotes
insert(key, value)Option<V> — the replaced valuetry_insert is the fallible form.
get(key) (where V: Copy)Option<V>
get_ref(key)Option<V*>Sound for owning values.
get_or_insert(key, default)V*try_get_or_insert is the fallible form.
remove(key)Option<V>The key is dropped; the value is returned.
contains_key(key)boolean
clear()Drops every key and value. Keeps the bucket array.
with_capacity(n)Sizes the bucket array to the smallest power of two that keeps the load factor below 1.0 for n entries.
bucket_count()u64Buckets allocated, not capacity — chaining means a bucket holds many entries.
get_bucket(index)Entry<K, V>*Head of a chain, for manual traversal. Null when empty or out of range.

Entry<K, V>

type struct Entry<K, V> {
    hash:  u64;
    key:   K;
    value: V;
    next:  Entry<K, V>*;
}

One node of a bucket's chain. get_bucket hands back the head of a chain as an Entry*, and next walks it; the cached hash is what lets a resize redistribute entries without re-hashing the keys. You only touch it for manual traversal.

Iterating

iter(), keys(), and values() yield by value and carry Copy bounds. entries(), keys_ref(), and values_ref() yield Pair<K*, V*>, K*, and V* respectively, and are sound for any key and value type — so they are what you want for a HashMap<String, Foo>. Order is bucket-major and unstable across resizes; every borrow is invalidated by any insert, remove, or resize.

Hash seeding

The hasher is FNV-1a, seeded per map from a per-process random value drawn from the kernel CSPRNG. Bucket placement therefore varies between runs, so adversarial keys cannot be precomputed to flood a single bucket. FNV-1a is not collision-resistant, so treat this as hardening rather than a cryptographic guarantee — supply a custom hasher where it matters.

with_seed(seed) and with_seed_in(seed, alloc) fix the seed for tests that need reproducible layout or iteration order. Production code should use new.

Chaining was chosen over open addressing because it sidesteps storing uninitialized key/value slots. The cost is one heap allocation per entry.

Trait implementations

implement<K, V, A> trait Drop for struct HashMap<K, V, A>
where K: Drop, V: Drop, A: Allocator

implement<K, V> trait Clone for struct HashMap<K, V, GlobalAlloc>
where K: Hash + Eq + Clone, V: Clone

implement<K, V> trait Default for struct HashMap<K, V, GlobalAlloc>

implement<K, V, A> trait Display for struct HashMap<K, V, A>
where K: Display, V: Display, A: Allocator   // std::fmt::display

implement<K, V, A> trait Debug for struct HashMap<K, V, A>
where K: Debug, V: Debug, A: Allocator   // std::fmt::display

Clone re-inserts every entry into a fresh map, so the clone's bucket layout may differ. Default is a fresh empty map that allocates no buckets until the first insert. Display renders {k: v, ...}.