The bucket array of a HashMap
is a nonempty array of AssocList
s.
(This type is an internal implementation detail of HashMap
.)
Equations
- Std.HashMap.Imp.Buckets α β = { b : Array (Std.AssocList α β) // 0 < Array.size b }
Instances For
Construct a new empty bucket array with the specified capacity.
Equations
- Std.HashMap.Imp.Buckets.mk buckets h = { val := mkArray buckets Std.AssocList.nil, property := ⋯ }
Instances For
Update one bucket in the bucket array with a new value.
Equations
- Std.HashMap.Imp.Buckets.update data i d h = { val := Array.uset data.val i d h, property := ⋯ }
Instances For
The number of elements in the bucket array.
Note: this is marked noncomputable
because it is only intended for specification.
Equations
- Std.HashMap.Imp.Buckets.size data = Nat.sum (List.map (fun (x : Std.AssocList α β) => List.length (Std.AssocList.toList x)) data.val.data)
Instances For
Map a function over the values in the map.
Equations
- Std.HashMap.Imp.Buckets.mapVal f self = { val := Array.map (Std.AssocList.mapVal f) self.val, property := ⋯ }
Instances For
The well-formedness invariant for the bucket array says that every element hashes to its index (assuming the hash is lawful - otherwise there are no promises about where elements are located).
- distinct : ∀ [inst : Std.HashMap.LawfulHashable α] [inst : PartialEquivBEq α] (bucket : Std.AssocList α β), bucket ∈ buckets.val.data → List.Pairwise (fun (a b : α × β) => ¬(a.fst == b.fst) = true) (Std.AssocList.toList bucket)
The elements of a bucket are all distinct according to the
BEq
relation. - hash_self : ∀ (i : Nat) (h : i < Array.size buckets.val), Std.AssocList.All (fun (k : α) (x : β) => USize.toNat (UInt64.toUSize (hash k) % Array.size buckets.val) = i) buckets.val[i]
Every element in a bucket should hash to its location.
Instances For
HashMap.Imp α β
is the internal implementation type of HashMap α β
.
- size : Nat
- buckets : Std.HashMap.Imp.Buckets α β
The bucket array of the
HashMap
.
Instances For
Given a desired capacity, this returns the number of buckets we should reserve.
A "load factor" of 0.75 is the usual standard for hash maps, so we return capacity * 4 / 3
.
Equations
- Std.HashMap.Imp.numBucketsForCapacity capacity = capacity * 4 / 3
Instances For
Constructs an empty hash map with the specified nonzero number of buckets.
Equations
- Std.HashMap.Imp.empty' buckets h = { size := 0, buckets := Std.HashMap.Imp.Buckets.mk buckets h }
Instances For
Constructs an empty hash map with the specified target capacity.
Equations
- One or more equations did not get rendered due to their size.
Instances For
Calculates the bucket index from a hash value u
.
Equations
- Std.HashMap.Imp.mkIdx h u = { val := u % n, property := ⋯ }
Instances For
Inserts a key-value pair into the bucket array. This function assumes that the data is not already in the array, which is appropriate when reinserting elements into the array after a resize.
Equations
- One or more equations did not get rendered due to their size.
Instances For
Folds a monadic function over the elements in the map (in arbitrary order).
Equations
- Std.HashMap.Imp.foldM f d map = Array.foldlM (fun (d : δ) (b : Std.AssocList α β) => Std.AssocList.foldlM f d b) d map.buckets.val 0
Instances For
Folds a function over the elements in the map (in arbitrary order).
Equations
- Std.HashMap.Imp.fold f d m = Id.run (Std.HashMap.Imp.foldM f d m)
Instances For
Runs a monadic function over the elements in the map (in arbitrary order).
Equations
- Std.HashMap.Imp.forM f h = Array.forM (fun (b : Std.AssocList α β) => Std.AssocList.forM f b) h.buckets.val 0
Instances For
Given a key a
, returns a key-value pair in the map whose key compares equal to a
.
Equations
- One or more equations did not get rendered due to their size.
Instances For
Looks up an element in the map with key a
.
Equations
- One or more equations did not get rendered due to their size.
Instances For
Returns true if the element a
is in the map.
Equations
- One or more equations did not get rendered due to their size.
Instances For
Copies all the entries from buckets
into a new hash map with a larger capacity.
Equations
- Std.HashMap.Imp.expand size buckets = let nbuckets := Array.size buckets.val * 2; { size := size, buckets := Std.HashMap.Imp.expand.go 0 buckets.val (Std.HashMap.Imp.Buckets.mk nbuckets ⋯) }
Instances For
Inner loop of expand
. Copies elements source[i:]
into target
,
destroying source
in the process.
Equations
- One or more equations did not get rendered due to their size.
Instances For
Inserts key-value pair a, b
into the map.
If an element equal to a
is already in the map, it is replaced by b
.
Equations
- One or more equations did not get rendered due to their size.
Instances For
Removes key a
from the map. If it does not exist in the map, the map is returned unchanged.
Equations
- One or more equations did not get rendered due to their size.
Instances For
Map a function over the values in the map.
Equations
- Std.HashMap.Imp.mapVal f self = { size := self.size, buckets := Std.HashMap.Imp.Buckets.mapVal f self.buckets }
Instances For
Performs an in-place edit of the value, ensuring that the value is used linearly.
Equations
- One or more equations did not get rendered due to their size.
Instances For
Applies f
to each key-value pair a, b
in the map. If it returns some c
then
a, c
is pushed into the new map; else the key is removed from the map.
Equations
- One or more equations did not get rendered due to their size.
Instances For
Inner loop of filterMap
. Note that this reverses the bucket lists,
but this is fine since bucket lists are unordered.
Equations
- One or more equations did not get rendered due to their size.
- Std.HashMap.Imp.filterMap.go f acc Std.AssocList.nil x = (acc, x)
Instances For
Constructs a map with the set of all pairs a, b
such that f
returns true.
Equations
- Std.HashMap.Imp.filter f m = Std.HashMap.Imp.filterMap (fun (a : α) (b : β) => bif f a b then some b else none) m
Instances For
The well-formedness invariant for a hash map. The first constructor is the real invariant,
and the others allow us to "cheat" in this file and define insert
and erase
,
which have more complex proofs that are delayed to Std.Data.HashMap.Lemmas
.
- mk: ∀ {α : Type u_1} [inst : BEq α] [inst_1 : Hashable α] {x : Type u_2} {m : Std.HashMap.Imp α x},
m.size = Std.HashMap.Imp.Buckets.size m.buckets → Std.HashMap.Imp.Buckets.WF m.buckets → Std.HashMap.Imp.WF m
The real well-formedness invariant:
- The
size
field should match the actual number of elements in the map - The bucket array should be well-formed, meaning that if the hashable instance is lawful then every element hashes to its index.
- The
- empty': ∀ {α : Type u_1} [inst : BEq α] [inst_1 : Hashable α] {x : Type u_2} {n : Nat} {h : 0 < n},
Std.HashMap.Imp.WF (Std.HashMap.Imp.empty' n h)
The empty hash map is well formed.
- insert: ∀ {α : Type u_1} [inst : BEq α] [inst_1 : Hashable α] {x : Type u_2} {m : Std.HashMap.Imp α x} {a : α} {b : x},
Std.HashMap.Imp.WF m → Std.HashMap.Imp.WF (Std.HashMap.Imp.insert m a b)
Inserting into a well formed hash map yields a well formed hash map.
- erase: ∀ {α : Type u_1} [inst : BEq α] [inst_1 : Hashable α] {x : Type u_2} {m : Std.HashMap.Imp α x} {a : α},
Std.HashMap.Imp.WF m → Std.HashMap.Imp.WF (Std.HashMap.Imp.erase m a)
Removing an element from a well formed hash map yields a well formed hash map.
- modify: ∀ {α : Type u_1} [inst : BEq α] [inst_1 : Hashable α] {x : Type u_2} {m : Std.HashMap.Imp α x} {a : α} {f : α → x → x},
Std.HashMap.Imp.WF m → Std.HashMap.Imp.WF (Std.HashMap.Imp.modify m a f)
Replacing an element in a well formed hash map yields a well formed hash map.
Instances For
HashMap α β
is a key-value map which stores elements in an array using a hash function
to find the values. This allows it to have very good performance for lookups
(average O(1)
for a perfectly random hash function), but it is not a persistent data structure,
meaning that one should take care to use the map linearly when performing updates.
Copies are O(n)
.
Equations
- Std.HashMap α β = { m : Std.HashMap.Imp α β // Std.HashMap.Imp.WF m }
Instances For
Make a new hash map with the specified capacity.
Equations
- Std.mkHashMap capacity = { val := Std.HashMap.Imp.empty capacity, property := ⋯ }
Instances For
Equations
- Std.HashMap.instInhabitedHashMap = { default := Std.mkHashMap }
Equations
- Std.HashMap.instEmptyCollectionHashMap = { emptyCollection := Std.mkHashMap }
Make a new empty hash map.
(empty : Std.HashMap Int Int).toList = []
Equations
- Std.HashMap.empty = Std.mkHashMap
Instances For
The number of elements in the hash map.
(ofList [("one", 1), ("two", 2)]).size = 2
Equations
- Std.HashMap.size self = self.val.size
Instances For
Is the map empty?
(empty : Std.HashMap Int Int).isEmpty = true
(ofList [("one", 1), ("two", 2)]).isEmpty = false
Equations
- Std.HashMap.isEmpty self = decide (Std.HashMap.size self = 0)
Instances For
Inserts key-value pair a, b
into the map.
If an element equal to a
is already in the map, it is replaced by b
.
def hashMap := ofList [("one", 1), ("two", 2)]
hashMap.insert "three" 3 = {"one" => 1, "two" => 2, "three" => 3}
hashMap.insert "two" 0 = {"one" => 1, "two" => 0}
Equations
- Std.HashMap.insert self a b = { val := Std.HashMap.Imp.insert self.val a b, property := ⋯ }
Instances For
Similar to insert
, but also returns a boolean flag indicating whether an existing entry has been
replaced with a => b
.
def hashMap := ofList [("one", 1), ("two", 2)]
hashMap.insert' "three" 3 = ({"one" => 1, "two" => 2, "three" => 3}, false)
hashMap.insert' "two" 0 = ({"one" => 1, "two" => 0}, true)
Equations
- Std.HashMap.insert' m a b = let old := Std.HashMap.size m; let m' := Std.HashMap.insert m a b; let replaced := old == Std.HashMap.size m'; (m', replaced)
Instances For
Removes key a
from the map. If it does not exist in the map, the map is returned unchanged.
def hashMap := ofList [("one", 1), ("two", 2)]
hashMap.erase "one" = {"two" => 2}
hashMap.erase "three" = {"one" => 1, "two" => 2}
Equations
- Std.HashMap.erase self a = { val := Std.HashMap.Imp.erase self.val a, property := ⋯ }
Instances For
Performs an in-place edit of the value, ensuring that the value is used linearly.
The function f
is passed the original key of the entry, along with the value in the map.
(ofList [("one", 1), ("two", 2)]).modify "one" (fun _ v => v + 1) = {"one" => 2, "two" => 2}
(ofList [("one", 1), ("two", 2)]).modify "three" (fun _ v => v + 1) = {"one" => 1, "two" => 2}
Equations
- Std.HashMap.modify self a f = { val := Std.HashMap.Imp.modify self.val a f, property := ⋯ }
Instances For
Given a key a
, returns a key-value pair in the map whose key compares equal to a
.
Note that the returned key may not be identical to the input, if ==
ignores some part
of the value.
def hashMap := ofList [("one", 1), ("two", 2)]
hashMap.findEntry? "one" = some ("one", 1)
hashMap.findEntry? "three" = none
Equations
- Std.HashMap.findEntry? self a = Std.HashMap.Imp.findEntry? self.val a
Instances For
Looks up an element in the map with key a
.
def hashMap := ofList [("one", 1), ("two", 2)]
hashMap.find? "one" = some 1
hashMap.find? "three" = none
Equations
- Std.HashMap.find? self a = Std.HashMap.Imp.find? self.val a
Instances For
Looks up an element in the map with key a
. Returns b₀
if the element is not found.
def hashMap := ofList [("one", 1), ("two", 2)]
hashMap.findD "one" 0 = 1
hashMap.findD "three" 0 = 0
Equations
- Std.HashMap.findD self a b₀ = Option.getD (Std.HashMap.find? self a) b₀
Instances For
Looks up an element in the map with key a
. Panics if the element is not found.
def hashMap := ofList [("one", 1), ("two", 2)]
hashMap.find! "one" = 1
hashMap.find! "three" => panic!
Equations
- One or more equations did not get rendered due to their size.
Instances For
Equations
- Std.HashMap.instGetElemHashMapOptionTrue = { getElem := fun (m : Std.HashMap α β) (k : α) (x_1 : True) => Std.HashMap.find? m k }
Returns true if the element a
is in the map.
def hashMap := ofList [("one", 1), ("two", 2)]
hashMap.contains "one" = true
hashMap.contains "three" = false
Equations
- Std.HashMap.contains self a = Std.HashMap.Imp.contains self.val a
Instances For
Folds a monadic function over the elements in the map (in arbitrary order).
def sumEven (sum: Nat) (k : String) (v : Nat) : Except String Nat :=
if v % 2 == 0 then pure (sum + v) else throw s!"value {v} at key {k} is not even"
foldM sumEven 0 (ofList [("one", 1), ("three", 3)]) =
Except.error "value 3 at key three is not even"
foldM sumEven 0 (ofList [("two", 2), ("four", 4)]) = Except.ok 6
Equations
- Std.HashMap.foldM f init self = Std.HashMap.Imp.foldM f init self.val
Instances For
Folds a function over the elements in the map (in arbitrary order).
fold (fun sum _ v => sum + v) 0 (ofList [("one", 1), ("two", 2)]) = 3
Equations
- Std.HashMap.fold f init self = Std.HashMap.Imp.fold f init self.val
Instances For
Combines two hashmaps using a monadic function f
to combine two values at a key.
def map1 := ofList [("one", 1), ("two", 2)]
def map2 := ofList [("two", 2), ("three", 3)]
def map3 := ofList [("two", 3), ("three", 3)]
def mergeIfNoConflict? (_ : String) (v₁ v₂ : Nat) : Option Nat :=
if v₁ != v₂ then none else some v₁
mergeWithM mergeIfNoConflict? map1 map2 = some {"one" => 1, "two" => 2, "three" => 3}
mergeWithM mergeIfNoConflict? map1 map3 = none
Equations
- One or more equations did not get rendered due to their size.
Instances For
Combines two hashmaps using function f
to combine two values at a key.
mergeWith (fun _ v₁ v₂ => v₁ + v₂ )
(ofList [("one", 1), ("two", 2)]) (ofList [("two", 2), ("three", 3)]) =
{"one" => 1, "two" => 4, "three" => 3}
Equations
- One or more equations did not get rendered due to their size.
Instances For
Runs a monadic function over the elements in the map (in arbitrary order).
def checkEven (k : String) (v : Nat) : Except String Unit :=
if v % 2 == 0 then pure () else throw s!"value {v} at key {k} is not even"
forM checkEven (ofList [("one", 1), ("three", 3)]) = Except.error "value 3 at key three is not even"
forM checkEven (ofList [("two", 2), ("four", 4)]) = Except.ok ()
Equations
- Std.HashMap.forM f self = Std.HashMap.Imp.forM f self.val
Instances For
Converts the map into a list of key-value pairs.
open List
(ofList [("one", 1), ("two", 2)]).toList ~ [("one", 1), ("two", 2)]
Equations
- Std.HashMap.toList self = Std.HashMap.fold (fun (r : List (α × β)) (k : α) (v : β) => (k, v) :: r) [] self
Instances For
Converts the map into an array of key-value pairs.
open List
(ofList [("one", 1), ("two", 2)]).toArray.data ~ #[("one", 1), ("two", 2)].data
Equations
- Std.HashMap.toArray self = Std.HashMap.fold (fun (r : Array (α × β)) (k : α) (v : β) => Array.push r (k, v)) #[] self
Instances For
The number of buckets in the hash map.
Equations
- Std.HashMap.numBuckets self = Array.size self.val.buckets.val
Instances For
Builds a HashMap
from a list of key-value pairs.
Values of duplicated keys are replaced by their respective last occurrences.
ofList [("one", 1), ("one", 2)] = {"one" => 2}
Equations
- Std.HashMap.ofList l = List.foldl (fun (m : Std.HashMap α β) (x : α × β) => match x with | (k, v) => Std.HashMap.insert m k v) Std.HashMap.empty l
Instances For
Variant of ofList
which accepts a function that combines values of duplicated keys.
ofListWith [("one", 1), ("one", 2)] (fun v₁ v₂ => v₁ + v₂) = {"one" => 3}
Equations
- One or more equations did not get rendered due to their size.