lean4-htt/src/Lean/Data/SMap.lean
Sebastian Ullrich 8e6f2750da
fix: namespace used in private import and current module vanishes dowstream (#12840)
This PR fixes an issue where the use of private imports led to unknown
namespaces in downstream modules.

Fixes #12833
2026-03-20 13:27:26 +00:00

124 lines
4.5 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
-/
module
prelude
public import Std.Data.HashMap.Basic
public import Lean.Data.PersistentHashMap
public import Std.Data.HashMap.Iterator
public import Lean.Data.Iterators.Producers.PersistentHashMap
public import Init.Data.Iterators.Combinators.Append
public section
universe 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 persistent hashtable.
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 PersistentHashMap.
- 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 `(PHashMap α (Option β))` 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) [BEq α] [Hashable α] where
stage₁ : Bool := true
/-- Imported constants. -/
map₁ : Std.HashMap α β := {}
/-- Local constants defined in the current module. -/
map₂ : PHashMap α β := {}
namespace SMap
variable {α : Type u} {β : Type v} [BEq α] [Hashable α]
instance : Inhabited (SMap α β) := ⟨{}⟩
def empty : SMap α β := {}
@[inline] def fromHashMap (m : Std.HashMap α β) (stage₁ := true) : SMap α β :=
{ map₁ := m, stage₁ := stage₁ }
@[specialize] def insert : SMap α β → α → β → SMap α β
| ⟨true, m₁, m₂⟩, k, v => ⟨true, m₁.insert k v, m₂⟩
| ⟨false, m₁, m₂⟩, k, v => ⟨false, m₁, m₂.insert k v⟩
@[specialize] def insert' : SMap α β → α → β → SMap α β
| ⟨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 α β → α → Option β
| ⟨true, m₁, _⟩, k => m₁[k]?
| ⟨false, m₁, m₂⟩, k => (m₂.find? k).orElse fun _ => m₁[k]?
@[inline] def findD (m : SMap α β) (a : α) (b₀ : β) : β :=
(m.find? a).getD b₀
@[inline] def find! [Inhabited β] (m : SMap α β) (a : α) : β :=
match m.find? a with
| some b => b
| none => panic! "key is not in the map"
@[specialize] def contains : SMap α β → α → 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 α β → α → Option β
| ⟨true, m₁, _⟩, k => m₁[k]?
| ⟨false, m₁, m₂⟩, k => m₁[k]?.orElse fun _ => m₂.find? k
def forM [Monad m] (s : SMap α β) (f : α → β → m PUnit) : m PUnit := do
s.map₁.forM f
s.map₂.forM f
instance [Monad m] : ForM m (SMap α β) (α × β) where
forM s f := forM s fun x y => f (x, y)
instance [Monad m] : ForIn m (SMap α β) (α × β) where
forIn := ForM.forIn
def iter (s : SMap α β) :=
s.map₁.iter.append s.map₂.iter
/-- Move from stage 1 into stage 2. -/
def switch (m : SMap α β) : SMap α β :=
if m.stage₁ then { m with stage₁ := false } else m
@[inline] def foldStage2 {σ : Type w} (f : σα → β → σ) (s : σ) (m : SMap α β) : σ :=
m.map₂.foldl f s
/-- Monadic fold over a staged map. -/
def foldM {m : Type w → Type w'} [Monad m]
(f : σα → β → m σ) (init : σ) (map : SMap α β) : m σ := do
map.map₂.foldlM f (← map.map₁.foldM f init)
def fold {σ : Type w} (f : σα → β → σ) (init : σ) (m : SMap α β) : σ :=
m.map₂.foldl f $ m.map₁.fold f init
def numBuckets (m : SMap α β) : Nat :=
Std.HashMap.Internal.numBuckets m.map₁
def toList (m : SMap α β) : List (α × β) :=
m.fold (init := []) fun es a b => (a, b)::es
end SMap
def _root_.List.toSMap [BEq α] [Hashable α] (es : List (α × β)) : SMap α β :=
es.foldl (init := {}) fun s (a, b) => s.insert a b
instance {_ : BEq α} {_ : Hashable α} [Repr α] [Repr β] : Repr (SMap α β) where
reprPrec v prec := Repr.addAppParen (reprArg v.toList ++ ".toSMap") prec
end Lean