| /- | |
| Copyright (c) 2025 Robin Arnez. All rights reserved. | |
| Released under Apache 2.0 license as described in the file LICENSE. | |
| Authors: Robin Arnez | |
| -/ | |
| prelude | |
| import Std.Data.ExtDHashMap.Basic | |
| set_option linter.missingDocs true | |
| set_option autoImplicit false | |
| /-! | |
| # Extensional hash maps | |
| This module develops the type `Std.ExtHashMap` of extensional hash maps. Dependent hash maps | |
| are defined in `Std.Data.ExtDHashMap`. | |
| Lemmas about the operations on `Std.ExtHashMap` are available in the | |
| module `Std.Data.ExtHashMap.Lemmas`. | |
| -/ | |
| universe u v w | |
| variable {α : Type u} {β : Type v} {γ : Type w} {_ : BEq α} {_ : Hashable α} | |
| namespace Std | |
| /-- | |
| Hash maps. | |
| This is a simple separate-chaining hash table. The data of the hash map consists of a cached size | |
| and an array of buckets, where each bucket is a linked list of key-value pais. The number of buckets | |
| is always a power of two. The hash map doubles its size upon inserting an element such that the | |
| number of elements is more than 75% of the number of buckets. | |
| The hash table is backed by an `Array`. Users should make sure that the hash map is used linearly to | |
| avoid expensive copies. | |
| The hash map uses `==` (provided by the `BEq` typeclass) to compare keys and `hash` (provided by | |
| the `Hashable` typeclass) to hash them. To ensure that the operations behave as expected, `==` | |
| should be an equivalence relation and `a == b` should imply `hash a = hash b` (see also the | |
| `EquivBEq` and `LawfulHashable` typeclasses). Both of these conditions are automatic if the BEq | |
| instance is lawful, i.e., if `a == b` implies `a = b`. | |
| In contrast to regular hash maps, `Std.ExtHashMap` offers several extensionality lemmas | |
| and therefore has more lemmas about equality of hash maps. This however also makes it lose the | |
| ability to iterate freely over hash maps. | |
| These hash maps contain a bundled well-formedness invariant, which means that they cannot | |
| be used in nested inductive types. For these use cases, `Std.HashMap.Raw` and | |
| `Std.HashMap.Raw.WF` unbundle the invariant from the hash map. When in doubt, prefer | |
| `HashMap` or `ExtHashMap` over `HashMap.Raw`. | |
| Dependent hash maps, in which keys may occur in their values' types, are available as | |
| `Std.ExtDHashMap` in the module `Std.Data.ExtDHashMap`. | |
| -/ | |
| structure ExtHashMap (α : Type u) (β : Type v) [BEq α] [Hashable α] where | |
| /-- Internal implementation detail of the hash map -/ | |
| inner : ExtDHashMap α (fun _ => β) | |
| namespace ExtHashMap | |
| @[inline, inherit_doc ExtDHashMap.emptyWithCapacity] | |
| def emptyWithCapacity [BEq α] [Hashable α] (capacity := 8) : | |
| ExtHashMap α β := | |
| ⟨ExtDHashMap.emptyWithCapacity capacity⟩ | |
| instance [BEq α] [Hashable α] : EmptyCollection (ExtHashMap α β) where | |
| emptyCollection := emptyWithCapacity | |
| instance [BEq α] [Hashable α] : Inhabited (ExtHashMap α β) where | |
| default := ∅ | |
| @[inline, inherit_doc ExtDHashMap.insert] | |
| def insert [EquivBEq α] [LawfulHashable α] (m : ExtHashMap α β) (a : α) | |
| (b : β) : ExtHashMap α β := | |
| ⟨m.inner.insert a b⟩ | |
| instance [EquivBEq α] [LawfulHashable α] : Singleton (α × β) (ExtHashMap α β) where | |
| singleton | ⟨a, b⟩ => (∅ : ExtHashMap α β).insert a b | |
| instance [EquivBEq α] [LawfulHashable α] : Insert (α × β) (ExtHashMap α β) where | |
| insert | ⟨a, b⟩, s => s.insert a b | |
| instance [EquivBEq α] [LawfulHashable α] : LawfulSingleton (α × β) (ExtHashMap α β) := | |
| ⟨fun _ => rfl⟩ | |
| @[inline, inherit_doc ExtDHashMap.insertIfNew] | |
| def insertIfNew [EquivBEq α] [LawfulHashable α] (m : ExtHashMap α β) | |
| (a : α) (b : β) : ExtHashMap α β := | |
| ⟨m.inner.insertIfNew a b⟩ | |
| @[inline, inherit_doc ExtDHashMap.containsThenInsert] | |
| def containsThenInsert [EquivBEq α] [LawfulHashable α] | |
| (m : ExtHashMap α β) (a : α) (b : β) : Bool × ExtHashMap α β := | |
| let ⟨replaced, r⟩ := m.inner.containsThenInsert a b | |
| ⟨replaced, ⟨r⟩⟩ | |
| @[inline, inherit_doc ExtDHashMap.containsThenInsertIfNew] | |
| def containsThenInsertIfNew [EquivBEq α] [LawfulHashable α] | |
| (m : ExtHashMap α β) (a : α) (b : β) : Bool × ExtHashMap α β := | |
| let ⟨replaced, r⟩ := m.inner.containsThenInsertIfNew a b | |
| ⟨replaced, ⟨r⟩⟩ | |
| /-- | |
| Checks whether a key is present in a map, returning the associate value, and inserts a value for | |
| the key if it was not found. | |
| If the returned value is `some v`, then the returned map is unaltered. If it is `none`, then the | |
| returned map has a new value inserted. | |
| Equivalent to (but potentially faster than) calling `get?` followed by `insertIfNew`. | |
| -/ | |
| @[inline] | |
| def getThenInsertIfNew? [EquivBEq α] [LawfulHashable α] (m : ExtHashMap α β) (a : α) (b : β) : | |
| Option β × ExtHashMap α β := | |
| let ⟨previous, r⟩ := ExtDHashMap.Const.getThenInsertIfNew? m.inner a b | |
| ⟨previous, ⟨r⟩⟩ | |
| /-- | |
| The notation `m[a]?` is preferred over calling this function directly. | |
| Tries to retrieve the mapping for the given key, returning `none` if no such mapping is present. | |
| -/ | |
| @[inline] def get? [EquivBEq α] [LawfulHashable α] (m : ExtHashMap α β) (a : α) : Option β := | |
| ExtDHashMap.Const.get? m.inner a | |
| @[inline, inherit_doc ExtDHashMap.contains] | |
| def contains [EquivBEq α] [LawfulHashable α] (m : ExtHashMap α β) | |
| (a : α) : Bool := | |
| m.inner.contains a | |
| instance [BEq α] [Hashable α] [EquivBEq α] [LawfulHashable α] : Membership α (ExtHashMap α β) where | |
| mem m a := a ∈ m.inner | |
| instance [BEq α] [Hashable α] [EquivBEq α] [LawfulHashable α] | |
| {m : ExtHashMap α β} {a : α} : Decidable (a ∈ m) := | |
| inferInstanceAs (Decidable (a ∈ m.inner)) | |
| /-- | |
| The notation `m[a]` or `m[a]'h` is preferred over calling this function directly. | |
| Retrieves the mapping for the given key. Ensures that such a mapping exists by requiring a proof of | |
| `a ∈ m`. | |
| -/ | |
| @[inline] def get [EquivBEq α] [LawfulHashable α] (m : ExtHashMap α β) (a : α) (h : a ∈ m) : β := | |
| ExtDHashMap.Const.get m.inner a h | |
| @[inline, inherit_doc ExtDHashMap.Const.getD] | |
| def getD [EquivBEq α] [LawfulHashable α] (m : ExtHashMap α β) (a : α) | |
| (fallback : β) : β := | |
| ExtDHashMap.Const.getD m.inner a fallback | |
| /-- | |
| The notation `m[a]!` is preferred over calling this function directly. | |
| Tries to retrieve the mapping for the given key, panicking if no such mapping is present. | |
| -/ | |
| @[inline] | |
| def get! [EquivBEq α] [LawfulHashable α] [Inhabited β] (m : ExtHashMap α β) (a : α) : β := | |
| ExtDHashMap.Const.get! m.inner a | |
| instance [BEq α] [Hashable α] [EquivBEq α] [LawfulHashable α] : | |
| GetElem? (ExtHashMap α β) α β (fun m a => a ∈ m) where | |
| getElem m a h := m.get a h | |
| getElem? m a := m.get? a | |
| getElem! m a := m.get! a | |
| @[inline, inherit_doc ExtDHashMap.getKey?] | |
| def getKey? [EquivBEq α] [LawfulHashable α] (m : ExtHashMap α β) (a : α) : Option α := | |
| ExtDHashMap.getKey? m.inner a | |
| @[inline, inherit_doc ExtDHashMap.getKey] | |
| def getKey [EquivBEq α] [LawfulHashable α] (m : ExtHashMap α β) (a : α) (h : a ∈ m) : α := | |
| ExtDHashMap.getKey m.inner a h | |
| @[inline, inherit_doc ExtDHashMap.getKeyD] | |
| def getKeyD [EquivBEq α] [LawfulHashable α] (m : ExtHashMap α β) (a : α) (fallback : α) : α := | |
| ExtDHashMap.getKeyD m.inner a fallback | |
| @[inline, inherit_doc ExtDHashMap.getKey!] | |
| def getKey! [EquivBEq α] [LawfulHashable α] [Inhabited α] (m : ExtHashMap α β) (a : α) : α := | |
| ExtDHashMap.getKey! m.inner a | |
| @[inline, inherit_doc ExtDHashMap.erase] | |
| def erase [EquivBEq α] [LawfulHashable α] (m : ExtHashMap α β) (a : α) : | |
| ExtHashMap α β := | |
| ⟨m.inner.erase a⟩ | |
| @[inline, inherit_doc ExtDHashMap.size] | |
| def size [EquivBEq α] [LawfulHashable α] (m : ExtHashMap α β) : Nat := | |
| m.inner.size | |
| @[inline, inherit_doc ExtDHashMap.isEmpty] | |
| def isEmpty [EquivBEq α] [LawfulHashable α] (m : ExtHashMap α β) : Bool := | |
| m.inner.isEmpty | |
| @[inline, inherit_doc ExtDHashMap.Const.ofList] | |
| def ofList [BEq α] [Hashable α] (l : List (α × β)) : | |
| ExtHashMap α β := | |
| ⟨ExtDHashMap.Const.ofList l⟩ | |
| @[inline, inherit_doc ExtDHashMap.Const.unitOfList] | |
| def unitOfList [BEq α] [Hashable α] (l : List α) : | |
| ExtHashMap α Unit := | |
| ⟨ExtDHashMap.Const.unitOfList l⟩ | |
| @[inline, inherit_doc ExtDHashMap.filter] | |
| def filter [EquivBEq α] [LawfulHashable α] (f : α → β → Bool) | |
| (m : ExtHashMap α β) : ExtHashMap α β := | |
| ⟨m.inner.filter f⟩ | |
| @[inline, inherit_doc ExtDHashMap.map] | |
| def map [EquivBEq α] [LawfulHashable α] (f : α → β → γ) | |
| (m : ExtHashMap α β) : ExtHashMap α γ := | |
| ⟨m.inner.map f⟩ | |
| @[inline, inherit_doc ExtDHashMap.filterMap] | |
| def filterMap [EquivBEq α] [LawfulHashable α] (f : α → β → Option γ) | |
| (m : ExtHashMap α β) : ExtHashMap α γ := | |
| ⟨m.inner.filterMap f⟩ | |
| @[inline, inherit_doc ExtDHashMap.modify] | |
| def modify [EquivBEq α] [LawfulHashable α] (m : ExtHashMap α β) (a : α) (f : β → β) : | |
| ExtHashMap α β := | |
| ⟨ExtDHashMap.Const.modify m.inner a f⟩ | |
| @[inline, inherit_doc ExtDHashMap.alter] | |
| def alter [EquivBEq α] [LawfulHashable α] (m : ExtHashMap α β) (a : α) | |
| (f : Option β → Option β) : ExtHashMap α β := | |
| ⟨ExtDHashMap.Const.alter m.inner a f⟩ | |
| @[inline, inherit_doc ExtDHashMap.Const.insertMany] | |
| def insertMany [EquivBEq α] [LawfulHashable α] {ρ : Type w} | |
| [ForIn Id ρ (α × β)] (m : ExtHashMap α β) (l : ρ) : ExtHashMap α β := | |
| ⟨ExtDHashMap.Const.insertMany m.inner l⟩ | |
| @[inline, inherit_doc ExtDHashMap.Const.insertManyIfNewUnit] | |
| def insertManyIfNewUnit [EquivBEq α] [LawfulHashable α] | |
| {ρ : Type w} [ForIn Id ρ α] (m : ExtHashMap α Unit) (l : ρ) : ExtHashMap α Unit := | |
| ⟨ExtDHashMap.Const.insertManyIfNewUnit m.inner l⟩ | |
| @[inline, inherit_doc ExtDHashMap.Const.unitOfArray] | |
| def unitOfArray [BEq α] [Hashable α] (l : Array α) : | |
| ExtHashMap α Unit := | |
| ⟨ExtDHashMap.Const.unitOfArray l⟩ | |
| end Std.ExtHashMap |