///|
test "create" {
let empty : @vector_map.VectorMap[String, Int] = @vector_map.new()
inspect(empty.is_empty(), content="true")
let one = @vector_map.singleton("a", 1)
inspect(one.length(), content="1")
// The array keeps its order — this is not sorted by key.
let m = @vector_map.VectorMap([("c", 3), ("a", 1), ("b", 2)])
debug_inspect(
m.keys().to_array(),
content=(
#|["c", "a", "b"]
),
)
}///|
test "order" {
let m = @vector_map.VectorMap([("a", 1), ("b", 2), ("c", 3)])
// replacing in place: "a" stays first
debug_inspect(
m.add("a", 10).keys().to_array(),
content=(
#|["a", "b", "c"]
),
)
// a fresh key is appended
debug_inspect(
m.add("d", 4).keys().to_array(),
content=(
#|["a", "b", "c", "d"]
),
)
// remove-then-add moves it to the end
debug_inspect(
m.remove("a").add("a", 1).keys().to_array(),
content=(
#|["b", "c", "a"]
),
)
}///|
test "add_get_remove" {
let m = @vector_map.new().add("a", 1).add("b", 2)
debug_inspect(m.get("a"), content="Some(1)")
inspect(m["b"], content="2")
inspect(m.contains("z"), content="false")
let smaller = m.remove("a")
debug_inspect(smaller.get("a"), content="None")
// the original is unchanged
debug_inspect(m.get("a"), content="Some(1)")
}///|
test "update" {
let m = @vector_map.VectorMap([("hits", 1)])
let bumped = m.update("hits", n => Some(n.unwrap_or(0) + 1))
debug_inspect(bumped.get("hits"), content="Some(2)")
let fresh = m.update("misses", n => Some(n.unwrap_or(0) + 1))
debug_inspect(fresh.get("misses"), content="Some(1)")
// returning None removes the key
inspect(m.update("hits", _ => None).is_empty(), content="true")
}///|
test "traverse" {
let m = @vector_map.VectorMap([("c", 3), ("a", 1), ("b", 2)])
debug_inspect(
m.to_array(),
content=(
#|[("c", 3), ("a", 1), ("b", 2)]
),
)
inspect(m.fold(init=0, (acc, _, v) => acc + v), content="6")
let labelled = []
m.eachi((i, k, _) => labelled.push("\{i}:\{k}"))
debug_inspect(
labelled,
content=(
#|["0:c", "1:a", "2:b"]
),
)
for k, v in m {
ignore((k, v))
}
}///|
test "transform" {
let m = @vector_map.VectorMap([("c", 3), ("a", 1), ("b", 2)])
debug_inspect(
m.map((_, v) => v * 10).to_array(),
content=(
#|[("c", 30), ("a", 10), ("b", 20)]
),
)
debug_inspect(
m.filter((_, v) => v > 1).to_array(),
content=(
#|[("c", 3), ("b", 2)]
),
)
}///|
test "equality" {
let ab = @vector_map.VectorMap([("a", 1), ("b", 2)])
let ba = @vector_map.VectorMap([("b", 2), ("a", 1)])
inspect(ab == ba, content="false")
inspect(ab == @vector_map.new().add("a", 1).add("b", 2), content="true")
}///|
test "json" {
let m = @vector_map.VectorMap([(30, "c"), (10, "a")])
json_inspect(m, content=[[30, "c"], [10, "a"]])
let back : @vector_map.VectorMap[Int, String] = @json.from_json(Json(m))
inspect(back == m, content="true")
}///|
test "no_op" {
let m = @vector_map.VectorMap([("a", 1)])
inspect(physical_equal(m.remove("absent"), m), content="true")
inspect(physical_equal(m.filter((_, _) => true), m), content="true")
}| Operation | Cost |
|---|---|
| contains | one trie descent |
| get | one trie descent, then one vector descent |
| add on an existing key | one trie descent, one vector descent to recover the stored key, then one vector path copied |
| add on a new key | one trie descent, one trie insertion, and usually only the vector's tail rewritten |
| remove | one trie descent, one trie removal, one vector write — plus the trimming or rebuild described below |
| length, is_empty | O(1) |
| iteration, map, filter, to_array | O(n) |
type VectorMap[K, V]test {
let m = @vector_map.VectorMap([(3, "c"), (1, "a"), (3, "z")])
debug_inspect(
m.to_array(),
content=(
#|[(3, "z"), (1, "a")]
),
)
}test {
let m = @vector_map.VectorMap([("a", 1), ("b", 2)])
// updating in place keeps "a" first
debug_inspect(
m.add("a", 10).keys().to_array(),
content=(
#|["a", "b"]
),
)
// re-adding after a removal appends
debug_inspect(
m.remove("a").add("a", 10).keys().to_array(),
content=(
#|["b", "a"]
),
)
}test {
let m = @vector_map.VectorMap([("a", 1)])
let bumped = m.update("a", v => Some(v.unwrap_or(0) + 1))
debug_inspect(bumped.get("a"), content="Some(2)")
let cleared = m.update("a", _ => None)
inspect(cleared.is_empty(), content="true")
}Install
Installed by default