12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091(* A cell, recording a single change of the changelog.
It needs to be a GADT to hide the parameters of the Hashtbl. *)typecell=Cell:{stamp:int;table:('a,'b)Hashtbl.t;key:'a;}->celltypechangelog={mutablerecent:celllist;(* The [recent] list contains the changes that happened since the last
call to backtrack, in reverse order (the most recent change is first
in the list). *)mutablesorted:celllist;(* Cells in the [sorted] list are sorted by decreasing stamp, such that
listing all cells greater than a threshold is a simple, in order,
traversal. *)}letcreate_changelog()={recent=[];sorted=[];}(* Wrappers around [Hashtbl] *)type('a,'b)t={table:('a,'b)Hashtbl.t;changelog:changelog;}letcreatechangelogn={table=Hashtbl.createn;changelog;}letadd{table;changelog}?stampkeyvalue=Hashtbl.addtablekeyvalue;matchstampwith|None->()|Somestamp->changelog.recent<-Cell{stamp;key;table}::changelog.recentletmemta=Hashtbl.memt.tablealetfindta=Hashtbl.findt.tablea(* Implementation of backtracking *)(* Helper to sort by decreasing stamps *)letorder(Cellc1)(Cellc2)=Int.comparec2.stampc1.stamp(* Drop the prefix not satisfying a certain predicate *)letrecfilter_prefixpred=function|x::xswhennot(predx)->filter_prefixpredxs|xs->xsletbacktrackcs~stamp=(* Check if a cell is still valid (older than [stamp]).
If not, remove it from its table. *)letprocess(Cellc)=ifc.stamp>stampthen(Hashtbl.removec.tablec.key;false)elsetruein(* Process recent list:
- remove items newer than [stamp]
- sort the remainder *)letrecent=cs.recent|>List.filterprocess|>List.fast_sortorderincs.recent<-[];(* Process sorted list:
- remove prefix items newer than [stamp]
- merge remaining items with the recent ones
*)letsorted=cs.sorted|>filter_prefixprocess|>List.mergeorderrecentincs.sorted<-sorted