lean4-htt/library/init/lean/smap.lean
Leonardo de Moura 7212fbab6e perf(library/init/lean/environment): search hashmap first
Hypothesis: the vast majority of Environment queries try to access
imported constants instead of local ones.
2019-05-15 11:01:25 -07:00

79 lines
2.9 KiB
Text
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/-
Copyright (c) 2019 Microsoft Corporation. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Authors: Leonardo de Moura
-/
prelude
import init.data.hashmap init.data.rbmap
universes u v w w'
namespace Lean
/- Staged map for implementing the Environment. The idea is to store
imported entries into a hashtable and local entries into a red-black tree.
Hypotheses:
- The number of entries (i.e., declarations) coming from imported files is much bigger than
the number of entries in the current file.
- HashMap is faster than RBMap.
- When we are reading imported files, we have exclusive access to the map, and efficient
destructive updates are performed.
Remarks:
- We never remove declarations from the Environment. In principle, we could support
deletion by using `(RBMap α (Option β) lt)` where the value `none` would indicate
that an entry was "removed" from the hashtable.
- We do not need additional bookkeeping for extracting the local entries.
-/
structure SMap (α : Type u) (β : Type v) (lt : αα → Bool) [HasBeq α] [Hashable α] :=
(stage₁ : Bool := true)
(map₁ : HashMap α β := {})
(map₂ : RBMap α β lt := {})
namespace SMap
variables {α : Type u} {β : Type v} {lt : αα → Bool} [HasBeq α] [Hashable α]
instance : Inhabited (SMap α β lt) := ⟨{}⟩
def empty : SMap α β lt := {}
instance : HasEmptyc (SMap α β lt) := ⟨SMap.empty⟩
@[specialize] def insert : SMap α β lt → α → β → SMap α β lt
| ⟨true, m₁, m₂⟩ k v := ⟨true, m₁.insert k v, m₂⟩
| ⟨false, m₁, m₂⟩ k v := ⟨false, m₁, m₂.insert k v⟩
@[specialize] def find : SMap α β lt → α → Option β
| ⟨true, m₁, _⟩ k := m₁.find k
| ⟨false, m₁, m₂⟩ k := (m₂.find k).orelse (m₁.find k)
@[specialize] def contains : SMap α β lt → α → Bool
| ⟨true, m₁, _⟩ k := m₁.contains k
| ⟨false, m₁, m₂⟩ k := m₁.contains k || m₂.contains k
/- Similar to `find`, but searches for result in the hashmap first.
So, the result is correct only if we never "overwrite" `map₁` entries using `map₂`. -/
@[specialize] def find' : SMap α β lt → α → Option β
| ⟨true, m₁, _⟩ k := m₁.find k
| ⟨false, m₁, m₂⟩ k := (m₁.find k).orelse (m₂.find k)
/- Move from stage 1 into stage 2. -/
def switch (m : SMap α β lt) : SMap α β lt :=
if m.stage₁ then { stage₁ := false, .. m } else m
@[inline] def foldStage2 {σ : Type w} (f : σα → β → σ) (s : σ) (m : SMap α β lt) : σ :=
m.map₂.fold f s
def size (m : SMap α β lt) : Nat :=
m.map₁.size + m.map₂.size
def stageSizes (m : SMap α β lt) : Nat × Nat :=
(m.map₁.size, m.map₂.size)
def maxDepth (m : SMap α β lt) : Nat :=
m.map₂.maxDepth
def numBuckets (m : SMap α β lt) : Nat :=
m.map₁.numBuckets
end SMap
end Lean