A hashtable that keeps a weak pointer to each key's data and uses a finalizer to detect when the data is no longer referenced (by any non-weak pointers).
Once a key's data is finalized, the table will effectively behave as if the key is not
in the table, e.g. find
will return None
. However, one must call
reclaim_space_for_keys_with_unused_data
to actually reclaim the space used by the
table for such keys.
Unlike (OCaml's) Weak.Make
, which also describes itself as a "weak hashtable,"
Weak_hashtbl
gives a dictionary style structure. In fact, OCaml's Weak.Make
may
better be described as a weak set.
There's a tricky type of bug one can write with this module, e.g.:
type t =
{ foo : string
; bar : float Incr.t
}
let tbl = Weak_hashtbl.create ()
let x1 =
let t = Weak_hashtbl.find_or_add tbl key ~default:(fun () ->
(... some function that computes a t...))
in
t.bar
At this point, the data associated with key
is unreachable (since all we did with it
was project out field bar), so it may disappear from the table at any time.
include sig ... end
val sexp_of_t : ('a ‑> Sexplib.Sexp.t) ‑> ('b ‑> Sexplib.Sexp.t) ‑> ('a, 'b) t ‑> Sexplib.Sexp.t
val create : ?growth_allowed:bool ‑> ?size:int ‑> 'a Core__.Import.Hashtbl.Hashable.t ‑> ('a, 'b) t
growth_allowed
and size
are both optionally passed on to the underlying call to
Hashtbl.create
.
val mem : ('a, _) t ‑> 'a ‑> bool
val find : ('a, 'b) t ‑> 'a ‑> 'b Core__.Import.Heap_block.t option
val find_or_add : ('a, 'b) t ‑> 'a ‑> default:(unit ‑> 'b Core__.Import.Heap_block.t) ‑> 'b Core__.Import.Heap_block.t
val remove : ('a, 'b) t ‑> 'a ‑> unit
val add_exn : ('a, 'b) t ‑> key:'a ‑> data:'b Core__.Import.Heap_block.t ‑> unit
val replace : ('a, 'b) t ‑> key:'a ‑> data:'b Core__.Import.Heap_block.t ‑> unit
val key_is_using_space : ('a, _) t ‑> 'a ‑> bool
key_is_using_space t key
returns true
if key
is using some space in t
. mem t
key
implies key_is_using_space t key
, but it is also possible that that
key_is_using_space t key && not (mem t key)
.
val reclaim_space_for_keys_with_unused_data : (_, _) t ‑> unit
reclaim_space_for_keys_with_unused_data t
reclaims space for all keys in t
whose
data has been detected (by a finalizer) to be unused. Only key
s such that
key_is_using_space t key && not (mem t key)
will be reclaimed.
val set_run_when_unused_data : (_, _) t ‑> thread_safe_f:(unit ‑> unit) ‑> unit
set_run_when_unused_data t ~thread_safe_f
calls thread_safe_f
in the finalizer
attached to each data
in t
, after ensuring the entry being finalized will be
handled in the next call to reclaim_space_for_keys_with_unused_data
. This can be
used to arrange to call reclaim_space_for_keys_with_unused_data
at a convenient time
in the future. thread_safe_f
must be thread safe -- it is *not* safe for it to call
any Weak_hashtbl
functions.