123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885open!Import(** @canonical Base.Hashtbl.Key *)moduleKey=structmoduletypeS=sigtypet[@@deriving_inlinecompare,sexp_of]includePpx_compare_lib.Comparable.Swithtypet:=tvalsexp_of_t:t->Sexplib0.Sexp.t[@@@end](** Two [t]s that [compare] equal must have equal hashes for the hashtable
to behave properly. *)valhash:t->intendtype'at=(moduleSwithtypet='a)end(** @canonical Base.Hashtbl.Merge_into_action *)moduleMerge_into_action=structtype'at=|Remove|Set_toof'aendmoduletypeAccessors=sig(** {2 Accessors} *)type('a,'b)ttype'akeyvalsexp_of_key:('a,_)t->'akey->Sexp.tvalclear:(_,_)t->unitvalcopy:('a,'b)t->('a,'b)t(** Attempting to modify ([set], [remove], etc.) the hashtable during iteration ([fold],
[iter], [iter_keys], [iteri]) will raise an exception. *)valfold:('a,'b)t->init:'acc->f:((key:'akey->data:'b->'acc->'acc)[@local])->'accvaliter_keys:('a,_)t->f:(('akey->unit)[@local])->unitvaliter:(_,'b)t->f:(('b->unit)[@local])->unit(** Iterates over both keys and values.
Example:
{v
let h = Hashtbl.of_alist_exn (module Int) [(1, 4); (5, 6)] in
Hashtbl.iteri h ~f:(fun ~key ~data ->
print_endline (Printf.sprintf "%d-%d" key data));;
1-4
5-6
- : unit = ()
v} *)valiteri:('a,'b)t->f:((key:'akey->data:'b->unit)[@local])->unitvalexistsi:('a,'b)t->f:((key:'akey->data:'b->bool)[@local])->boolvalexists:(_,'b)t->f:(('b->bool)[@local])->boolvalfor_alli:('a,'b)t->f:((key:'akey->data:'b->bool)[@local])->boolvalfor_all:(_,'b)t->f:(('b->bool)[@local])->boolvalcounti:('a,'b)t->f:((key:'akey->data:'b->bool)[@local])->intvalcount:(_,'b)t->f:(('b->bool)[@local])->intvallength:(_,_)t->intvalis_empty:(_,_)t->boolvalmem:('a,_)t->'akey->boolvalremove:('a,_)t->'akey->unit(** Choose an arbitrary key/value pair of a hash table. Returns [None] if [t] is empty.
The choice is deterministic. Calling [choose] multiple times on the same table
returns the same key/value pair, so long as the table is not mutated in between.
Beyond determinism, no guarantees are made about how the choice is made. Expect
bias toward certain hash values.
This hash bias can lead to degenerate performance in some cases, such as clearing
a hash table using repeated [choose] and [remove]. At each iteration, finding the
next element may have to scan farther from its initial hash value. *)valchoose:('a,'b)t->('akey*'b)option(** Like [choose]. Raises if [t] is empty. *)valchoose_exn:('a,'b)t->'akey*'b(** Chooses a random key/value pair of a hash table. Returns [None] if [t] is empty.
The choice is distributed uniformly across hash values, rather than across keys
themselves. As a consequence, the closer the keys are to evenly spaced out in the
table, the closer this function will be to a uniform choice of keys.
This function may be preferable to [choose] when nondeterministic choice is
acceptable, and bias toward certain hash values is undesirable. *)valchoose_randomly:?random_state:Random.State.t(** default: [Random.State.default] *)->('a,'b)t->('akey*'b)option(** Like [choose_randomly]. Raises if [t] is empty. *)valchoose_randomly_exn:?random_state:Random.State.t(** default: [Random.State.default] *)->('a,'b)t->'akey*'b(** Sets the given [key] to [data]. *)valset:('a,'b)t->key:'akey->data:'b->unit(** [add] and [add_exn] leave the table unchanged if the key was already present. *)valadd:('a,'b)t->key:'akey->data:'b->[`Ok|`Duplicate]valadd_exn:('a,'b)t->key:'akey->data:'b->unit(** [change t key ~f] changes [t]'s value for [key] to be [f (find t key)]. *)valchange:('a,'b)t->'akey->f:(('boption->'boption)[@local])->unit(** [update t key ~f] is [change t key ~f:(fun o -> Some (f o))]. *)valupdate:('a,'b)t->'akey->f:(('boption->'b)[@local])->unit(** [update_and_return t key ~f] is [update], but returns the result of [f o]. *)valupdate_and_return:('a,'b)t->'akey->f:(('boption->'b)[@local])->'b(** [map t f] returns a new table with values replaced by the result of applying [f]
to the current values.
Example:
{v
let h = Hashtbl.of_alist_exn (module Int) [(1, 4); (5, 6)] in
let h' = Hashtbl.map h ~f:((fun x -> x * 2)[@local]) in
Hashtbl.to_alist h';;
- : (int * int) list = [(5, 12); (1, 8)]
v} *)valmap:('a,'b)t->f:(('b->'c)[@local])->('a,'c)t(** Like [map], but the function [f] takes both key and data as arguments. *)valmapi:('a,'b)t->f:((key:'akey->data:'b->'c)[@local])->('a,'c)t(** Returns a new table by filtering the given table's values by [f]: the keys for which
[f] applied to the current value returns [Some] are kept, and those for which it
returns [None] are discarded.
Example:
{v
let h = Hashtbl.of_alist_exn (module Int) [(1, 4); (5, 6)] in
Hashtbl.filter_map h ~f:((fun x -> if x > 5 then Some x else None)[@local])
|> Hashtbl.to_alist;;
- : (int * int) list = [(5, 6)]
v} *)valfilter_map:('a,'b)t->f:(('b->'coption)[@local])->('a,'c)t(** Like [filter_map], but the function [f] takes both key and data as arguments. *)valfilter_mapi:('a,'b)t->f:((key:'akey->data:'b->'coption)[@local])->('a,'c)tvalfilter_keys:('a,'b)t->f:(('akey->bool)[@local])->('a,'b)tvalfilter:('a,'b)t->f:(('b->bool)[@local])->('a,'b)tvalfilteri:('a,'b)t->f:((key:'akey->data:'b->bool)[@local])->('a,'b)t(** Returns new tables with bound values partitioned by [f] applied to the bound
values. *)valpartition_map:('a,'b)t->f:(('b->('c,'d)Either.t)[@local])->('a,'c)t*('a,'d)t(** Like [partition_map], but the function [f] takes both key and data as arguments. *)valpartition_mapi:('a,'b)t->f:((key:'akey->data:'b->('c,'d)Either.t)[@local])->('a,'c)t*('a,'d)t(** Returns a pair of tables [(t1, t2)], where [t1] contains all the elements of the
initial table which satisfy the predicate [f], and [t2] contains the rest. *)valpartition_tf:('a,'b)t->f:(('b->bool)[@local])->('a,'b)t*('a,'b)t(** Like [partition_tf], but the function [f] takes both key and data as arguments. *)valpartitioni_tf:('a,'b)t->f:((key:'akey->data:'b->bool)[@local])->('a,'b)t*('a,'b)t(** [find_or_add t k ~default] returns the data associated with key [k] if it is in the
table [t], and otherwise assigns [k] the value returned by [default ()]. *)valfind_or_add:('a,'b)t->'akey->default:((unit->'b)[@local])->'b(** Like [find_or_add] but [default] takes the key as an argument. *)valfindi_or_add:('a,'b)t->'akey->default:(('akey->'b)[@local])->'b(** [find t k] returns [Some] (the current binding) of [k] in [t], or [None] if no such
binding exists. *)valfind:('a,'b)t->'akey->'boption(** [find_exn t k] returns the current binding of [k] in [t], or raises [Stdlib.Not_found]
or [Not_found_s] if no such binding exists. *)valfind_exn:('a,'b)t->'akey->'b(** [find_and_call t k ~if_found ~if_not_found]
is equivalent to:
[match find t k with Some v -> if_found v | None -> if_not_found k]
except that it doesn't allocate the option. *)valfind_and_call:('a,'b)t->'akey->if_found:(('b->'c)[@local])->if_not_found:(('akey->'c)[@local])->'c(** Just like [find_and_call], but takes an extra argument which is passed to [if_found]
and [if_not_found], so that the client code can avoid allocating closures or using
refs to pass this additional information. This function is only useful in code
which tries to minimize heap allocation. *)valfind_and_call1:('a,'b)t->'akey->a:'d->if_found:(('b->'d->'c)[@local])->if_not_found:(('akey->'d->'c)[@local])->'cvalfind_and_call2:('a,'b)t->'akey->a:'d->b:'e->if_found:(('b->'d->'e->'c)[@local])->if_not_found:(('akey->'d->'e->'c)[@local])->'cvalfindi_and_call:('a,'b)t->'akey->if_found:((key:'akey->data:'b->'c)[@local])->if_not_found:(('akey->'c)[@local])->'cvalfindi_and_call1:('a,'b)t->'akey->a:'d->if_found:((key:'akey->data:'b->'d->'c)[@local])->if_not_found:(('akey->'d->'c)[@local])->'cvalfindi_and_call2:('a,'b)t->'akey->a:'d->b:'e->if_found:((key:'akey->data:'b->'d->'e->'c)[@local])->if_not_found:(('akey->'d->'e->'c)[@local])->'c(** [find_and_remove t k] returns Some (the current binding) of k in t and removes it,
or None is no such binding exists. *)valfind_and_remove:('a,'b)t->'akey->'boption(** Merges two hashtables.
The result of [merge f h1 h2] has as keys the set of all [k] in the union of the
sets of keys of [h1] and [h2] for which [d(k)] is not None, where:
d(k) =
- [f ~key:k (`Left d1)]
if [k] in [h1] maps to d1, and [h2] does not have data for [k];
- [f ~key:k (`Right d2)]
if [k] in [h2] maps to d2, and [h1] does not have data for [k];
- [f ~key:k (`Both (d1, d2))]
otherwise, where [k] in [h1] maps to [d1] and [k] in [h2] maps to [d2].
Each key [k] is mapped to a single piece of data [x], where [d(k) = Some x].
Example:
{v
let h1 = Hashtbl.of_alist_exn (module Int) [(1, 5); (2, 3232)] in
let h2 = Hashtbl.of_alist_exn (module Int) [(1, 3)] in
Hashtbl.merge h1 h2 ~f:(fun ~key:_ -> function
| `Left x -> Some (`Left x)
| `Right x -> Some (`Right x)
| `Both (x, y) -> if x=y then None else Some (`Both (x,y))
) |> Hashtbl.to_alist;;
- : (int * [> `Both of int * int | `Left of int | `Right of int ]) list =
[(2, `Left 3232); (1, `Both (5, 3))]
v} *)valmerge:('k,'a)t->('k,'b)t->f:((key:'kkey->[`Leftof'a|`Rightof'b|`Bothof'a*'b]->'coption)[@local])->('k,'c)t(** Every [key] in [src] will be removed or set in [dst] according to the return value
of [f]. *)valmerge_into:src:('k,'a)t->dst:('k,'b)t->f:((key:'kkey->'a->'boption->'bMerge_into_action.t)[@local])->unit(** Returns the list of all keys for given hashtable. *)valkeys:('a,_)t->'akeylist(** Returns the list of all data for given hashtable. *)valdata:(_,'b)t->'blist(** [filter_inplace t ~f] removes all the elements from [t] that don't satisfy [f]. *)valfilter_keys_inplace:('a,_)t->f:(('akey->bool)[@local])->unitvalfilter_inplace:(_,'b)t->f:(('b->bool)[@local])->unitvalfilteri_inplace:('a,'b)t->f:((key:'akey->data:'b->bool)[@local])->unit(** [map_inplace t ~f] applies [f] to all elements in [t], transforming them in
place. *)valmap_inplace:(_,'b)t->f:(('b->'b)[@local])->unitvalmapi_inplace:('a,'b)t->f:((key:'akey->data:'b->'b)[@local])->unit(** [filter_map_inplace] combines the effects of [map_inplace] and [filter_inplace]. *)valfilter_map_inplace:(_,'b)t->f:(('b->'boption)[@local])->unitvalfilter_mapi_inplace:('a,'b)t->f:((key:'akey->data:'b->'boption)[@local])->unit(** [equal f t1 t2] and [similar f t1 t2] both return true iff [t1] and [t2] have the
same keys and for all keys [k], [f (find_exn t1 k) (find_exn t2 k)]. [equal] and
[similar] only differ in their types. *)valequal:('b->'b->bool)->('a,'b)t->('a,'b)t->boolvalsimilar:('b1->'b2->bool)->('a,'b1)t->('a,'b2)t->bool(** Returns the list of all (key, data) pairs for given hashtable. *)valto_alist:('a,'b)t->('akey*'b)list(** [remove_if_zero]'s default is [false]. *)valincr:?by:int->?remove_if_zero:bool->('a,int)t->'akey->unitvaldecr:?by:int->?remove_if_zero:bool->('a,int)t->'akey->unitendmoduletypeMulti=sigtype('a,'b)ttype'akey(** [add_multi t ~key ~data] if [key] is present in the table then cons
[data] on the list, otherwise add [key] with a single element list. *)valadd_multi:('a,'blist)t->key:'akey->data:'b->unit(** [remove_multi t key] updates the table, removing the head of the list bound to
[key]. If the list has only one element (or is empty) then the binding is
removed. *)valremove_multi:('a,_list)t->'akey->unit(** [find_multi t key] returns the empty list if [key] is not present in the table,
returns [t]'s values for [key] otherwise. *)valfind_multi:('a,'blist)t->'akey->'blistendtype('key,'data,'z)create_options=?growth_allowed:bool(** defaults to [true] *)->?size:int(** initial size -- default 0 *)->'keyKey.t->'ztype('key,'data,'z)create_options_without_first_class_module=?growth_allowed:bool(** defaults to [true] *)->?size:int(** initial size -- default 0 *)->'zmoduletypeCreators_generic=sigtype('a,'b)ttype'akeytype('key,'data,'z)create_optionsvalcreate:('akey,'b,unit->('a,'b)t)create_optionsvalof_alist:('akey,'b,('akey*'b)list->[`Okof('a,'b)t|`Duplicate_keyof'akey])create_optionsvalof_alist_report_all_dups:('akey,'b,('akey*'b)list->[`Okof('a,'b)t|`Duplicate_keysof'akeylist])create_optionsvalof_alist_or_error:('akey,'b,('akey*'b)list->('a,'b)tOr_error.t)create_optionsvalof_alist_exn:('akey,'b,('akey*'b)list->('a,'b)t)create_optionsvalof_alist_multi:('akey,'blist,('akey*'b)list->('a,'blist)t)create_options(** {[ create_mapped get_key get_data [x1,...,xn]
= of_alist [get_key x1, get_data x1; ...; get_key xn, get_data xn] ]} *)valcreate_mapped:('akey,'b,get_key:(('r->'akey)[@local])->get_data:(('r->'b)[@local])->'rlist->[`Okof('a,'b)t|`Duplicate_keysof'akeylist])create_options(** {[ create_with_key ~get_key [x1,...,xn]
= of_alist [get_key x1, x1; ...; get_key xn, xn] ]} *)valcreate_with_key:('akey,'r,get_key:(('r->'akey)[@local])->'rlist->[`Okof('a,'r)t|`Duplicate_keysof'akeylist])create_optionsvalcreate_with_key_or_error:('akey,'r,get_key:(('r->'akey)[@local])->'rlist->('a,'r)tOr_error.t)create_optionsvalcreate_with_key_exn:('akey,'r,get_key:(('r->'akey)[@local])->'rlist->('a,'r)t)create_optionsvalgroup:('akey,'b,get_key:(('r->'akey)[@local])->get_data:(('r->'b)[@local])->combine:(('b->'b->'b)[@local])->'rlist->('a,'b)t)create_optionsendmoduletypeCreators=sigtype('a,'b)t(** {2 Creators} *)(** The module you pass to [create] must have a type that is hashable, sexpable, and
comparable.
Example:
{v
Hashtbl.create (module Int);;
- : (int, '_a) Hashtbl.t = <abstr>;;
v} *)valcreate:?growth_allowed:bool(** defaults to [true] *)->?size:int(** initial size -- default 0 *)->'aKey.t->('a,'b)t(** Example:
{v
Hashtbl.of_alist (module Int) [(3, "something"); (2, "whatever")]
- : [ `Duplicate_key of int | `Ok of (int, string) Hashtbl.t ] = `Ok <abstr>
v} *)valof_alist:?growth_allowed:bool(** defaults to [true] *)->?size:int(** initial size -- default 0 *)->'aKey.t->('a*'b)list->[`Okof('a,'b)t|`Duplicate_keyof'a](** Whereas [of_alist] will report [Duplicate_key] no matter how many dups there are in
your list, [of_alist_report_all_dups] will report each and every duplicate entry.
For example:
{v
Hashtbl.of_alist (module Int) [(1, "foo"); (1, "bar"); (2, "foo"); (2, "bar")];;
- : [ `Duplicate_key of int | `Ok of (int, string) Hashtbl.t ] = `Duplicate_key 1
Hashtbl.of_alist_report_all_dups (module Int) [(1, "foo"); (1, "bar"); (2, "foo"); (2, "bar")];;
- : [ `Duplicate_keys of int list | `Ok of (int, string) Hashtbl.t ] = `Duplicate_keys [1; 2]
v} *)valof_alist_report_all_dups:?growth_allowed:bool(** defaults to [true] *)->?size:int(** initial size -- default 0 *)->'aKey.t->('a*'b)list->[`Okof('a,'b)t|`Duplicate_keysof'alist]valof_alist_or_error:?growth_allowed:bool(** defaults to [true] *)->?size:int(** initial size -- default 0 *)->'aKey.t->('a*'b)list->('a,'b)tOr_error.tvalof_alist_exn:?growth_allowed:bool(** defaults to [true] *)->?size:int(** initial size -- default 0 *)->'aKey.t->('a*'b)list->('a,'b)t(** Creates a {{!Multi} "multi"} hashtable, i.e., a hashtable where each key points to a
list potentially containing multiple values. So instead of short-circuiting with a
[`Duplicate_key] variant on duplicates, as in [of_alist], [of_alist_multi] folds
those values into a list for the given key:
{v
let h = Hashtbl.of_alist_multi (module Int) [(1, "a"); (1, "b"); (2, "c"); (2, "d")];;
val h : (int, string list) Hashtbl.t = <abstr>
Hashtbl.find_exn h 1;;
- : string list = ["b"; "a"]
v} *)valof_alist_multi:?growth_allowed:bool(** defaults to [true] *)->?size:int(** initial size -- default 0 *)->'aKey.t->('a*'b)list->('a,'blist)t(** Applies the [get_key] and [get_data] functions to the ['r list] to create the
initial keys and values, respectively, for the new hashtable.
{[ create_mapped get_key get_data [x1;...;xn]
= of_alist [get_key x1, get_data x1; ...; get_key xn, get_data xn]
]}
Example:
{v
let h =
Hashtbl.create_mapped (module Int)
~get_key:((fun x -> x)[@local])
~get_data:((fun x -> x + 1)[@local])
[1; 2; 3];;
val h : [ `Duplicate_keys of int list | `Ok of (int, int) Hashtbl.t ] = `Ok <abstr>
let h =
match h with
| `Ok x -> x
| `Duplicate_keys _ -> failwith ""
in
Hashtbl.find_exn h 1;;
- : int = 2
v} *)valcreate_mapped:?growth_allowed:bool(** defaults to [true] *)->?size:int(** initial size -- default 0 *)->'aKey.t->get_key:(('r->'a)[@local])->get_data:(('r->'b)[@local])->'rlist->[`Okof('a,'b)t|`Duplicate_keysof'alist](** {[ create_with_key ~get_key [x1;...;xn]
= of_alist [get_key x1, x1; ...; get_key xn, xn] ]} *)valcreate_with_key:?growth_allowed:bool(** defaults to [true] *)->?size:int(** initial size -- default 0 *)->'aKey.t->get_key:(('r->'a)[@local])->'rlist->[`Okof('a,'r)t|`Duplicate_keysof'alist]valcreate_with_key_or_error:?growth_allowed:bool(** defaults to [true] *)->?size:int(** initial size -- default 0 *)->'aKey.t->get_key:(('r->'a)[@local])->'rlist->('a,'r)tOr_error.tvalcreate_with_key_exn:?growth_allowed:bool(** defaults to [true] *)->?size:int(** initial size -- default 0 *)->'aKey.t->get_key:(('r->'a)[@local])->'rlist->('a,'r)t(** Like [create_mapped], applies the [get_key] and [get_data] functions to the ['r
list] to create the initial keys and values, respectively, for the new hashtable --
and then, like [add_multi], folds together values belonging to the same keys. Here,
though, the function used for the folding is given by [combine] (instead of just
being a [cons]).
Example:
{v
Hashtbl.group (module Int)
~get_key:((fun x -> x / 2)[@local])
~get_data:((fun x -> x)[@local])
~combine:((fun x y -> x * y)[@local])
[ 1; 2; 3; 4]
|> Hashtbl.to_alist;;
- : (int * int) list = [(2, 4); (1, 6); (0, 1)]
v} *)valgroup:?growth_allowed:bool(** defaults to [true] *)->?size:int(** initial size -- default 0 *)->'aKey.t->get_key:(('r->'a)[@local])->get_data:(('r->'b)[@local])->combine:(('b->'b->'b)[@local])->'rlist->('a,'b)tendmoduletypeS_without_submodules=sigvalhash:'a->intvalhash_param:int->int->'a->inttype(!'a,!'b)t(** We provide a [sexp_of_t] but not a [t_of_sexp] for this type because one needs to be
explicit about the hash and comparison functions used when creating a hashtable.
Note that [Hashtbl.Poly.t] does have [[@@deriving sexp]], and uses OCaml's built-in
polymorphic comparison and and polymorphic hashing. *)valsexp_of_t:('a->Sexp.t)->('b->Sexp.t)->('a,'b)t->Sexp.tincludeCreatorswithtype('a,'b)t:=('a,'b)t(** @inline *)includeAccessorswithtype('a,'b)t:=('a,'b)twithtype'akey='a(** @inline *)includeMultiwithtype('a,'b)t:=('a,'b)twithtype'akey:='akey(** @inline *)valhashable_s:('key,_)t->'keyKey.tincludeInvariant.S2withtype('a,'b)t:=('a,'b)tendmoduletypeS_poly=sigtype('a,'b)t[@@deriving_inlinesexp,sexp_grammar]includeSexplib0.Sexpable.S2withtype('a,'b)t:=('a,'b)tvalt_sexp_grammar:'aSexplib0.Sexp_grammar.t->'bSexplib0.Sexp_grammar.t->('a,'b)tSexplib0.Sexp_grammar.t[@@@end]valhashable:'aHashable.tincludeInvariant.S2withtype('a,'b)t:=('a,'b)tincludeCreators_genericwithtype('a,'b)t:=('a,'b)twithtype'akey='awithtype('key,'data,'z)create_options:=('key,'data,'z)create_options_without_first_class_moduleincludeAccessorswithtype('a,'b)t:=('a,'b)twithtype'akey:='akeyincludeMultiwithtype('a,'b)t:=('a,'b)twithtype'akey:='akeyendmoduletypeFor_deriving=sigtype('k,'v)tmoduletypeSexp_of_m=sigtypet[@@deriving_inlinesexp_of]valsexp_of_t:t->Sexplib0.Sexp.t[@@@end]endmoduletypeM_of_sexp=sigtypet[@@deriving_inlineof_sexp]valt_of_sexp:Sexplib0.Sexp.t->t[@@@end]includeKey.Swithtypet:=tendmoduletypeM_sexp_grammar=sigtypet[@@deriving_inlinesexp_grammar]valt_sexp_grammar:tSexplib0.Sexp_grammar.t[@@@end]endmoduletypeEqual_m=sigendvalsexp_of_m__t:(moduleSexp_of_mwithtypet='k)->('v->Sexp.t)->('k,'v)t->Sexp.tvalm__t_of_sexp:(moduleM_of_sexpwithtypet='k)->(Sexp.t->'v)->Sexp.t->('k,'v)tvalm__t_sexp_grammar:(moduleM_sexp_grammarwithtypet='k)->'vSexplib0.Sexp_grammar.t->('k,'v)tSexplib0.Sexp_grammar.tvalequal_m__t:(moduleEqual_m)->('v->'v->bool)->('k,'v)t->('k,'v)t->boolendmoduletypeHashtbl=sig(** A hash table is a mutable data structure implementing a map between keys and values.
It supports constant-time lookup and in-place modification.
{1 Usage}
As a simple example, we'll create a hash table with string keys using the
{{!create}[create]} constructor, which expects a module defining the key's type:
{[
let h = Hashtbl.create (module String);;
val h : (string, '_a) Hashtbl.t = <abstr>
]}
We can set the values of individual keys with {{!set}[set]}. If the key already has
a value, it will be overwritten.
{v
Hashtbl.set h ~key:"foo" ~data:5;;
- : unit = ()
Hashtbl.set h ~key:"foo" ~data:6;;
- : unit = ()
Hashtbl.set h ~key:"bar" ~data:6;;
- : unit = ()
v}
We can access values by key, or dump all of the hash table's data:
{v
Hashtbl.find h "foo";;
- : int option = Some 6
Hashtbl.find_exn h "foo";;
- : int = 6
Hashtbl.to_alist h;;
- : (string * int) list = [("foo", 6); ("bar", 6)]
v}
{{!change}[change]} lets us change a key's value by applying the given function:
{v
Hashtbl.change h "foo" (fun x ->
match x with
| Some x -> Some (x * 2)
| None -> None
);;
- : unit = ()
Hashtbl.to_alist h;;
- : (string * int) list = [("foo", 12); ("bar", 6)]
v}
We can use {{!merge}[merge]} to merge two hashtables with fine-grained control over
how we choose values when a key is present in the first ("left") hashtable, the
second ("right"), or both. Here, we'll cons the values when both hashtables have a
key:
{v
let h1 = Hashtbl.of_alist_exn (module Int) [(1, 5); (2, 3232)] in
let h2 = Hashtbl.of_alist_exn (module Int) [(1, 3)] in
Hashtbl.merge h1 h2 ~f:(fun ~key:_ -> function
| `Left x -> Some (`Left x)
| `Right x -> Some (`Right x)
| `Both (x, y) -> if x=y then None else Some (`Both (x,y))
) |> Hashtbl.to_alist;;
- : (int * [> `Both of int * int | `Left of int | `Right of int ]) list =
[(2, `Left 3232); (1, `Both (5, 3))]
v}
{1 Interface} *)includeS_without_submodules(** @inline *)moduletypeAccessors=AccessorsmoduletypeCreators=CreatorsmoduletypeMulti=MultimoduletypeS_poly=S_polymoduletypeS_without_submodules=S_without_submodulesmoduletypeFor_deriving=For_derivingmoduleKey=KeymoduleMerge_into_action=Merge_into_actiontypenonrec('key,'data,'z)create_options=('key,'data,'z)create_optionsmoduleCreators(Key:sigtype'atvalhashable:'atHashable.tend):sigtype('a,'b)t_=('aKey.t,'b)tvalt_of_sexp:(Sexp.t->'aKey.t)->(Sexp.t->'b)->Sexp.t->('a,'b)t_includeCreators_genericwithtype('a,'b)t:=('a,'b)t_withtype'akey:='aKey.twithtype('key,'data,'a)create_options:=('key,'data,'a)create_options_without_first_class_moduleendmodulePoly:S_polywithtype('a,'b)t=('a,'b)t(** [M] is meant to be used in combination with OCaml applicative functor types:
{[
type string_to_int_table = int Hashtbl.M(String).t
]}
which stands for:
{[
type string_to_int_table = (String.t, int) Hashtbl.t
]}
The point is that [int Hashtbl.M(String).t] supports deriving, whereas the second
syntax doesn't (because [t_of_sexp] doesn't know what comparison/hash function to
use). *)moduleM(K:T.T):sigtypenonrec'vt=(K.t,'v)tendincludeFor_derivingwithtype('a,'b)t:=('a,'b)t(**/**)(*_ See the Jane Street Style Guide for an explanation of [Private] submodules:
https://opensource.janestreet.com/standards/#private-submodules *)modulePrivate:sigmoduletypeCreators_generic=Creators_generictypenonrec('key,'data,'z)create_options_without_first_class_module=('key,'data,'z)create_options_without_first_class_modulevalhashable:('key,_)t->'keyHashable.tendend