123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452(* This file is free software, part of containers. See file "license" for more details. *)(** {1 Extension to the standard Hashtbl} *)type'aiter=('a->unit)->unittype'asequence=('a->unit)->unittype'aeq='a->'a->booltype'ahash='a->inttype'aprinter=Format.formatter->'a->unit(** {2 Polymorphic tables} *)modulePoly=structletgettblx=trySome(Hashtbl.findtblx)withNot_found->Noneletget_ortblx~default=tryHashtbl.findtblxwithNot_found->default(*$=
"c" (let tbl = of_list [1,"a"; 2,"b"] in get_or tbl 3 ~default:"c")
"b" (let tbl = of_list [1,"a"; 2,"b"] in get_or tbl 2 ~default:"c")
*)letkeystblk=Hashtbl.iter(funkey_->kkey)tblletvaluestblk=Hashtbl.iter(fun_v->kv)tblletkeys_listtbl=Hashtbl.fold(funk_a->k::a)tbl[]letvalues_listtbl=Hashtbl.fold(fun_va->v::a)tbl[]letadd_listtblkv=letl=tryHashtbl.findtblkwithNot_found->[]inHashtbl.replacetblk(v::l)letincr?(by=1)tblx=letn=get_ortblx~default:0inifn+by<=0thenHashtbl.removetblxelseHashtbl.replacetblx(n+by)letdecr?(by=1)tblx=tryletn=Hashtbl.findtblxinifn-by<=0thenHashtbl.removetblxelseHashtbl.replacetblx(n-by)withNot_found->()letmap_listfh=Hashtbl.fold(funxyacc->fxy::acc)h[](*$T
of_list [1,"a"; 2,"b"] |> map_list (fun x y -> string_of_int x ^ y) \
|> List.sort Stdlib.compare = ["1a"; "2b"]
*)letto_itertblk=Hashtbl.iter(funkeyv->k(key,v))tblletadd_itertbli=i(fun(k,v)->Hashtbl.addtblkv)letadd_std_seqtblseq=Seq.iter(fun(k,v)->Hashtbl.addtblkv)seqletof_iteri=lettbl=Hashtbl.create32inadd_itertbli;tblletof_std_seqi=lettbl=Hashtbl.create32inadd_std_seqtbli;tblletadd_iter_counttbli=i(funk->incrtblk)letadd_std_seq_counttblseq=Seq.iter(funk->incrtblk)seqletof_iter_counti=lettbl=Hashtbl.create32inadd_iter_counttbli;tblletof_std_seq_counti=lettbl=Hashtbl.create32inadd_std_seq_counttbli;tblletto_seq=to_iterletadd_seq=add_iterletof_seq=of_iterletadd_seq_count=add_iter_countletof_seq_count=of_iter_countletto_listtbl=Hashtbl.fold(funkvl->(k,v)::l)tbl[]letof_listl=lettbl=Hashtbl.create32inList.iter(fun(k,v)->Hashtbl.addtblkv)l;tblletupdatetbl~f~k=letv=gettblkinmatchv,fkvwith|None,None->()|None,Somev'->Hashtbl.addtblkv'|Some_,Somev'->Hashtbl.replacetblkv'|Some_,None->Hashtbl.removetblk(*$R
let tbl = Hashtbl.create 32 in
update tbl ~f:(fun _ _ -> Some "1") ~k:1;
assert_equal (Some "1") (get tbl 1);
update tbl ~f:(fun _ v->match v with Some _ -> assert false | None -> Some "2") ~k:2;
assert_equal (Some "2") (get tbl 2);
assert_equal 2 (Hashtbl.length tbl);
update tbl ~f:(fun _ _ -> None) ~k:1;
assert_equal None (get tbl 1);
*)letget_or_addtbl~f~k=tryHashtbl.findtblkwithNot_found->letv=fkinHashtbl.addtblkv;v(*$R
let tbl = Hashtbl.create 32 in
let v1 = get_or_add tbl ~f:(fun _ -> "1") ~k:1 in
assert_equal "1" v1;
assert_equal (Some "1") (get tbl 1);
let v2 = get_or_add tbl ~f:(fun _ ->"2") ~k:2 in
assert_equal "2" v2;
assert_equal (Some "2") (get tbl 2);
assert_equal "2" (get_or_add tbl ~f:(fun _ -> assert false) ~k:2);
assert_equal 2 (Hashtbl.length tbl);
()
*)letpppp_kpp_vfmtm=Format.fprintffmt"@[<hov2>tbl {@,";letfirst=reftrueinHashtbl.iter(funkv->if!firstthenfirst:=falseelseFormat.fprintffmt",@ ";pp_kfmtk;Format.pp_print_stringfmt" -> ";pp_vfmtv;)m;Format.fprintffmt"@,}@]"endincludePoly(** {2 Functor} *)moduletypeS=sigincludeHashtbl.Svalget:'at->key->'aoption(** Safe version of {!Hashtbl.find}. *)valget_or:'at->key->default:'a->'a(** [get_or tbl k ~default] returns the value associated to [k] if present,
and returns [default] otherwise (if [k] doesn't belong in [tbl]).
@since 0.16 *)valadd_list:'alistt->key->'a->unit(** [add_list tbl x y] adds [y] to the list [x] is bound to. If [x] is
not bound, it becomes bound to [y].
@since 0.16 *)valincr:?by:int->intt->key->unit(** [incr ?by tbl x] increments or initializes the counter associated with [x].
If [get tbl x = None], then after update, [get tbl x = Some 1];
otherwise, if [get tbl x = Some n], now [get tbl x = Some (n+1)].
@param by if specified, the int value is incremented by [by] rather than 1.
@since 0.16 *)valdecr:?by:int->intt->key->unit(** Like {!incr} but subtract 1 (or the value of [by]).
If the value reaches 0, the key is removed from the table.
This does nothing if the key is not already present in the table.
@since 0.16 *)valkeys:'at->keyiter(** Iterate on keys (similar order as {!Hashtbl.iter}). *)valvalues:'at->'aiter(** Iterate on values in the table. *)valkeys_list:_t->keylist(** [keys_list t] is the list of keys in [t].
If the key is in the Hashtable multiple times, all occurrences will be returned.
@since 0.8 *)valvalues_list:'at->'alist(** [values_list t] is the list of values in [t].
@since 0.8 *)valmap_list:(key->'a->'b)->'at->'blist(** Map on a hashtable's items, collect into a list. *)valto_iter:'at->(key*'a)iter(** Iterate on bindings in the table.
@since 2.8 *)valto_seq:'at->(key*'a)sequence(** Iterate on values in the table.
@deprecated use {!to_iter} instead *)[@@ocaml.deprecated"use to_iter"]valadd_iter:'at->(key*'a)iter->unit(** Add the corresponding pairs to the table, using {!Hashtbl.add}.
@since 2.8 *)valadd_std_seq:'at->(key*'a)Seq.t->unit(** Add the corresponding pairs to the table, using {!Hashtbl.add}.
@since 2.8 *)valadd_seq:'at->(key*'a)sequence->unit(** Add the corresponding pairs to the table, using {!Hashtbl.add}.
@since 0.16
@deprecated use {!add_iter} or {!add_std_seq} *)[@@ocaml.deprecated"use add_iter or add_std_seq"]valof_iter:(key*'a)iter->'at(** From the given bindings, added in order.
@since 2.8 *)valof_std_seq:(key*'a)Seq.t->'at(** From the given bindings, added in order.
@since 2.8 *)valof_seq:(key*'a)sequence->'at(** From the given bindings, added in order.
@deprecated use {!of_iter} or {!of_std_seq} *)[@@ocaml.deprecated"use of_iter or of_std_seq"]valadd_iter_count:intt->keyiter->unit(** [add_iter_count tbl i] increments the count of each element of [i]
by calling {!incr}. This is useful for counting how many times each
element of [i] occurs.
@since 2.8 *)valadd_std_seq_count:intt->keySeq.t->unit(** [add_seq_count tbl seq] increments the count of each element of [seq]
by calling {!incr}. This is useful for counting how many times each
element of [seq] occurs.
@since 2.8 *)valadd_seq_count:intt->keysequence->unit(** [add_seq_count tbl seq] increments the count of each element of [seq]
by calling {!incr}. This is useful for counting how many times each
element of [seq] occurs.
@since 0.16
@deprecated use {!add_iter_count} or {!add_std_seq_count} *)[@@ocaml.deprecated"use add_iter_count or add_std_seq_count"]valof_iter_count:keyiter->intt(** Like {!add_seq_count}, but allocates a new table and returns it.
@since 2.8 *)valof_std_seq_count:keySeq.t->intt(** Like {!add_seq_count}, but allocates a new table and returns it.
@since 2.8 *)valof_seq_count:keysequence->intt(** Like {!add_seq_count}, but allocates a new table and returns it.
@since 0.16
@deprecated use {!of_iter_count} or {!of_std_seq_count} *)[@@ocaml.deprecated"use add_iter_count or add_std_seq_count"]valto_list:'at->(key*'a)list(** List of bindings (order unspecified). *)valof_list:(key*'a)list->'at(** Build a table from the given list of bindings [k_i -> v_i],
added in order using {!add}. If a key occurs several times,
it will be added several times, and the visible binding
will be the last one. *)valupdate:'at->f:(key->'aoption->'aoption)->k:key->unit(** [update tbl ~f ~k] updates key [k] by calling [f k (Some v)] if
[k] was mapped to [v], or [f k None] otherwise; if the call
returns [None] then [k] is removed/stays removed, if the call
returns [Some v'] then the binding [k -> v'] is inserted
using {!Hashtbl.replace}.
@since 0.14 *)valget_or_add:'at->f:(key->'a)->k:key->'a(** [get_or_add tbl ~k ~f] finds and returns the binding of [k]
in [tbl], if it exists. If it does not exist, then [f k]
is called to obtain a new binding [v]; [k -> v] is added
to [tbl] and [v] is returned.
@since 1.0 *)valpp:keyprinter->'aprinter->'atprinter(** Printer for tables.
Renamed from [print] since 2.0.
@since 0.13 *)end(*$inject
module T = Make(CCInt)
*)moduleMake(X:Hashtbl.HashedType):Swithtypekey=X.tandtype'at='aHashtbl.Make(X).t=structincludeHashtbl.Make(X)letgettblx=trySome(findtblx)withNot_found->Noneletget_ortblx~default=tryfindtblxwithNot_found->default(*$=
"c" (let tbl = T.of_list [1,"a"; 2,"b"] in T.get_or tbl 3 ~default:"c")
"b" (let tbl = T.of_list [1,"a"; 2,"b"] in T.get_or tbl 2 ~default:"c")
*)letincr?(by=1)tblx=letn=get_ortblx~default:0inifn+by<=0thenremovetblxelsereplacetblx(n+by)(*$R
let tbl = T.create 32 in
T.incr tbl 1 ;
T.incr tbl 2;
T.incr tbl 1;
assert_equal 2 (T.find tbl 1);
assert_equal 1 (T.find tbl 2);
assert_equal 2 (T.length tbl);
T.decr tbl 2;
assert_equal 0 (T.get_or tbl 2 ~default:0);
assert_equal 1 (T.length tbl);
assert_bool "2 removed" (not (T.mem tbl 2));
*)letadd_listtblkv=letl=tryfindtblkwithNot_found->[]inreplacetblk(v::l)letdecr?(by=1)tblx=tryletn=findtblxinifn-by<=0thenremovetblxelsereplacetblx(n-by)withNot_found->()letkeystblk=iter(funkey_->kkey)tblletvaluestblk=iter(fun_v->kv)tblletkeys_listtbl=fold(funk_a->k::a)tbl[]letvalues_listtbl=fold(fun_va->v::a)tbl[]letmap_listfh=fold(funxyacc->fxy::acc)h[]letupdatetbl~f~k=letv=gettblkinmatchv,fkvwith|None,None->()|None,Somev'->addtblkv'|Some_,Somev'->replacetblkv'|Some_,None->removetblkletget_or_addtbl~f~k=tryfindtblkwithNot_found->letv=fkinaddtblkv;vletto_itertblk=iter(funkeyv->k(key,v))tblletadd_itertbli=i(fun(k,v)->addtblkv)letadd_std_seqtblseq=Seq.iter(fun(k,v)->addtblkv)seqletof_iteri=lettbl=create32inadd_itertbli;tblletof_std_seqi=lettbl=create32inadd_std_seqtbli;tblletadd_iter_counttbli=i(funk->incrtblk)letadd_std_seq_counttblseq=Seq.iter(funk->incrtblk)seqletof_iter_countseq=lettbl=create32inadd_iter_counttblseq;tblletof_std_seq_counti=lettbl=create32inadd_std_seq_counttbli;tblletto_seq=to_iterletadd_seq=add_iterletof_seq=of_iterletadd_seq_count=add_iter_countletof_seq_count=of_iter_countletto_listtbl=fold(funkvl->(k,v)::l)tbl[]letof_listl=lettbl=create32inList.iter(fun(k,v)->addtblkv)l;tblletpppp_kpp_vfmtm=Format.fprintffmt"@[<hov2>tbl {@,";letfirst=reftrueiniter(funkv->if!firstthenfirst:=falseelseFormat.pp_print_stringfmt", ";pp_kfmtk;Format.pp_print_stringfmt" -> ";pp_vfmtv;Format.pp_print_cutfmt())m;Format.fprintffmt"}@]"end