123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880open!ImportincludeHashtbl_intfletwith_return=With_return.with_returnlethash_param=Hashable.hash_paramlethash=Hashable.hashtype('k,'v)t={mutabletable:('k,'v)Avltree.tarray;mutablelength:int(* [recently_added] is the reference passed to [Avltree.add]. We put it in the hash
table to avoid allocating it at every [set]. *);recently_added:boolref;growth_allowed:bool;hashable:'kHashable.t;mutablemutation_allowed:bool(* Set during all iteration operations *)}type'akey='aletsexp_of_keyt=t.hashable.Hashable.sexp_of_tletcompare_keyt=t.hashable.Hashable.compareletensure_mutation_allowedt=ifnott.mutation_allowedthenfailwith"Hashtbl: mutation not allowed during iteration";;letwithout_mutatingtf=ift.mutation_allowedthenbegint.mutation_allowed<-false;matchf()with|x->t.mutation_allowed<-true;x|exceptionexn->t.mutation_allowed<-true;raiseexnendelsef();;(** Internally use a maximum size that is a power of 2. Reverses the above to find the
floor power of 2 below the system max array length *)letmax_table_length=Int.floor_pow2Array.max_length;;letcreate?(growth_allowed=true)?(size=128)~hashable()=letsize=Int.min(Int.max1size)max_table_lengthinletsize=Int.ceil_pow2sizein{table=Array.create~len:sizeAvltree.empty;length=0;growth_allowed=growth_allowed;recently_added=reffalse;hashable;mutation_allowed=true};;(** Supplemental hash. This may not be necessary, it is intended as a defense against poor
hash functions, for which the power of 2 sized table will be especially sensitive.
With some testing we may choose to add it, but this table is designed to be robust to
collisions, and in most of my testing this degrades performance. *)let_supplemental_hashh=leth=hlxor((hlsr20)lxor(hlsr12))inhlxor(hlsr7)lxor(hlsr4);;letslottkey=lethash=t.hashable.Hashable.hashkeyin(* this is always non-negative because we do [land] with non-negative number *)hashland((Array.lengtht.table)-1);;letadd_workert~replace~key~data=leti=slottkeyinletroot=t.table.(i)inletadded=t.recently_addedinadded:=false;letnew_root=(* The avl tree might replace the value [replace=true] or do nothing [replace=false]
to the entry, in that case the table did not get bigger, so we should not
increment length, we pass in the bool ref t.added so that it can tell us whether
it added or replaced. We do it this way to avoid extra allocation. Since the bool
is an immediate it does not go through the write barrier. *)Avltree.add~replaceroot~compare:(compare_keyt)~added~key~datainif!addedthent.length<-t.length+1;(* This little optimization saves a caml_modify when the tree
hasn't been rebalanced. *)ifnot(phys_equalnew_rootroot)thent.table.(i)<-new_root;;letmaybe_resize_tablet=letlen=Array.lengtht.tableinletshould_grow=t.length>leninifshould_grow&&t.growth_allowedthenbeginletnew_array_length=Int.min(len*2)max_table_lengthinifnew_array_length>lenthenbeginletnew_table=Array.create~len:new_array_lengthAvltree.emptyinletold_table=t.tableint.table<-new_table;t.length<-0;letf~key~data=add_worker~replace:truet~key~datainfori=0toArray.lengthold_table-1doAvltree.iterold_table.(i)~fdoneendend;;letsett~key~data=ensure_mutation_allowedt;add_worker~replace:truet~key~data;maybe_resize_tablet;;letreplace=setletaddt~key~data=ensure_mutation_allowedt;add_worker~replace:falset~key~data;if!(t.recently_added)thenbeginmaybe_resize_tablet;`Okendelse`Duplicate;;letadd_exnt~key~data=matchaddt~key~datawith|`Ok->()|`Duplicate->letsexp_of_key=sexp_of_keytinleterror=Error.create"Hashtbl.add_exn got key already present"keysexp_of_keyinError.raiseerror;;letcleart=ensure_mutation_allowedt;fori=0toArray.lengtht.table-1dot.table.(i)<-Avltree.empty;done;t.length<-0;;letfind_and_calltkey~if_found~if_not_found=(* with a good hash function these first two cases will be the overwhelming majority,
and Avltree.find is recursive, so it can't be inlined, so doing this avoids a
function call in most cases. *)matcht.table.(slottkey)with|Avltree.Empty->if_not_foundkey|Avltree.Leaf{key=k;value=v}->ifcompare_keytkkey=0thenif_foundvelseif_not_foundkey|tree->Avltree.find_and_calltree~compare:(compare_keyt)key~if_found~if_not_found;;letfindi_and_calltkey~if_found~if_not_found=(* with a good hash function these first two cases will be the overwhelming majority,
and Avltree.find is recursive, so it can't be inlined, so doing this avoids a
function call in most cases. *)matcht.table.(slottkey)with|Avltree.Empty->if_not_foundkey|Avltree.Leaf{key=k;value=v}->ifcompare_keytkkey=0thenif_found~key:k~data:velseif_not_foundkey|tree->Avltree.findi_and_calltree~compare:(compare_keyt)key~if_found~if_not_found;;letfind=letif_foundv=Somevinletif_not_found_=Noneinfuntkey->find_and_calltkey~if_found~if_not_found;;letmemtkey=matcht.table.(slottkey)with|Avltree.Empty->false|Avltree.Leaf{key=k;value=_}->compare_keytkkey=0|tree->Avltree.memtree~compare:(compare_keyt)key;;letremovetkey=ensure_mutation_allowedt;leti=slottkeyinletroot=t.table.(i)inletadded_or_removed=t.recently_addedinadded_or_removed:=false;letnew_root=Avltree.removeroot~removed:added_or_removed~compare:(compare_keyt)keyinifnot(phys_equalrootnew_root)thent.table.(i)<-new_root;if!added_or_removedthent.length<-t.length-1;;letlengtht=t.lengthletis_emptyt=lengtht=0letfoldt~init~f=iflengtht=0theninitelsebeginletn=Array.lengtht.tableinletacc=refinitinletm=t.mutation_allowedinmatcht.mutation_allowed<-false;fori=0ton-1domatchArray.unsafe_gett.tableiwith|Avltree.Empty->()|Avltree.Leaf{key;value=data}->acc:=f~key~data!acc|bucket->acc:=Avltree.foldbucket~init:!acc~fdonewith|()->t.mutation_allowed<-m;!acc|exceptionexn->t.mutation_allowed<-m;raiseexnend;;letiterit~f=ift.length=0then()elsebeginletn=Array.lengtht.tableinletm=t.mutation_allowedinmatcht.mutation_allowed<-false;fori=0ton-1domatchArray.unsafe_gett.tableiwith|Avltree.Empty->()|Avltree.Leaf{key;value=data}->f~key~data|bucket->Avltree.iterbucket~fdonewith|()->t.mutation_allowed<-m|exceptionexn->t.mutation_allowed<-m;raiseexnend;;letitert~f=iterit~f:(fun~key:_~data->fdata)letiter_keyst~f=iterit~f:(fun~key~data:_->fkey)letinvariantinvariant_keyinvariant_datat=fori=0toArray.lengtht.table-1doAvltree.invariantt.table.(i)~compare:(compare_keyt)done;letreal_len=foldt~init:0~f:(fun~key~datai->invariant_keykey;invariant_datadata;i+1)inassert(real_len=t.length);;;letfind_exn=letif_foundv=vinletif_not_found_=raiseCaml.Not_foundinfuntkey->find_and_calltkey~if_found~if_not_found;;letexistsit~f=with_return(funr->iterit~f:(fun~key~data->iff~key~datathenr.returntrue);false);;letexistst~f=existsit~f:(fun~key:_~data->fdata);;letfor_allit~f=not(existsit~f:(fun~key~data->not(f~key~data)))letfor_allt~f=not(existsit~f:(fun~key:_~data->not(fdata)))letcountit~f=foldt~init:0~f:(fun~key~dataacc->iff~key~datathenacc+1elseacc)letcountt~f=foldt~init:0~f:(fun~key:_~dataacc->iffdatathenacc+1elseacc)letmapit~f=letnew_t=create~growth_allowed:t.growth_allowed~hashable:t.hashable~size:t.length()initerit~f:(fun~key~data->replacenew_t~key~data:(f~key~data));new_tletmapt~f=mapit~f:(fun~key:_~data->fdata)letcopyt=mapt~f:Fn.idletfilter_mapit~f=letnew_t=create~growth_allowed:t.growth_allowed~hashable:t.hashable~size:t.length()initerit~f:(fun~key~data->matchf~key~datawith|Somenew_data->replacenew_t~key~data:new_data|None->());new_tletfilter_mapt~f=filter_mapit~f:(fun~key:_~data->fdata)letfilterit~f=filter_mapit~f:(fun~key~data->iff~key~datathenSomedataelseNone);;letfiltert~f=filterit~f:(fun~key:_~data->fdata)letfilter_keyst~f=filterit~f:(fun~key~data:_->fkey)letpartition_mapit~f=lett0=create~growth_allowed:t.growth_allowed~hashable:t.hashable~size:t.length()inlett1=create~growth_allowed:t.growth_allowed~hashable:t.hashable~size:t.length()initerit~f:(fun~key~data->matchf~key~datawith|`Fstnew_data->replacet0~key~data:new_data|`Sndnew_data->replacet1~key~data:new_data);(t0,t1);;letpartition_mapt~f=partition_mapit~f:(fun~key:_~data->fdata)letpartitioni_tft~f=partition_mapit~f:(fun~key~data->iff~key~datathen`Fstdataelse`Snddata);;letpartition_tft~f=partitioni_tft~f:(fun~key:_~data->fdata)letfind_or_addtid~default=matchfindtidwith|Somex->x|None->letdefault=default()inreplacet~key:id~data:default;defaultletfindi_or_addtid~default=matchfindtidwith|Somex->x|None->letdefault=defaultidinreplacet~key:id~data:default;default(* Some hashtbl implementations may be able to perform this more efficiently than two
separate lookups *)letfind_and_removetid=letresult=findtidinifOption.is_someresultthenremovetid;resultletchangetid~f=matchf(findtid)with|None->removetid|Somedata->replacet~key:id~data;;letupdatetid~f=sett~key:id~data:(f(findtid));;letincr_by~remove_if_zerotkeyby=ifremove_if_zerothenchangetkey~f:(funopt->matchby+Option.valueopt~default:0with|0->None|n->Somen)elseupdatetkey~f:(function|None->by|Somei->by+i);;letincr?(by=1)?(remove_if_zero=false)tkey=incr_by~remove_if_zerotkeybyletdecr?(by=1)?(remove_if_zero=false)tkey=incr_by~remove_if_zerotkey(-by);;letadd_multit~key~data=updatetkey~f:(function|None->[data]|Somel->data::l);;letremove_multitkey=matchfindtkeywith|None->()|Some[]|Some[_]->removetkey|Some(_::tl)->replacet~key~data:tlletfind_multitkey=matchfindtkeywith|None->[]|Somel->lletcreate_mapped?growth_allowed?size~hashable~get_key~get_datarows=letsize=matchsizewithSomes->s|None->List.lengthrowsinletres=create?growth_allowed~hashable~size()inletdupes=ref[]inList.iterrows~f:(funr->letkey=get_keyrinletdata=get_datarinifmemreskeythendupes:=key::!dupeselsereplaceres~key~data);match!dupeswith|[]->`Okres|keys->`Duplicate_keys(List.dedup_and_sort~compare:hashable.Hashable.comparekeys);;(*
{[
let create_mapped_exn ?growth_allowed ?size ~hashable ~get_key ~get_data rows =
let size = match size with Some s -> s | None -> List.length rows in
let res = create ?growth_allowed ~size ~hashable () in
List.iter rows ~f:(fun r ->
let key = get_key r in
let data = get_data r in
if mem res key then
let sexp_of_key = hashable.Hashable.sexp_of_t in
failwiths "Hashtbl.create_mapped_exn: duplicate key" key <:sexp_of< key >>
else
replace res ~key ~data);
res
;;
]} *)letcreate_mapped_multi?growth_allowed?size~hashable~get_key~get_datarows=letsize=matchsizewithSomes->s|None->List.lengthrowsinletres=create?growth_allowed~size~hashable()inList.iterrows~f:(funr->letkey=get_keyrinletdata=get_datarinadd_multires~key~data);res;;letof_alist?growth_allowed?size~hashablelst=matchcreate_mapped?growth_allowed?size~hashable~get_key:fst~get_data:sndlstwith|`Okt->`Okt|`Duplicate_keysk->`Duplicate_key(List.hd_exnk);;letof_alist_report_all_dups?growth_allowed?size~hashablelst=create_mapped?growth_allowed?size~hashable~get_key:fst~get_data:sndlst;;letof_alist_or_error?growth_allowed?size~hashablelst=matchof_alist?growth_allowed?size~hashablelstwith|`Okv->Result.Okv|`Duplicate_keykey->letsexp_of_key=hashable.Hashable.sexp_of_tinOr_error.error"Hashtbl.of_alist_exn: duplicate key"keysexp_of_key;;letof_alist_exn?growth_allowed?size~hashablelst=matchof_alist_or_error?growth_allowed?size~hashablelstwith|Result.Okv->v|Result.Errore->Error.raisee;;letof_alist_multi?growth_allowed?size~hashablelst=create_mapped_multi?growth_allowed?size~hashable~get_key:fst~get_data:sndlst;;letto_alistt=fold~f:(fun~key~datalist->(key,data)::list)~init:[]tletsexp_of_tsexp_of_keysexp_of_datat=t|>to_alist|>List.sort~compare:(fun(k1,_)(k2,_)->t.hashable.comparek1k2)|>sexp_of_list(sexp_of_pairsexp_of_keysexp_of_data);;lett_of_sexp~hashablek_of_sexpd_of_sexpsexp=letalist=list_of_sexp(pair_of_sexpk_of_sexpd_of_sexp)sexpinof_alist_exn~hashablealist~size:(List.lengthalist);;letvalidate~nameft=Validate.alist~namef(to_alistt)letkeyst=foldt~init:[]~f:(fun~key~data:_acc->key::acc)letdatat=fold~f:(fun~key:_~datalist->data::list)~init:[]tletadd_to_groupsgroups~get_key~get_data~combine~rows=List.iterrows~f:(funrow->letkey=get_keyrowinletdata=get_datarowinletdata=matchfindgroupskeywith|None->data|Someold->combineolddatainreplacegroups~key~data);;letgroup?growth_allowed?size~hashable~get_key~get_data~combinerows=letres=create?growth_allowed?size~hashable()inadd_to_groupsres~get_key~get_data~combine~rows;res;;letcreate_with_key?growth_allowed?size~hashable~get_keyrows=create_mapped?growth_allowed?size~hashable~get_key~get_data:Fn.idrows;;letcreate_with_key_or_error?growth_allowed?size~hashable~get_keyrows=matchcreate_with_key?growth_allowed?size~hashable~get_keyrowswith|`Okt->Result.Okt|`Duplicate_keyskeys->letsexp_of_key=hashable.Hashable.sexp_of_tinOr_error.error_s(Sexp.message"Hashtbl.create_with_key: duplicate keys"["keys",sexp_of_listsexp_of_keykeys]);;letcreate_with_key_exn?growth_allowed?size~hashable~get_keyrows=Or_error.ok_exn(create_with_key_or_error?growth_allowed?size~hashable~get_keyrows);;letmerge=letmaybe_sett~key~fd=matchf~keydwith|None->()|Somev->sett~key~data:vinfunt_leftt_right~f->ifnot(Hashable.equalt_left.hashablet_right.hashable)theninvalid_arg"Hashtbl.merge: different 'hashable' values";letnew_t=create~growth_allowed:t_left.growth_allowed~hashable:t_left.hashable~size:t_left.length()inwithout_mutatingt_left(fun()->without_mutatingt_right(fun()->iterit_left~f:(fun~key~data:left->matchfindt_rightkeywith|None->maybe_setnew_t~key~f(`Leftleft)|Someright->maybe_setnew_t~key~f(`Both(left,right)));iterit_right~f:(fun~key~data:right->matchfindt_leftkeywith|None->maybe_setnew_t~key~f(`Rightright)|Some_->()(* already done above *))));new_t;;type'amerge_into_action=Remove|Set_toof'aletmerge_into~src~dst~f=iterisrc~f:(fun~key~data->letdst_data=finddstkeyinletaction=without_mutatingdst(fun()->f~keydatadst_data)inmatchactionwith|Remove->removedstkey|Set_todata->matchdst_datawith|None->replacedst~key~data|Somedst_data->ifnot(phys_equaldst_datadata)thenreplacedst~key~data);;letfilteri_inplacet~f=letto_remove=foldt~init:[]~f:(fun~key~dataac->iff~key~datathenacelsekey::ac)inList.iterto_remove~f:(funkey->removetkey);;;letfilter_inplacet~f=filteri_inplacet~f:(fun~key:_~data->fdata);;letfilter_keys_inplacet~f=filteri_inplacet~f:(fun~key~data:_->fkey);;letfilter_mapi_inplacet~f=letmap_results=foldt~init:[]~f:(fun~key~dataac->(key,f~key~data)::ac)inList.itermap_results~f:(fun(key,result)->matchresultwith|None->removetkey|Somedata->sett~key~data);;;letfilter_map_inplacet~f=filter_mapi_inplacet~f:(fun~key:_~data->fdata)letmapi_inplacet~f=ensure_mutation_allowedt;without_mutatingt(fun()->Array.itert.table~f:(Avltree.mapi_inplace~f))letmap_inplacet~f=mapi_inplacet~f:(fun~key:_~data->fdata)letequaltt'equal=lengtht=lengtht'&&with_return(funr->without_mutatingt'(fun()->iterit~f:(fun~key~data->matchfindt'keywith|None->r.returnfalse|Somedata'->ifnot(equaldatadata')thenr.returnfalse));true);;letsimilar=equalmoduleAccessors=structtypenonrec'amerge_into_action='amerge_into_action=Remove|Set_toof'aletinvariant=invariantletclear=clearletcopy=copyletremove=removeletset=setletadd=addletadd_exn=add_exnletchange=changeletupdate=updateletadd_multi=add_multiletremove_multi=remove_multiletfind_multi=find_multiletmem=memletiter_keys=iter_keysletiter=iterletiteri=iteriletexists=existsletexistsi=existsiletfor_all=for_allletfor_alli=for_alliletcount=countletcounti=countiletfold=foldletlength=lengthletis_empty=is_emptyletmap=mapletmapi=mapiletfilter_map=filter_mapletfilter_mapi=filter_mapiletfilter_keys=filter_keysletfilter=filterletfilteri=filteriletpartition_map=partition_mapletpartition_mapi=partition_mapiletpartition_tf=partition_tfletpartitioni_tf=partitioni_tfletfind_or_add=find_or_addletfindi_or_add=findi_or_addletfind=findletfind_exn=find_exnletfind_and_call=find_and_callletfindi_and_call=findi_and_callletfind_and_remove=find_and_removeletto_alist=to_alistletvalidate=validateletmerge=mergeletmerge_into=merge_intoletkeys=keysletdata=dataletfilter_keys_inplace=filter_keys_inplaceletfilter_inplace=filter_inplaceletfilteri_inplace=filteri_inplaceletmap_inplace=map_inplaceletmapi_inplace=mapi_inplaceletfilter_map_inplace=filter_map_inplaceletfilter_mapi_inplace=filter_mapi_inplaceletequal=equalletsimilar=similarletincr=incrletdecr=decrletsexp_of_key=sexp_of_keyendmoduleCreators(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_moduleend=structlethashable=Key.hashabletype('a,'b)t_=('aKey.t,'b)tletcreate?growth_allowed?size()=create?growth_allowed?size~hashable()letof_alist?growth_allowed?sizel=of_alist?growth_allowed~hashable?sizel;;letof_alist_report_all_dups?growth_allowed?sizel=of_alist_report_all_dups?growth_allowed~hashable?sizel;;letof_alist_or_error?growth_allowed?sizel=of_alist_or_error?growth_allowed~hashable?sizel;;letof_alist_exn?growth_allowed?sizel=of_alist_exn?growth_allowed~hashable?sizel;;lett_of_sexpk_of_sexpd_of_sexpsexp=t_of_sexp~hashablek_of_sexpd_of_sexpsexp;;letof_alist_multi?growth_allowed?sizel=of_alist_multi?growth_allowed~hashable?sizel;;letcreate_mapped?growth_allowed?size~get_key~get_datal=create_mapped?growth_allowed~hashable?size~get_key~get_datal;;letcreate_with_key?growth_allowed?size~get_keyl=create_with_key?growth_allowed~hashable?size~get_keyl;;letcreate_with_key_or_error?growth_allowed?size~get_keyl=create_with_key_or_error?growth_allowed~hashable?size~get_keyl;;letcreate_with_key_exn?growth_allowed?size~get_keyl=create_with_key_exn?growth_allowed~hashable?size~get_keyl;;letgroup?growth_allowed?size~get_key~get_data~combinel=group?growth_allowed~hashable?size~get_key~get_data~combinel;;endmodulePoly=structtypenonrec('a,'b)t=('a,'b)ttype'akey='alethashable=Hashable.polyincludeCreators(structtype'at='alethashable=hashableend)includeAccessorsletsexp_of_t=sexp_of_tendmodulePrivate=structmoduletypeCreators_generic=Creators_genericmoduletypeHashable=Hashable.Hashabletypenonrec('key,'data,'z)create_options_without_first_class_module=('key,'data,'z)create_options_without_first_class_modulelethashablet=t.hashableendletcreate?growth_allowed?sizem=create~hashable:(Hashable.of_keym)?growth_allowed?size()letof_alist?growth_allowed?sizeml=of_alist~hashable:(Hashable.of_keym)?growth_allowed?sizelletof_alist_report_all_dups?growth_allowed?sizeml=of_alist_report_all_dups~hashable:(Hashable.of_keym)?growth_allowed?sizelletof_alist_or_error?growth_allowed?sizeml=of_alist_or_error~hashable:(Hashable.of_keym)?growth_allowed?sizelletof_alist_exn?growth_allowed?sizeml=of_alist_exn~hashable:(Hashable.of_keym)?growth_allowed?sizelletof_alist_multi?growth_allowed?sizeml=of_alist_multi~hashable:(Hashable.of_keym)?growth_allowed?sizelletcreate_mapped?growth_allowed?sizem~get_key~get_datal=create_mapped~hashable:(Hashable.of_keym)?growth_allowed?size~get_key~get_datalletcreate_with_key?growth_allowed?sizem~get_keyl=create_with_key~hashable:(Hashable.of_keym)?growth_allowed?size~get_keylletcreate_with_key_or_error?growth_allowed?sizem~get_keyl=create_with_key_or_error~hashable:(Hashable.of_keym)?growth_allowed?size~get_keylletcreate_with_key_exn?growth_allowed?sizem~get_keyl=create_with_key_exn~hashable:(Hashable.of_keym)?growth_allowed?size~get_keylletgroup?growth_allowed?sizem~get_key~get_data~combinel=group~hashable:(Hashable.of_keym)?growth_allowed?size~get_key~get_data~combinellethashable_st=Hashable.to_keyt.hashablemoduleM(K:T.T)=structtypenonrec'vt=(K.t,'v)tendmoduletypeSexp_of_m=sigtypet[@@deriving_inlinesexp_of]includesig[@@@ocaml.warning"-32"]valsexp_of_t:t->Ppx_sexp_conv_lib.Sexp.tend[@@ocaml.doc"@inline"][@@@end]endmoduletypeM_of_sexp=sigtypet[@@deriving_inlineof_sexp]includesig[@@@ocaml.warning"-32"]valt_of_sexp:Ppx_sexp_conv_lib.Sexp.t->tend[@@ocaml.doc"@inline"][@@@end]includeKeywithtypet:=tendletsexp_of_m__t(typek)(moduleK:Sexp_of_mwithtypet=k)sexp_of_vt=sexp_of_tK.sexp_of_tsexp_of_vtletm__t_of_sexp(typek)(moduleK:M_of_sexpwithtypet=k)v_of_sexpsexp=t_of_sexp~hashable:(Hashable.of_key(moduleK))K.t_of_sexpv_of_sexpsexp(* typechecking this code is a compile-time test that [Creators] is a specialization of
[Creators_generic]. *)moduleCheck:sigend=structmoduleMake_creators_check(Type:T.T2)(Key:T.T1)(Options:T.T3)(M:Creators_genericwithtype('a,'b)t:=('a,'b)Type.twithtype'akey:='aKey.twithtype('a,'b,'z)create_options:=('a,'b,'z)Options.t)=structendmoduleCheck_creators_is_specialization_of_creators_generic(M:Creators)=Make_creators_check(structtype('a,'b)t=('a,'b)M.tend)(structtype'at='aend)(structtype('a,'b,'z)t=('a,'b,'z)create_optionsend)(structincludeMletcreate?growth_allowed?sizem()=create?growth_allowed?sizemend)end