lib/std/collections/dict.rad 1.9 KiB raw
1
//! Open-addressed hash map from string keys to `i32` values.
2
//!
3
//! Uses DJB2 hashing with linear probing. The table size must be a power
4
//! of two and is provided by the caller via arena-allocated storage.
5
6
use std::mem;
7
8
/// Hash map entry.
9
pub record Entry {
10
    /// Key.
11
    key: *[u8],
12
    /// Associated value.
13
    value: i32,
14
}
15
16
/// Open-addressed hash map with caller-provided storage.
17
pub record Dict {
18
    /// Hash table entries.
19
    entries: *mut [Entry],
20
    /// Number of occupied entries.
21
    count: u32,
22
}
23
24
/// Create a dict backed by the given entry storage.
25
/// The storage length must be a power of two.
26
pub fn init(entries: *mut [Entry]) -> Dict {
27
    for i in 0..entries.len {
28
        entries[i] = Entry { key: &[], value: 0 };
29
    }
30
    return Dict { entries, count: 0 };
31
}
32
33
/// Insert or update a key-value pair. Panics if the table exceeds 50% load.
34
pub fn insert(m: *mut Dict, key: *[u8], value: i32) {
35
    let mask = m.entries.len - 1;
36
    let mut idx = hash(key) & mask;
37
38
    loop {
39
        let entry = m.entries[idx];
40
        if entry.key.len == 0 {
41
            assert m.count < m.entries.len / 2, "dict::insert: table full";
42
            m.entries[idx] = Entry { key, value };
43
            m.count += 1;
44
            return;
45
        }
46
        if mem::eq(entry.key, key) {
47
            m.entries[idx].value = value;
48
            return;
49
        }
50
        idx = (idx + 1) & mask;
51
    }
52
}
53
54
/// Look up a value by key. Returns `nil` if not found.
55
pub fn get(m: *Dict, key: *[u8]) -> ?i32 {
56
    let mask = m.entries.len - 1;
57
    let mut idx = hash(key) & mask;
58
59
    loop {
60
        let entry = m.entries[idx];
61
        if entry.key.len == 0 {
62
            return nil;
63
        }
64
        if mem::eq(entry.key, key) {
65
            return entry.value;
66
        }
67
        idx = (idx + 1) & mask;
68
    }
69
}
70
71
/// DJB2 hash function.
72
pub fn hash(str: *[u8]) -> u32 {
73
    let mut h: u32 = 5381;
74
    for b in str {
75
        h = ((h << 5) + h) + b as u32;
76
    }
77
    return h;
78
}