flowchart TD
S["set(k, v)"] --> H["idx = hash & mask, psl = 0"]
H --> C{"entries[idx]?"}
C -->|"same hash and key"| U["update value in place"]
C -->|"occupied, psl ≤ slot's psl"| N["idx = (idx + 1) & mask, psl += 1"] --> C
C -->|"empty, or occupied with psl > slot's psl"| G{"size ≥ capacity / 2?"}
G -->|"yes"| R["double capacity, rehash all, restart"] --> H
G -->|"no, slot was empty"| P["store {psl, hash, k, v}"]
G -->|"no, stealing"| E["swap: evict the richer entry,<br/>keep probing to re-place it"] --> N///|
test {
let _map1 = @hashmap.HashMap([("a", 1), ("b", 2)])
let _map2 : @hashmap.HashMap[String, Int] = HashMap([])
}///|
test {
let map : @hashmap.HashMap[String, Int] = HashMap([])
map.set("a", 1)
@test.assert_eq(map.get("a"), Some(1))
@test.assert_eq(map.get_or_default("a", 0), 1)
@test.assert_eq(map.get_or_default("b", 0), 0)
map.remove("a")
@test.assert_eq(map.contains("a"), false)
}///|
test {
let map = @hashmap.from_array([("a", 1), ("b", 2), ("c", 3)])
map.remove("a") |> ignore
assert_false(map.contains("a"))
}///|
test {
let map = @hashmap.from_array([("a", 1), ("b", 2), ("c", 3)])
@test.assert_eq(map.contains("a"), true)
@test.assert_eq(map.contains("d"), false)
}///|
test {
let map = @hashmap.from_array([("a", 1), ("b", 2), ("c", 3)])
@test.assert_eq(map.length(), 3)
@test.assert_eq(map.capacity(), 8)
}///|
test {
let map : @hashmap.HashMap[String, Int] = HashMap([])
@test.assert_eq(map.is_empty(), true)
}///|
test {
let map = @hashmap.from_array([("a", 1), ("b", 2), ("c", 3)])
map.clear()
@test.assert_eq(map.is_empty(), true)
}///|
test {
let map = @hashmap.from_array([("a", 1), ("b", 2), ("c", 3)])
let arr = []
map.each((k, v) => arr.push((k, v)))
let arr2 = []
map.eachi((i, k, v) => arr2.push((i, k, v)))
}///|
test {
let map = @hashmap.from_array([("a", 1)])
let _iter = map.iter()
let _keys = map.keys()
let _vals = map.values()
}///|
test {
let map : @hashmap.HashMap[String, Int] = HashMap([])
let val = map.get_or_init("key", () => 42)
@test.assert_eq(val, 42)
@test.assert_eq(map.get("key"), Some(42))
}///|
test {
let map = @hashmap.from_array([(1, "a"), (2, "b")])
let mapped = map.map((k, _v) => k * 10)
@test.assert_eq(mapped.get(1), Some(10))
let map2 = @hashmap.from_array([("a", 1), ("b", 2), ("c", 3)])
map2.retain((_k, v) => v > 1)
@test.assert_eq(map2.contains("a"), false)
@test.assert_eq(map2.contains("b"), true)
}///|
test {
let map = @hashmap.from_array([("x", 10), ("y", 20)])
@test.assert_eq(map["x"], 10)
map["z"] = 30
@test.assert_eq(map["z"], 30)
}///|
test {
let map = @hashmap.from_array([("a", 1), ("b", 2)])
@test.assert_eq(map.contains_kv("a", 1), true)
@test.assert_eq(map.contains_kv("a", 99), false)
}///|
test {
let map = @hashmap.from_array([("a", 1)])
let cloned = map.copy()
cloned.set("b", 2)
@test.assert_eq(map.contains("b"), false) // original unchanged
}///|
test {
let map = @hashmap.from_iter([("a", 1), ("b", 2)].iter())
@test.assert_eq(map.length(), 2)
}///|
test {
let m1 = @hashmap.from_array([("a", 1)])
let m2 = @hashmap.from_array([("b", 2)])
let merged = m1.merge(m2)
@test.assert_eq(merged.get("a"), Some(1))
@test.assert_eq(merged.get("b"), Some(2))
// merge_in_place
let m3 = @hashmap.from_array([("x", 1)])
let m4 = @hashmap.from_array([("y", 2)])
m3.merge_in_place(m4)
@test.assert_eq(m3.contains("y"), true)
}type HashMap[K, V]test {
let map = @hashmap.HashMap([(3, "three"), (8, "eight"), (1, "one")])
@test.assert_eq(map.get(2), None)
@test.assert_eq(map.get(3), Some("three"))
map.set(3, "updated")
@test.assert_eq(map.get(3), Some("updated"))
}test {
let arr : ReadOnlyArray[(Int, String)] = [(1, "one"), (2, "two"), (1, "ONE")]
let map = @hashmap.HashMap(arr)
debug_inspect(map.get(1), content="Some(\"ONE\")")
debug_inspect(map.get(2), content="Some(\"two\")")
}test {
let map = @hashmap.from_array([("key", 42)])
inspect(map["key"], content="42")
}test {
let map : @hashmap.HashMap[Int, String] = HashMap([], capacity=16)
inspect(map.capacity(), content="16")
}test {
let map = @hashmap.from_array([("a", 1), ("b", 2)])
map.clear()
inspect(map.length(), content="0")
debug_inspect(map.get("a"), content="None")
}test {
let map = @hashmap.from_array([("a", 1), ("b", 2)])
inspect(map.contains("a"), content="true")
inspect(map.contains("c"), content="false")
}test {
let map = @hashmap.HashMap([])
map.set("a", 1)
map.set("b", 2)
inspect(map.contains_kv("a", 1), content="true")
inspect(map.contains_kv("a", 2), content="false")
inspect(map.contains_kv("c", 3), content="false")
}test {
let map = @hashmap.from_array([(1, "one"), (2, "two")])
let array = []
map.each((k, v) => array.push((k, v)))
array.sort()
debug_inspect(
array,
content=(
#|[(1, "one"), (2, "two")]
),
)
}test {
let iter = Iter::singleton((1, "one")) + Iter::singleton((2, "two"))
let map = @hashmap.from_iter(iter)
debug_inspect(map.get(1), content="Some(\"one\")")
debug_inspect(map.get(2), content="Some(\"two\")")
}test {
let map = @hashmap.from_array([("key", 42)])
debug_inspect(map.get("key"), content="Some(42)")
debug_inspect(map.get("nonexistent"), content="None")
}test {
let map = @hashmap.from_array([(b"hello", 1), (b"world", 2)])
let bytes = b"prefix_hello_suffix"
let view = bytes[7:12] // view of "hello"
@debug.debug_inspect(map.get_from_bytes(view), content="Some(1)")
}test {
let map = @hashmap.from_array([("hello", 1), ("world", 2)])
let str = "say hello to everyone"
let view = str.view(start_offset=4, end_offset=9) // view of "hello"
@debug.debug_inspect(map.get_from_string(view), content="Some(1)")
}test {
let map = @hashmap.from_array([("a", 1), ("b", 2)])
inspect(map.get_or_default("a", 0), content="1")
inspect(map.get_or_default("c", 0), content="0")
}test {
let map : @hashmap.HashMap[String, Int] = HashMap([])
let value = map.get_or_init("key", () => 42)
inspect(value, content="42")
debug_inspect(map.get("key"), content="Some(42)")
}test {
let map : @hashmap.HashMap[String, Int] = HashMap([])
inspect(map.is_empty(), content="true")
map.set("key", 42)
inspect(map.is_empty(), content="false")
}test {
let map = @hashmap.from_array([(1, "one"), (2, "two")])
let pairs = map.iter().to_array()
inspect(pairs.length(), content="2")
inspect(pairs.contains((1, "one")), content="true")
inspect(pairs.contains((2, "two")), content="true")
}test {
let map = @hashmap.from_array([(1, "one"), (2, "two"), (3, "three")])
let keys = map.keys().to_array()
inspect(keys.length(), content="3")
inspect(keys.contains(1), content="true")
inspect(keys.contains(2), content="true")
inspect(keys.contains(3), content="true")
}test {
let map = @hashmap.from_array([("a", 1), ("b", 2), ("c", 3)])
inspect(map.length(), content="3")
}test {
let map1 = @hashmap.from_array([("a", 1), ("b", 2)])
let map2 = @hashmap.from_array([("b", 3), ("c", 4)])
let merged = map1.merge(map2).to_array()
merged.sort()
@json.json_inspect(merged, content=[["a", 1], ["b", 3], ["c", 4]])
}test {
let map1 = @hashmap.from_array([("a", 1), ("b", 2)])
let map2 = @hashmap.from_array([("b", 3), ("c", 4)])
map1.merge_in_place(map2)
let merged = map1.to_array()
merged.sort()
@json.json_inspect(merged, content=[["a", 1], ["b", 3], ["c", 4]])
}test {
let map = @hashmap.from_array([("a", 1), ("b", 2)])
map.remove("a")
debug_inspect(map.get("a"), content="None")
inspect(map.length(), content="1")
}test {
let map = @hashmap.from_array([("a", 1), ("b", 2), ("c", 3), ("d", 4)])
map.retain((_k, v) => v % 2 == 0) // Keep only even values
inspect(map.length(), content="2")
debug_inspect(map.get("a"), content="None")
debug_inspect(map.get("b"), content="Some(2)")
debug_inspect(map.get("c"), content="None")
debug_inspect(map.get("d"), content="Some(4)")
}test {
let map : @hashmap.HashMap[String, Int] = HashMap([])
map.set("key", 42)
debug_inspect(map.get("key"), content="Some(42)")
map.set("key", 24) // update existing key
debug_inspect(map.get("key"), content="Some(24)")
}test {
let map = @hashmap.from_array([(1, "one"), (2, "two")])
let arr = map.to_array()
arr.sort()
debug_inspect(
arr,
content=(
#|[(1, "one"), (2, "two")]
),
)
}test {
let map : @hashmap.HashMap[String, Int] = HashMap([("a", 1), ("b", 2)])
// Update existing value
map.update("a", fn(v) {
match v {
Some(x) => Some(x + 10)
None => Some(0)
}
})
debug_inspect(map.get("a"), content="Some(11)")
// Insert new value
map.update("c", fn(v) {
match v {
Some(x) => Some(x)
None => Some(3)
}
})
debug_inspect(map.get("c"), content="Some(3)")
// Remove existing value
map.update("b", fn(_) { None })
debug_inspect(map.get("b"), content="None")
}test {
let counts : @hashmap.HashMap[String, Int] = HashMap([])
counts.update_or_default("a", 1, x => x + 1)
counts.update_or_default("a", 1, x => x + 1)
counts.update_or_default("b", 1, x => x + 1)
debug_inspect(counts.get("a"), content="Some(2)")
debug_inspect(counts.get("b"), content="Some(1)")
}test {
let map = @hashmap.from_array([("a", 1), ("b", 2), ("c", 3)])
let values = map.values().to_array()
inspect(values.length(), content="3")
inspect(values.contains(1), content="true")
inspect(values.contains(2), content="true")
inspect(values.contains(3), content="true")
}Install
Installed by default