123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125openCoremoduleMake_plain(Key:sigtypet[@@derivingsexp_of]includeComparator.Swithtypet:=tend)=structmoduleUpdate=structmoduleDiff=structtypet=|RemoveofKey.t|AddofKey.t(* We add a [unit] argument so matching the more common cases
is more performant (no check for immediate vs. block). *)|Idleofunit[@@derivingsexp_of]letidle=Idle()endtypet=Diff.tlist[@@derivingsexp_of]endtypet=Set.M(Key).tletempty=Set.empty(moduleKey)letupdatetdiffs=List.folddiffs~init:t~f:(funtd->match(d:Update.Diff.t)with|Removekey->Set.removetkey|Addkey->Set.addtkey|Idle()->t);;letdiffs~from~to_:Update.t=Set.symmetric_difffromto_|>Sequence.map~f:(function|Firstk->Update.Diff.Removek|Secondk->Addk)|>Sequence.to_list;;letof_diffs(diffs:Update.t)=List.folddiffs~init:empty~f:(funtd->matchdwith|Remove_->failwith"Remove is not allowed in of_diffs."|Addkey->Set.addtkey|Idle()->t);;letto_diffs(t:t):Update.t=letl=Set.to_listt|>List.map~f:(funk->Update.Diff.Addk)inmatchlwith|[]->[Update.Diff.idle]|l->l;;endmoduleMake(Key:sigtypet[@@derivingsexp,bin_io]includeComparator.Swithtypet:=tend)=structmodulePlain=Make_plain(Key)moduleUpdate=structmoduleDiff=structtypet=Plain.Update.Diff.t=|RemoveofKey.t|AddofKey.t|Idleofunit[@@derivingsexp,bin_io]endtypet=Diff.tlist[@@derivingsexp,bin_io]endinclude(Plain:moduletypeofstructincludePlainendwithmoduleUpdate:=Plain.Update)endlet%test_module"tests"=(modulestructmoduleT=structmoduleU=structtypet=int[@@derivingbin_io,compare,equal,sexp]endincludeUincludeComparable.Make(U)endincludeTincludeMake(T)let%test_unit"atomic round-trip works"=Quickcheck.test(Quickcheck.Generator.listInt.quickcheck_generator)~sexp_of:[%sexp_of:intlist]~f:(funns->lett=T.Set.of_listnsin[%test_result:T.Set.t]~expect:t(of_diffs(to_diffst)));;let%test_unit"atomic diff/update works"=letopenQuickcheckinQuickcheck.test(Generator.tuple2(Quickcheck.Generator.listInt.quickcheck_generator)(Quickcheck.Generator.listInt.quickcheck_generator))~sexp_of:[%sexp_of:intlist*intlist]~f:(fun(from,to_)->letfrom=T.Set.of_listfrominletto_=T.Set.of_listto_in[%test_result:T.Set.t]~expect:to_(updatefrom(diffs~from~to_)));;end);;