123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158(************************************************************************)(* * The Rocq Prover / The Rocq 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 *)type'af='a->int*'a(* [t] is the type of object to hash-cons
* [hashcons x] is a function that hash-cons the sub-structures of x
* [eq] is a comparison function. It is allowed to use physical equality
* on the sub-terms hash-consed by the hashcons function.
*)moduletypeHashconsedType=sigtypetvalhashcons:tfvaleq:t->t->boolendmoduletypeHashconsedRecType=sigtypetvalhashcons:tf->tfvaleq:t->t->boolend(** 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=sigtypettypetablevalgenerate:unit->tablevalhcons:table->tfvalstats:table->Hashset.statisticsendmoduleMake(X:HashconsedType):(Swithtypet=X.t)=structtypet=X.t(* 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.tletgenerate()=lettab=Htbl.create97intablethconstabx=leth,y=X.hashconsxinh,Htbl.reprhytabletstats=Htbl.statsendmoduleMakeRec(X:HashconsedRecType):(Swithtypet=X.t)=structtypet=X.tmoduleHtbl=Hashset.Make(X)typetable=Htbl.tletgenerate()=lettab=Htbl.create97intabletrechconstabx=leth,y=X.hashcons(hconstab)xinh,Htbl.reprhytabletstats=Htbl.statsend(* 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=sigtypetvalhcons:tfend(* list *)moduleHlist(D:HashedType):Swithtypet=D.tlist=structmoduleX=structtypet=D.tlistleteql1l2=l1==l2||matchl1,l2with|[],[]->true|x1::l1,x2::l2->x1==x2&&l1==l2|_->falseendtypet=X.tmoduleHtbl=Hashset.Make(X)typetable=Htbl.tletgenerate()=lettab=Htbl.create97intabletrechconstabl=leth,l=matchlwith|[]->0,[]|x::l->lethx,x=D.hconsxinleth,l=hconstablinleth=Hashset.Combine.combinehxhinh,x::linh,Htbl.reprhltabletstats=Htbl.statsendlethashcons_arrayhconsa=CArray.Smart.fold_left_map(funaccx->lethx,x=hconsxinHashset.Combine.combineacchx,x)0a