123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150(************************************************************************)(* * The Coq Proof Assistant / The Coq Development Team *)(* v * Copyright INRIA, CNRS and contributors *)(* <O___,, * (see version control and CREDITS file for authors & dates) *)(* \VV/ **************************************************************)(* // * This file is distributed under the terms of the *)(* * GNU Lesser General Public License Version 2.1 *)(* * (see LICENSE file for the text of the license) *)(************************************************************************)(* Hash consing of datastructures *)(* [t] is the type of object to hash-cons
* [u] is the type of hash-cons functions for the sub-structures
* of objects of type t (u usually has the form (t1->t1)*(t2->t2)*...).
* [hashcons u x] is a function that hash-cons the sub-structures of x using
* the hash-consing functions u provides.
* [eq] is a comparison function. It is allowed to use physical equality
* on the sub-terms hash-consed by the hashcons function.
* [hash] is the hash function given to the Hashtbl.Make function
*
* Note that this module type coerces to the argument of Hashtbl.Make.
*)moduletypeHashconsedType=sigtypettypeuvalhashcons:u->t->tvaleq:t->t->boolvalhash:t->intend(** The output is a function [generate] such that [generate args] creates a
hash-table of the hash-consed objects, together with [hcons], a function
taking a table and an object, and hashcons it. For simplicity of use, we use
the wrapper functions defined below. *)moduletypeS=sigtypettypeutypetablevalgenerate:u->tablevalhcons:table->t->tvalstats:table->Hashset.statisticsendmoduleMake(X:HashconsedType):(Swithtypet=X.tandtypeu=X.u)=structtypet=X.ttypeu=X.u(* We create the type of hashtables for t, with our comparison fun.
* An invariant is that the table never contains two entries equals
* w.r.t (=), although the equality on keys is X.eq. This is
* granted since we hcons the subterms before looking up in the table.
*)moduleHtbl=Hashset.Make(X)typetable=(Htbl.t*u)letgenerateu=lettab=Htbl.create97in(tab,u)lethcons(tab,u)x=lety=X.hashconsuxinHtbl.repr(X.hashy)ytabletstats(tab,_)=Htbl.statstabend(* A few useful wrappers:
* takes as argument the function [generate] above and build a function of type
* u -> t -> t that creates a fresh table each time it is applied to the
* sub-hcons functions. *)(* For non-recursive types it is quite easy. *)letsimple_hconshfu=lettable=huinfunx->ftablex(* Basic hashcons modules for string and obj. Integers do not need be
hashconsed. *)moduletypeHashedType=sigtypetvalhash:t->intend(* list *)moduleHlist(D:HashedType)=structmoduleX=structtypet=D.tlistleteql1l2=l1==l2||matchl1,l2with|[],[]->true|x1::l1,x2::l2->x1==x2&&l1==l2|_->falseendtypet=X.ttypeu=(D.t->D.t)moduleHtbl=Hashset.Make(X)typetable=(Htbl.t*u)letgenerateu=lettab=Htbl.create97in(tab,u)letrechcons(tab,hdataasdata)l=leth,l=matchlwith|[]->0,[]|x::l->leth,l=hconsdatalinleth=Hashset.Combine.combine(D.hashx)hinh,hdatax::linh,Htbl.reprhltablethconsdatal=snd(hconsdatal)letstats(tab,_)=Htbl.statstabend(* string *)moduleHstring=Make(structtypet=stringtypeu=unitlethashcons()s=(* incr accesstr;*)sleteq=String.equal(** Copy from CString *)letrechashlensiaccu=ifi=lenthenaccuelseletc=Char.code(String.unsafe_getsi)inhashlens(succi)(accu*19+c)lethashs=letlen=String.lengthsinhashlens00end)