123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260open!ImportincludeComparable_intfmoduleValidate(T:sigtypet[@@deriving_inlinecompare,sexp_of]valcompare:t->t->intvalsexp_of_t:t->Ppx_sexp_conv_lib.Sexp.t[@@@end]end):Validatewithtypet:=T.t=structmoduleV=ValidateopenMaybe_boundletto_stringt=Sexp.to_string(T.sexp_of_tt)letvalidate_bound~min~maxt=V.bounded~name:to_string~lower:min~upper:max~compare:T.comparet;;letvalidate_lbound~mint=validate_bound~min~max:Unboundedtletvalidate_ubound~maxt=validate_bound~max~min:UnboundedtendmoduleWith_zero(T:sigtypet[@@deriving_inlinecompare]valcompare:t->t->int[@@@end]valzero:tincludeValidatewithtypet:=tend)=structopenT(* Preallocate the interesting bounds to minimize allocation in the implementations of
[validate_*]. *)letexcl_zero=Maybe_bound.Exclzeroletincl_zero=Maybe_bound.Inclzeroletvalidate_positivet=validate_lbound~min:excl_zerotletvalidate_non_negativet=validate_lbound~min:incl_zerotletvalidate_negativet=validate_ubound~max:excl_zerotletvalidate_non_positivet=validate_ubound~max:incl_zerotletis_positivet=comparetzero>0letis_non_negativet=comparetzero>=0letis_negativet=comparetzero<0letis_non_positivet=comparetzero<=0letsignt=Sign0.of_int(comparetzero)endmoduleValidate_with_zero(T:sigtypet[@@deriving_inlinecompare,sexp_of]valcompare:t->t->intvalsexp_of_t:t->Ppx_sexp_conv_lib.Sexp.t[@@@end]valzero:tend)=structmoduleV=Validate(T)includeVincludeWith_zero(structincludeTincludeVend)endmodulePoly(T:sigtypet[@@deriving_inlinesexp_of]valsexp_of_t:t->Ppx_sexp_conv_lib.Sexp.t[@@@end]end)=structmoduleReplace_polymorphic_compare=structtypet=T.t[@@deriving_inlinesexp_of]letsexp_of_t=(T.sexp_of_t:t->Ppx_sexp_conv_lib.Sexp.t)[@@@end]includePolyendincludePolyletbetweent~low~high=low<=t&&t<=highletclamp_uncheckedt~min~max=ift<minthenminelseift<=maxthentelsemaxletclamp_exnt~min~max=assert(min<=max);clamp_uncheckedt~min~max;;letclampt~min~max=ifmin>maxthenOr_error.error_s(Sexp.message"clamp requires [min <= max]"["min",T.sexp_of_tmin;"max",T.sexp_of_tmax])elseOk(clamp_uncheckedt~min~max);;moduleC=structincludeTincludeComparator.Make(Replace_polymorphic_compare)endincludeCincludeValidate(structtypenonrect=t[@@deriving_inlinecompare,sexp_of]letcompare=(compare:t->t->int)letsexp_of_t=(sexp_of_t:t->Ppx_sexp_conv_lib.Sexp.t)[@@@end]end)endletgtcmpab=cmpab>0letltcmpab=cmpab<0letgeqcmpab=cmpab>=0letleqcmpab=cmpab<=0letequalcmpab=cmpab=0letnot_equalcmpab=cmpab<>0letmincmptt'=ifleqcmptt'thentelset'letmaxcmptt'=ifgeqcmptt'thentelset'moduleInfix(T:sigtypet[@@deriving_inlinecompare]valcompare:t->t->int[@@@end]end):Infixwithtypet:=T.t=structlet(>)ab=gtT.compareablet(<)ab=ltT.compareablet(>=)ab=geqT.compareablet(<=)ab=leqT.compareablet(=)ab=equalT.compareablet(<>)ab=not_equalT.compareabendmodulePolymorphic_compare(T:sigtypet[@@deriving_inlinecompare]valcompare:t->t->int[@@@end]end):Polymorphic_comparewithtypet:=T.t=structincludeInfix(T)letcompare=T.compareletequal=(=)letmintt'=mincomparett'letmaxtt'=maxcomparett'endmoduleMake_using_comparator(T:sigtypet[@@deriving_inlinesexp_of]valsexp_of_t:t->Ppx_sexp_conv_lib.Sexp.t[@@@end]includeComparator.Swithtypet:=tend):Swithtypet:=T.tandtypecomparator_witness=T.comparator_witness=structmoduleT=structincludeTletcompare=comparator.compareendincludeTmoduleReplace_polymorphic_compare=Polymorphic_compare(T)includeReplace_polymorphic_compareletascending=compareletdescendingtt'=comparet'tletbetweent~low~high=low<=t&&t<=highletclamp_uncheckedt~min~max=ift<minthenminelseift<=maxthentelsemaxletclamp_exnt~min~max=assert(min<=max);clamp_uncheckedt~min~max;;letclampt~min~max=ifmin>maxthenOr_error.error_s(Sexp.message"clamp requires [min <= max]"["min",T.sexp_of_tmin;"max",T.sexp_of_tmax])elseOk(clamp_uncheckedt~min~max);;includeValidate(T)endmoduleMake(T:sigtypet[@@deriving_inlinecompare,sexp_of]valcompare:t->t->intvalsexp_of_t:t->Ppx_sexp_conv_lib.Sexp.t[@@@end]end)=Make_using_comparator(structincludeTincludeComparator.Make(T)end)moduleInherit(C:sigtypet[@@deriving_inlinecompare]valcompare:t->t->int[@@@end]end)(T:sigtypet[@@deriving_inlinesexp_of]valsexp_of_t:t->Ppx_sexp_conv_lib.Sexp.t[@@@end]valcomponent:t->C.tend)=Make(structtypet=T.t[@@deriving_inlinesexp_of]letsexp_of_t=(T.sexp_of_t:t->Ppx_sexp_conv_lib.Sexp.t)[@@@end]letcomparett'=C.compare(T.componentt)(T.componentt')end)(* compare [x] and [y] lexicographically using functions in the list [cmps] *)letlexicographiccmpsxy=letrecloop=function|cmp::cmps->letres=cmpxyinifres=0thenloopcmpselseres|[]->0inloopcmps;;letliftcmp~fxy=cmp(fx)(fy)letreversecmpxy=cmpyx