This makes changes to the `GetElem` class so that it does not lead to unnecessary overhead in container like `RBMap`. The changes are to: 1. Make `getElem?` and `getElem!` part of the `GetElem` class so they can be overridden in instances. 2. Introduce a `LawfulGetElem` class that contains correctness theorems for `getElem?` and `getElem!` using the original definitions. 3. Reorganize definitions (e.g, by moving `GetElem` out of `Init.Prelude`) so that the `GetElem` changes are feasible. 4. Provide `LawfulGetElem` instances to complement all existing `GetElem` instances in Lean core. To reduce the size of the PR, this doesn't do the work of providing new `GetElem` instances for `RBMap`, `HashMap` etc. That will be done in a separate PR (#3688) that depends on this. --------- Co-authored-by: Mac Malone <tydeu@hatpress.net>
92 lines
4.1 KiB
Text
92 lines
4.1 KiB
Text
/-
|
||
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.String.Basic
|
||
import Init.Data.ToString.Basic
|
||
|
||
universe u v
|
||
|
||
/-! # Debugging helper functions -/
|
||
|
||
set_option linter.unusedVariables.funArgs false in
|
||
@[never_extract, extern "lean_dbg_trace"]
|
||
def dbgTrace {α : Type u} (s : String) (f : Unit → α) : α := f ()
|
||
|
||
def dbgTraceVal {α : Type u} [ToString α] (a : α) : α :=
|
||
dbgTrace (toString a) (fun _ => a)
|
||
|
||
set_option linter.unusedVariables.funArgs false in
|
||
/-- Display the given message if `a` is shared, that is, RC(a) > 1 -/
|
||
@[never_extract, extern "lean_dbg_trace_if_shared"]
|
||
def dbgTraceIfShared {α : Type u} (s : String) (a : α) : α := a
|
||
|
||
/-- Print stack trace to stderr before evaluating given closure. Currently supported on Linux only. -/
|
||
@[never_extract, extern "lean_dbg_stack_trace"]
|
||
def dbgStackTrace {α : Type u} (f : Unit → α) : α := f ()
|
||
|
||
@[extern "lean_dbg_sleep"]
|
||
def dbgSleep {α : Type u} (ms : UInt32) (f : Unit → α) : α := f ()
|
||
|
||
@[noinline] private def mkPanicMessage (modName : String) (line col : Nat) (msg : String) : String :=
|
||
"PANIC at " ++ modName ++ ":" ++ toString line ++ ":" ++ toString col ++ ": " ++ msg
|
||
|
||
@[never_extract, inline] def panicWithPos {α : Type u} [Inhabited α] (modName : String) (line col : Nat) (msg : String) : α :=
|
||
panic (mkPanicMessage modName line col msg)
|
||
|
||
@[noinline] private def mkPanicMessageWithDecl (modName : String) (declName : String) (line col : Nat) (msg : String) : String :=
|
||
"PANIC at " ++ declName ++ " " ++ modName ++ ":" ++ toString line ++ ":" ++ toString col ++ ": " ++ msg
|
||
|
||
@[never_extract, inline] def panicWithPosWithDecl {α : Type u} [Inhabited α] (modName : String) (declName : String) (line col : Nat) (msg : String) : α :=
|
||
panic (mkPanicMessageWithDecl modName declName line col msg)
|
||
|
||
@[extern "lean_ptr_addr"]
|
||
unsafe opaque ptrAddrUnsafe {α : Type u} (a : @& α) : USize
|
||
|
||
set_option linter.unusedVariables.funArgs false in
|
||
@[inline] unsafe def withPtrAddrUnsafe {α : Type u} {β : Type v} (a : α) (k : USize → β) (h : ∀ u₁ u₂, k u₁ = k u₂) : β :=
|
||
k (ptrAddrUnsafe a)
|
||
|
||
@[inline] unsafe def ptrEq (a b : α) : Bool := ptrAddrUnsafe a == ptrAddrUnsafe b
|
||
|
||
unsafe def ptrEqList : (as bs : List α) → Bool
|
||
| [], [] => true
|
||
| a::as, b::bs => if ptrEq a b then ptrEqList as bs else false
|
||
| _, _ => false
|
||
|
||
set_option linter.unusedVariables.funArgs false in
|
||
@[inline] unsafe def withPtrEqUnsafe {α : Type u} (a b : α) (k : Unit → Bool) (h : a = b → k () = true) : Bool :=
|
||
if ptrEq a b then true else k ()
|
||
|
||
@[implemented_by withPtrEqUnsafe]
|
||
def withPtrEq {α : Type u} (a b : α) (k : Unit → Bool) (h : a = b → k () = true) : Bool := k ()
|
||
|
||
/-- `withPtrEq` for `DecidableEq` -/
|
||
@[inline] def withPtrEqDecEq {α : Type u} (a b : α) (k : Unit → Decidable (a = b)) : Decidable (a = b) :=
|
||
let b := withPtrEq a b (fun _ => toBoolUsing (k ())) (toBoolUsing_eq_true (k ()));
|
||
match h:b with
|
||
| true => isTrue (ofBoolUsing_eq_true h)
|
||
| false => isFalse (ofBoolUsing_eq_false h)
|
||
|
||
@[implemented_by withPtrAddrUnsafe]
|
||
def withPtrAddr {α : Type u} {β : Type v} (a : α) (k : USize → β) (h : ∀ u₁ u₂, k u₁ = k u₂) : β := k 0
|
||
|
||
/--
|
||
Marks given value and its object graph closure as multi-threaded if currently
|
||
marked single-threaded. This will make reference counter updates atomic and
|
||
thus more costly. It can still be useful to do eagerly when the value will be
|
||
shared between threads later anyway and there is available time budget to mark
|
||
it now. -/
|
||
@[extern "lean_runtime_mark_multi_threaded"]
|
||
def Runtime.markMultiThreaded (a : α) : α := a
|
||
|
||
/--
|
||
Marks given value and its object graph closure as persistent. This will remove
|
||
reference counter updates but prevent the closure from being deallocated until
|
||
the end of the process! It can still be useful to do eagerly when the value
|
||
will be marked persistent later anyway and there is available time budget to
|
||
mark it now or it would be unnecessarily marked multi-threaded in between. -/
|
||
@[extern "lean_runtime_mark_persistent"]
|
||
def Runtime.markPersistent (a : α) : α := a
|