123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851open!ImportmoduleSexp=Sexp0moduleDefinitions=struct[%%template[@@@kind_set.defineadditional=(bits64,float64)][@@@kind_set.defineall=(additional,value_or_null)](** @canonical Base.Hashtbl.Key *)moduleKey=struct[@@@mode.defaultm=(local,global),p=(nonportable,portable)]moduletypeS=sig@@ptypet:any[@@derivingsexp_of]valcompare:t@m->t@m->int[@@modem=(global,m)](** Two [t]s that [compare] equal must have equal hashes for the hashtable to behave
properly. *)valhash:t->intendtype('a:any)t=((moduleSwithtypet='a)[@modemp])endmoduleMerge_into_action=Dictionary_mutable.Merge_into_actionmoduletype%template[@modes=(uncontended,shared)]Accessors=sig(** {2 Accessors} *)type('a,'b)ttype'akey:valuemodswith'a(** Attempting to modify ([set], [remove], etc.) the hashtable during iteration
([fold], [iter], [iter_keys], [iteri]) will raise an exception. *)(** @inline *)includeDictionary_mutable.Accessors[@modes]withtype'keykey:='keykeyandtype('key,'data,_)t:=('key,'data)tandtype('fn,_,_,_)accessor:='fnvalsexp_of_key:('a,_)t->'akey->Sexp.tvalcapacity:_t->intvalgrowth_allowed:_t->bool[%%template:[@@@mode.defaultc=(uncontended,s)](** We redeclare [choose*] below to add implementation-specific notes on performance. *)(** 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@c->('akey*'b)option@cm[@@modem=global,c=c](** Like [choose], but returns a local pair option *)valchoose:('a,'b)t@c->('akeyModes.Global.t*'bModes.Global.t)option@cm[@@modem=local,c=c](** Like [choose]. Raises if [t] is empty. *)valchoose_exn:('a,'b)t@c->#('akey*'b)@c(** 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@c->('akey*'b)option@c(** Like [choose_randomly]. Raises if [t] is empty. *)valchoose_randomly_exn:?random_state:Random.State.t(** default: [Random.State.default] *)->('a,'b)t@c->#('akey*'b)@c(** [find_or_null] returns [This data] if the key is found, [Null] if not. *)valfind_or_null:('a:valuemodc)'b.('a,'b)t@c->'akey->'bor_null@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:valuemodc)'b('c:value_or_null)('d:value_or_null).('a,'b)t@c->'akey->a:'d->if_found:local_('b@c->'d->'c)->if_not_found:local_('akey->'d->'c)->'cvalfind_and_call2:('a:valuemodc)'b('c:value_or_null)('d:value_or_null)('e:value_or_null).('a,'b)t@c->'akey->a:'d->b:'e->if_found:local_('b@c->'d->'e->'c)->if_not_found:local_('akey->'d->'e->'c)->'cvalfindi_and_call1:('a:valuemodc)'b('c:value_or_null)('d:value_or_null).('a,'b)t@c->'akey->a:'d->if_found:local_(key:'akey->data:'b@c->'d->'c)->if_not_found:local_('akey->'d->'c)->'cvalfindi_and_call2:('a:valuemodc)'b('c:value_or_null)('d:value_or_null)('e:value_or_null).('a,'b)t@c->'akey->a:'d->b:'e->if_found:local_(key:'akey->data:'b@c->'d->'e->'c)->if_not_found:local_('akey->'d->'e->'c)->'c](** [change_or_null t ~f] is like [change t ~f], but the function [f] receives and
returns ['v or_null] instead of ['v option]. If [f] returns [Null], value at the
key is removed, and if [f] returns [This data], value at key is replaced with
[data]. *)valchange_or_null:('a,'b)t->'akey->f:local_('bor_null->'bor_null)->unit(** [update_or_null t ~f] is like [update t ~f] , but the function [f] receives
['v or_null] instead of ['v option]. *)valupdate_or_null:('a,'b)t->'akey->f:local_('bor_null->'b)->unit(** [update_or_null_and_return t ~f] is like [update_and_return t ~f], but the
function [f] receives ['v or_null] instead of ['v option]. *)valupdate_or_null_and_return:('a,'b)t->'akey->f:local_('bor_null->'b)->'b(** [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->boolendmoduletype%template[@modes=(uncontended,shared)]Multi=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. *)val%templatefind_multi:('a:valuemodc)'b.('a,'blist)t@c->'akey->'blist@c[@@modec=(uncontended,s)]endtype('key,'data,'z)create_options=?growth_allowed:bool(** defaults to [true] *)->?size:int(** initial size -- default 0 *)->'keyKey.t@immutable->'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_options(** @inline *)includeDictionary_mutable.Creatorswithtype'keykey:='keykeyandtype('key,'data,_)t:=('key,'data)tandtype('fn,'key,'data,_)creator:=('keykey,'data,'fn)create_optionsendmoduletype%template[@mode(p,c)=((nonportable,uncontended),(portable,contended))]Creators=sigtype('a,'b)t(** {2 Creators} *)[%%template:[@@@mode.default(p,c)=((nonportable,uncontended),(p,c))](** 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:('a:valuemodp)('b:valuemodp).?growth_allowed:bool(** defaults to [true] *)->?size:int(** initial size -- default 0 *)->('aKey.t[@modep])@immutable->('a,'b)t@p(** 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:('a:valuemodp)('b:valuemodp).?growth_allowed:bool(** defaults to [true] *)->?size:int(** initial size -- default 0 *)->('aKey.t[@modep])@immutable->('a*'b)list->[`Okof('a,'b)t|`Duplicate_keyof'a]@p(** 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:('a:valuemodp)('b:valuemodp).?growth_allowed:bool(** defaults to [true] *)->?size:int(** initial size -- default 0 *)->('aKey.t[@modep])@immutable->('a*'b)list->[`Okof('a,'b)t|`Duplicate_keysof'alist]@pvalof_alist_or_error:('a:valuemodcp)('b:valuemodp).?growth_allowed:bool(** defaults to [true] *)->?size:int(** initial size -- default 0 *)->('aKey.t[@modep])@immutable->('a*'b)list->('a,'b)tOr_error.t@pvalof_alist_exn:('a:valuemodcp)('b:valuemodp).?growth_allowed:bool(** defaults to [true] *)->?size:int(** initial size -- default 0 *)->('aKey.t[@modep])@immutable->('a*'b)list->('a,'b)t@p(** 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:('a:valuemodp)('b:valuemodp).?growth_allowed:bool(** defaults to [true] *)->?size:int(** initial size -- default 0 *)->('aKey.t[@modep])@immutable->('a*'b)list->('a,'blist)t@p(** 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:(local_ (fun x -> x))
~get_data:(local_ (fun x -> x + 1))
[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:('a:valuemodp)('b:valuemodp)'r.?growth_allowed:bool(** defaults to [true] *)->?size:int(** initial size -- default 0 *)->('aKey.t[@modep])@immutable->get_key:local_('r->'a)->get_data:local_('r->'b)->'rlist->[`Okof('a,'b)t|`Duplicate_keysof'alist]@p(** {[
create_with_key ~get_key [x1;...;xn]
= of_alist [get_key x1, x1; ...; get_key xn, xn]
]} *)valcreate_with_key:('a:valuemodp)('r:valuemodp).?growth_allowed:bool(** defaults to [true] *)->?size:int(** initial size -- default 0 *)->('aKey.t[@modep])@immutable->get_key:local_('r->'a)->'rlist->[`Okof('a,'r)t|`Duplicate_keysof'alist]@pvalcreate_with_key_or_error:('a:valuemodp)('r:valuemodp).?growth_allowed:bool(** defaults to [true] *)->?size:int(** initial size -- default 0 *)->('aKey.t[@modep])@immutable->get_key:local_('r->'a)->'rlist->('a,'r)tOr_error.t@pvalcreate_with_key_exn:('a:valuemodp)('r:valuemodp).?growth_allowed:bool(** defaults to [true] *)->?size:int(** initial size -- default 0 *)->('aKey.t[@modep])@immutable->get_key:local_('r->'a)->'rlist->('a,'r)t@p(** 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:(local_ (fun x -> x / 2))
~get_data:(local_ (fun x -> x))
~combine:(local_ (fun x y -> x * y))
[ 1; 2; 3; 4]
|> Hashtbl.to_alist;;
- : (int * int) list = [(2, 4); (1, 6); (0, 1)]
v} *)valgroup:('a:valuemodp)('b:valuemodp)'r.?growth_allowed:bool(** defaults to [true] *)->?size:int(** initial size -- default 0 *)->('aKey.t[@modep])@immutable->get_key:local_('r->'a)->get_data:local_('r->'b)->combine:local_('b->'b->'b)->'rlist->('a,'b)t@p]endmoduletype%template[@mode(p,s)=((nonportable,uncontended),(portable,shared))]S_without_submodules=sigvalhash:'a->intvalhash_param:int->int->'a->inttype(!'a,!'b)t:valuemodnon_float(** 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.tincludeCreators[@modep]withtype('a,'b)t:=('a,'b)t(** @inline *)includeAccessors[@modes]withtype('a,'b)t:=('a,'b)twithtype'akey='a(** @inline *)includeMulti[@modes]withtype('a,'b)t:=('a,'b)twithtype'akey:='akey(** @inline *)valhashable_s:('key,_)t->'keyKey.tincludeInvariant.S2withtype('a,'b)t:=('a,'b)tendmoduletype%template[@modes=(uncontended,shared)]S_poly=sigtype('a,'b)t:valuemodnon_float[@@derivingsexp,sexp_grammar]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_moduleincludeAccessors[@modes]withtype('a,'b)t:=('a,'b)twithtype'akey:='akeyincludeMulti[@modes]withtype('a,'b)t:=('a,'b)twithtype'akey:='akeyendmoduletypeFor_deriving=sigtype('k,'v)tmoduletypeSexp_of_m=sigtypet[@@derivingsexp_of]endmoduletypeM_of_sexp=sigtypet[@@derivingof_sexp]includeKey.Swithtypet:=tendmoduletypeM_sexp_grammar=sigtypet[@@derivingsexp_grammar]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.t@@portablevalequal_m__t:(moduleEqual_m)->('v->'v->bool)->('k,'v)t->('k,'v)t->boolendmoduletypeNon_value=sig@@portableincludesigtype(!'a:k,!'b:v)t:valuemodnon_float[@@derivingsexp_of][@@kindk=all,v=all](*_ Unmangled [t] is shadowed below, so define [t] with explicit mangling. *)type(!'a:k,!'b:v)t:=(('a,'b)t[@kindkv])[@@kind.explicitk=all,v=all][@@@kindk=all,v=all]type(!'a:k,!'b:v)t:=(('a,'b)t[@kind.explicitkv])type('a:k)key:=('aKey.t[@modep])[@@modep=(nonportable,portable)][@@@kind.defaultkv][@@@kindk_create=kmodnon_nullseparable]valcreate:('a:k_createmodp)('b:vmodp).?growth_allowed:bool(** defaults to [true] *)->?size:int(** initial size -- default 0 *)->('akey[@modep])@immutablep->('a,'b)t@p[@@modep=(nonportable,portable)]valsingleton:('k:k_createmodp)('v:vmodp).?growth_allowed:bool->?size:int->('kkey[@modep])@immutablep->'k->'v->('k,'v)t@p[@@modep=(nonportable,portable)]vallength:('k:k)('v:v).('k,'v)t@c->int[@@modec=(uncontended,shared)][@@zero_alloc]valcapacity:('k:k)('v:v).('k,'v)t@c->int[@@modec=(uncontended,shared)]valgrowth_allowed:('k:k)('v:v).('k,'v)t@c->bool[@@modec=(uncontended,contended)]valis_empty:('k:k)('v:v).('k,'v)t@c->bool[@@modec=(uncontended,shared)]valadd_exn:('k:k)('v:v).('k,'v)t->key:'k->data:'v->unitvaladd:('k:k)('v:v).('k,'v)t->key:'k->data:'v->[`Ok|`Duplicate]valfind:('k:kmodc)('v:v).('k,'v)t@c->'k->('vOption.t[@kindv])@c[@@modec=(uncontended,shared)]valfind_exn:('k:kmodc)('v:v).('k,'v)t@c->'k->'v@c[@@modec=(uncontended,shared)]valfind_and_remove:('k:k)('v:v).('k,'v)t->'k->('vOption.t[@kindv])valremove:('k:k)('v:v).('k,'v)t->'k->unitvalmem:('k:kmodc)('v:v).('k,'v)t@c->'k->bool[@@modec=(uncontended,shared)]valset:('k:k)('v:v).('k,'v)t->key:'k->data:'v->unitvalclear:('k:k)('v:v).('k,'v)t->unitvalfind_and_call:('k:kmodc)('v:v)('a:r).('k,'v)t@c->'k->if_found:local_('v@c->'a)->if_not_found:local_('k@c->'a)->'a[@@kindk=k,v=v,r=v][@@modec=(uncontended,shared)]valfind_and_call1:('k:kmodc)('v:v)('a:a)('r:r).('k,'v)t@c->'k->a:'a->if_found:local_('v@c->'a->'r)->if_not_found:local_('k->'a->'r)->'r[@@kindk=k,v=v,a=value_or_null,r=v][@@modec=(uncontended,shared)]valupdate:('k:k)('v:v).('k,'v)t->'k->f:local_(('vOption.t[@kindv])->'v)->unitvalupdate_and_return:('k:k)('v:v).('k,'v)t->'k->f:local_(('vOption.t[@kindv])->'v)->'vvalfilter_inplace:('k:k)('v:v).('k,'v)t->f:('v->bool)@local->unitvalfilteri_inplace:('k:k)('v:v).('k,'v)t->f:(key:'k->data:'v->bool)@local->unitvalfilter_keys_inplace:('k:k)('v:v).('k,'v)t->f:('k->bool)@local->unitvalmapi_inplace:('k:k)('v:v).('k,'v)t->f:(key:'k->data:'v->'v)@local->unitvalmap_inplace:('k:k)('v:v).('k,'v)t->f:('v->'v)@local->unitvalfilter_map_inplace:('k:k)('v:v).('k,'v)t->f:('v->('vOption.t[@kindv]))@local->unitvalfilter_mapi_inplace:('k:k)('v:v).('k,'v)t->f:(key:'k->data:'v->('vOption.t[@kindv]))@local->unitvalchange:('k,'v)t->'k->f:local_(('vOption.t[@kindv])->('vOption.t[@kindv]))->unitvalfold:('k:k)('v:v)('acc:value_or_null).('k,'v)t@c->init:'acc->f:local_(key:'k@c->data:'v@c->'acc->'acc)->'acc[@@synchro__@c=(unsync_uncontended,sync_shared)]valiter:('k:k)('v:v).('k,'v)t@cl->f:local_('v@c->unit)->unit[@@model=(global,local)][@@synchro__@c=(unsync_uncontended,sync_shared)]valiter_keys:('k:k)('v:v).('k,'v)t@cl->f:local_('k@c->unit)->unit[@@model=(global,local)][@@synchro__@c=(unsync_uncontended,sync_shared)]valiteri:('k:k)('v:v).('k,'v)t@cl->f:local_(key:'k@c->data:'v@c->unit)->unit[@@model=(global,local)][@@synchro__@c=(unsync_uncontended,sync_shared)]valfind_or_add:('k:k)('v:v).('k,'v)t->'k->default:local_(unit->'v)->'vvalfindi_or_add:('k:k)('v:v).('k,'v)t->'k->default:local_('k->'v)->'vvalkeys:('k:k)('v:v).('k,'v)t@c->('kList.t[@kindk])@c[@@synchro__@c=(unsync_uncontended,sync_shared)]valdata:('k:k)('v:v).('k,'v)t@c->('vList.t[@kindv])@c[@@synchro__@c=(unsync_uncontended,sync_shared)]valchoose_exn:('k:k)('v:v).('k,'v)t@c->#('k*'v)@c[@@modec=(uncontended,shared)]valinvariant:('k:k)('v:v).('k->unit)->('v->unit)->('k,'v)t->unitendincludesig[@@@kind.defaultk=all,v=all]valadd_multi:('k:k)('v:v).(('k,('vList.t[@kindv]))t[@kindkvalue_or_null])->key:'k->data:'v->unitvalremove_multi:('k:k)('v:v).(('k,('vList.t[@kindv]))t[@kindkvalue_or_null])->'k->unitvalfind_multi:('k:kmodc)('v:v).(('k,('vList.t[@kindv]))t[@kindkvalue_or_null])@c->'k->('vList.t[@kindv])@c[@@modec=(uncontended,shared)]valmap:('k:k)('v:v)('w:v').(('k,'v)t[@kindkv])->f:local_('v->'w)->(('k,'w)t[@kindkv'])[@@kindk=k,v=v,v'=all]endincludesigvalto_alist:('k:value_or_null)('v:value_or_null).('k,'v)t->('k*'v)listendendmoduletypeHashtbl_equality=sigtype('a,'b)tvalequal:('b@m->'b@m->bool)->('a,'b)t@m->('a,'b)t@m->bool[@@modem=local]valsimilar:('b@m->'c@m->bool)->('a,'b)t@m->('a,'c)t@m->bool[@@modem=local]end]endmoduletypeHashtbl=sig@@portableincludemoduletypeofstructincludeDefinitionsend(** 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} *)type(!'a:value_or_null,!'b:value_or_null)t:valuemodnon_floatinclude%templateS_without_submodules[@modeportable]withtype('k,'v)t:=('k,'v)t(** @inline *)includeHashtbl_equalitywithtype('k,'v)t:=('k,'v)t(** @inline *)includeNon_valuewithtype('k:value_or_null,'v:value_or_null)t:=('k,'v)t(** @inline *)module%template.portableCreators(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_moduleendmodule%templatePoly:S_poly[@modeshared]withtype('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