123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153open!CoreopenPolyincludeFlags_intf(* To allow [create] to be eagerly inlined, move this exception with macro expansion to
its own function and mark it [@cold] so that it isn't inlined. *)let[@cold]raise_invalid_bitn=failwiths~here:[%here]"Flags.create got invalid ~bit (must be between 0 and 62)"n[%sexp_of:int];;letcreate~bit:n=ifn<0||n>62thenraise_invalid_bitn;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_andletall=List.foldM.known~init:empty~f:(funacc(flag,_)->acc+flag)letcomplementa=all-aletis_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]typesexp_format_with_unrecognized_bits=stringlist*[`unrecognized_bitsofstring][@@derivingsexp]letto_flag_list=(* 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->List.foldknown~init:(t,[])~f:(fun(t,flag_names)(flag,flag_name)->ifInt63.bit_andtflag=flagthent-flag,flag_name::flag_nameselset,flag_names);;letsexp_of_tt=letto_unsigned_hex_stringx=Int64.(max_valuelandInt63.to_int64x)|>Int64.Hex.to_stringinletleftover,flag_names=to_flag_listtinifleftover=emptythen[%sexp_of:sexp_format]flag_nameselse[%sexp_of:sexp_format_with_unrecognized_bits](flag_names,`unrecognized_bits(to_unsigned_hex_stringleftover));;letknown_by_name=String.Table.of_alist_exn(List.mapknown~f:(fun(mask,name)->name,mask));;lett_of_sexp(sexp:Sexp.t)=letof_unsigned_hex_strings=Int64.Hex.of_strings|>Int63.of_int64_truncinletrestore_int_of_flags_sexpflags=List.fold(flags|>[%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)inmatchsexpwith|Sexp.List[Sexp.Listflags;Sexp.Listunrecognized]->(matchunrecognizedwith|[Sexp.Atom"unrecognized_bits";Sexp.Atomnum]->restore_int_of_flags_sexp(Sexp.Listflags)+of_unsigned_hex_stringnum|_->raise_s[%message"Of_sexp_error: sexp format does not match any recognized format"(sexp:Sexp.t)])|Sexp.Listflags->restore_int_of_flags_sexp(Sexp.Listflags)|Sexp.Atom_->raise_s[%message"Of_sexp_error: list needed"(sexp:Sexp.t)];;(* 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