### Parameters

`Key : Core.Hashable`

### Signature

`type ('state, 'job_tag) t`````

Every `Key.t` in the table has an associated `state`, which each job running on that key gets access to. Jobs maybe have an associated `job_tag` which is provided purely to assist debugging, as the tag is included in the sexp serialization of `t`.

`include sig ... end`
`val sexp_of_t : ('state ‑> Base.Sexp.t) ‑> ('job_tag ‑> Base.Sexp.t) ‑> ('state, 'job_tag) t ‑> Base.Sexp.t`
`val create : unit ‑> (_, _) t`
`val enqueue : ('state, 'job_tag) t ‑> key:Key.t ‑> ?⁠tag:'job_tag ‑> ('state option ‑> 'b Async.Deferred.t) ‑> 'b Async.Deferred.t`

`enqueue t ~key f` enqueues `f` for `key`. `f` will be called with the state of `key` when invoked.

Invariant 1: it is guaranteed that `f` will not be called immediately.

Invariant 2: if `f` raises, then the exception will be raised to the monitor in effect when `enqueue` was called. Subsequent jobs for `key` will proceed.

Invariant 3: to avoid race, there are no deferred operations between finding the state and calling `f` with the state found. Otherwise, the user would need to consider the race that the state passed to `f` might have been changed by `set_state`.

`val set_state : ('state, _) t ‑> key:Key.t ‑> 'state option ‑> unit`

`set_state t key state_opt` sets the state for `key` immediately. The state will be kept internally until set to `None`

`val find_state : ('state, _) t ‑> Key.t ‑> 'state option`
`val num_unfinished_jobs : (_, _) t ‑> Key.t ‑> int`

`num_unfinished_jobs t key` returns the number of jobs for `key` including including pending and running.

`val mem : (_, _) t ‑> Key.t ‑> bool`

`mem t key` returns `true` if there is state or an pending/running job

`val fold : ('state, _) t ‑> init:'b ‑> f:('b ‑> key:Key.t ‑> 'state option ‑> 'b) ‑> 'b`

Fold over keys with states or pending/running jobs. It's safe to mutate (`enqueue` or `set_state`) when folding

`val prior_jobs_done : (_, _) t ‑> unit Async.Deferred.t`

The result is determined when all jobs enqueued before this are finished. The implementation adds a new job to every key currently with at least one running job attached, so it will affect `num_unfinished_jobs`