123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124open!CoreopenPolyincludeFlags_intfletcreate~bit:n=ifn<0||n>62thenfailwiths~here:[%here]"Flags.create got invalid ~bit (must be between 0 and 62)"n[%sexp_of:int];Int63.shift_leftInt63.onen;;moduleMake(M:Make_arg)=structtypet=Int63.t[@@derivingbin_io,hash,typerep]letof_int=Int63.of_intletto_int_exn=Int63.to_int_exnletempty=Int63.zeroletis_emptyt=t=emptylet(+)ab=Int63.bit_orablet(-)ab=Int63.bit_anda(Int63.bit_notb)letintersect=Int63.bit_andletcomplement=Int63.bit_notletis_subsett~of_=Int63.(=)t(intersecttof_)letdo_intersectt1t2=Int63.(<>)(Int63.bit_andt1t2)Int63.zeroletare_disjointt1t2=Int63.(=)(Int63.bit_andt1t2)Int63.zeroleterrormessageasexp_of_a=lete=Error.createmessageasexp_of_ainifM.should_print_errortheneprintf"%s\n%!"(Sexp.to_string_hum(Error.sexp_of_te));Error.raisee;;letknown=ifM.remove_zero_flagsthenList.filter~f:(fun(n,_)->not(Int63.equalnInt63.zero))M.knownelseM.known;;let()=ifnotM.allow_intersectingthen(letrecchecklac=matchlwith|[]->ac|(flag,name)::l->letbad=List.filterl~f:(fun(flag',_)->do_intersectflagflag')inletac=ifList.is_emptybadthenacelse(flag,name,bad)::acinchecklacinletbad=checkknown[]inifnot(List.is_emptybad)thenerror"Flags.Make got intersecting flags"bad[%sexp_of:(Int63.t*string*(Int63.t*string)list)list]);;let()=letbad=List.filterknown~f:(fun(flag,_)->flag=Int63.zero)inifnot(List.is_emptybad)thenerror"Flag.Make got flags with no bits set"bad[%sexp_of:(Int63.t*string)list];;typesexp_format=stringlist[@@derivingsexp]letsexp_of_t=(* We reverse [known] so that the fold below accumulates from right to left, giving a
final list with elements in the same order as [known]. *)letknown=List.revknowninfunt->letleftover,flag_names=List.foldknown~init:(t,[])~f:(fun(t,flag_names)(flag,flag_name)->ifInt63.bit_andtflag=flagthent-flag,flag_name::flag_nameselset,flag_names)inifleftover=emptythen[%sexp_of:sexp_format]flag_nameselse[%sexp_of:stringlist*[`unrecognized_bitsofstring]](flag_names,`unrecognized_bits(sprintf"0x%Lx"(Int63.to_int64leftover)));;letknown_by_name=String.Table.of_alist_exn(List.mapknown~f:(fun(mask,name)->name,mask));;lett_of_sexpsexp=List.fold(sexp|>[%of_sexp:sexp_format])~init:empty~f:(funtname->matchHashtbl.findknown_by_namenamewith|Somemask->t+mask|None->of_sexp_error(sprintf"Flags.t_of_sexp got unknown name: %s"name)sexp);;(* total order such that [subset a b] implies [a <= b] *)letcomparetu=(* This is the same as {| Int63.(i bit_xor (one shift_left 62)) |} *)letflip_top_biti=Int63.(+)iInt63.min_valueinInt63.compare(flip_top_bitt)(flip_top_bitu);;includeComparable.Make(structtypenonrect=t[@@derivingsexp,compare,hash]end)(* [Comparable.Make] turns [equal] into a function call to [compare] rather than the
much simpler (and equally correct) [Int63.(=)]. Restore it, as well as (=) and (<>). *)letequal=Int63.(=)let(=)=Int63.(=)let(<>)=Int63.(<>)moduleUnstable=structtypenonrect=t[@@derivingbin_io,compare,sexp]endend