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.

`type ``('a, 'b) `

t

`val create : ``'a Std_internal.Hashtbl.Hashable.t -> ('a, 'b) t`

`val mem : ``('a, 'b) t -> 'a -> bool`

`val find : ``('a, 'b) t -> 'a -> 'b Heap_block.t option`

`val find_or_add : ``('a, 'b) t -> 'a -> default:(unit -> 'b Heap_block.t) -> 'b Heap_block.t`

`val remove : ``('a, 'b) t -> 'a -> unit`

`val add_exn : ``('a, 'b) t -> key:'a -> data:'b Heap_block.t -> unit`

`val replace : ``('a, 'b) t -> key:'a -> data:'b Heap_block.t -> unit`

`val key_is_using_space : ``('a, 'b) 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 : ``('a, 'b) 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 : ``('a, 'b) 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.`val sexp_of_t : ````
('a -> Sexplib.Sexp.t) ->
('b -> Sexplib.Sexp.t) -> ('a, 'b) t -> Sexplib.Sexp.t
```