Legend:
Page
Library
Module
Module type
Parameter
Class
Class type
Source
Source file int63_emul.ml
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453(* A 63bit integer is a 64bit integer with its bits shifted to the left
and its lowest bit set to 0.
This is the same kind of encoding as OCaml int on 64bit architecture.
The only difference being the lowest bit (immediate bit) set to 1. *)open!ImportincludeInt64_replace_polymorphic_comparemoduleT0=structmoduleT=structtypet=int64[@@deriving_inlinecompare,hash,sexp,sexp_grammar]letcompare=(compare_int64:t->t->int)let(hash_fold_t:Ppx_hash_lib.Std.Hash.state->t->Ppx_hash_lib.Std.Hash.state)=hash_fold_int64and(hash:t->Ppx_hash_lib.Std.Hash.hash_value)=letfunc=hash_int64infunx->funcx;;lett_of_sexp=(int64_of_sexp:Sexplib0.Sexp.t->t)letsexp_of_t=(sexp_of_int64:t->Sexplib0.Sexp.t)let(t_sexp_grammar:tSexplib0.Sexp_grammar.t)=int64_sexp_grammar[@@@end]lethashable:tHashable.t={hash;compare;sexp_of_t}endincludeTincludeComparator.Make(T)endmoduleConv=Int_conversionsmoduleW:sigincludemoduletypeofstructincludeT0endtypet=int64valwrap_exn:Caml.Int64.t->tvalwrap_modulo:Caml.Int64.t->tvalunwrap:t->Caml.Int64.t(** Returns a non-negative int64 that is equal to the input int63 modulo 2^63. *)valunwrap_unsigned:t->Caml.Int64.tvalinvariant:t->unitvaladd:t->t->tvalsub:t->t->tvalneg:t->tvalabs:t->tvalsucc:t->tvalpred:t->tvalmul:t->t->tvalpow:t->t->tvaldiv:t->t->tvalrem:t->t->tvalpopcount:t->intvalbit_not:t->tvalbit_xor:t->t->tvalbit_or:t->t->tvalbit_and:t->t->tvalshift_left:t->int->tvalshift_right:t->int->tvalshift_right_logical:t->int->tvalmin_value:tvalmax_value:tvalto_int64:t->Caml.Int64.tvalof_int64:Caml.Int64.t->toptionvalof_int64_exn:Caml.Int64.t->tvalof_int64_trunc:Caml.Int64.t->tvalcompare:t->t->intvalceil_pow2:t->tvalfloor_pow2:t->tvalceil_log2:t->intvalfloor_log2:t->intvalis_pow2:t->boolvalclz:t->intvalctz:t->intend=structincludeT0typet=int64letwrap_exnx=(* Raises if the int64 value does not fit on int63. *)Conv.int64_fit_on_int63_exnx;Caml.Int64.mulx2L;;letwrapx=ifConv.int64_is_representable_as_int63xthenSome(Caml.Int64.mulx2L)elseNone;;letwrap_modulox=Caml.Int64.mulx2Lletunwrapx=Caml.Int64.shift_rightx1letunwrap_unsignedx=Caml.Int64.shift_right_logicalx1(* This does not use wrap or unwrap to avoid generating exceptions in the case of
overflows. This is to preserve the semantics of int type on 64 bit architecture. *)letf2fab=Caml.Int64.mul(f(Caml.Int64.shift_righta1)(Caml.Int64.shift_rightb1))2L;;letmask=0xffff_ffff_ffff_fffeLletmx=Caml.Int64.logandxmaskletinvariantt=assert(mt=t)letaddxy=Caml.Int64.addxyletsubxy=Caml.Int64.subxyletnegx=Caml.Int64.negxletabsx=Caml.Int64.absxletone=wrap_exn1Lletsucca=addaoneletpreda=subaoneletmin_value=mCaml.Int64.min_intletmax_value=mCaml.Int64.max_intletbit_notx=m(Caml.Int64.lognotx)letbit_and=Caml.Int64.logandletbit_xor=Caml.Int64.logxorletbit_or=Caml.Int64.logorletshift_leftxi=Caml.Int64.shift_leftxiletshift_rightxi=m(Caml.Int64.shift_rightxi)letshift_right_logicalxi=m(Caml.Int64.shift_right_logicalxi)letpow=f2Int_math.Private.int63_pow_on_int64letmulab=Caml.Int64.mula(Caml.Int64.shift_rightb1)letdivab=wrap_modulo(Caml.Int64.divab)letremab=Caml.Int64.remabletpopcountx=Popcount.int64_popcountxletto_int64t=unwraptletof_int64t=wraptletof_int64_exnt=wrap_exntletof_int64_trunct=wrap_modulotlett_of_sexpx=wrap_exn(int64_of_sexpx)letsexp_of_tx=sexp_of_int64(unwrapx)letcompare(x:t)y=comparexyletis_pow2x=Int64.is_pow2(unwrapx)letclzx=(* We run Int64.clz directly on the wrapped int63 value. This is correct because the
bits of the int63_emul are left-aligned in the Int64. *)Int64.clzx;;letctzx=Int64.ctz(unwrapx)letfloor_pow2x=Int64.floor_pow2(unwrapx)|>wrap_exnletceil_pow2x=Int64.floor_pow2(unwrapx)|>wrap_exnletfloor_log2x=Int64.floor_log2(unwrapx)letceil_log2x=Int64.ceil_log2(unwrapx)endopenWmoduleT=structtypet=W.t[@@deriving_inlinehash,sexp,sexp_grammar]let(hash_fold_t:Ppx_hash_lib.Std.Hash.state->t->Ppx_hash_lib.Std.Hash.state)=W.hash_fold_tand(hash:t->Ppx_hash_lib.Std.Hash.hash_value)=letfunc=W.hashinfunx->funcx;;lett_of_sexp=(W.t_of_sexp:Sexplib0.Sexp.t->t)letsexp_of_t=(W.sexp_of_t:t->Sexplib0.Sexp.t)let(t_sexp_grammar:tSexplib0.Sexp_grammar.t)=W.t_sexp_grammar[@@@end]typecomparator_witness=W.comparator_witnessletcomparator=W.comparatorletcompare=W.compareletinvariant=W.invariant(* We don't expect [hash] to follow the behavior of int in 64bit architecture *)let_=hashlethash(x:t)=Caml.Hashtbl.hashxlethashable:tHashable.t={hash;compare;sexp_of_t}letinvalid_strx=Printf.failwithf"Int63.of_string: invalid input %S"x()(*
"sign" refers to whether the number starts with a '-'
"signedness = false" means the rest of the number is parsed as unsigned and then cast
to signed with wrap-around modulo 2^i
"signedness = true" means no such craziness happens
The terminology and the logic is due to the code in byterun/ints.c in ocaml 4.03
([parse_sign_and_base] function).
Signedness equals true for plain decimal number (e.g. 1235, -6789)
Signedness equals false in the following cases:
- [0xffff], [-0xffff] (hexadecimal representation)
- [0b0101], [-0b0101] (binary representation)
- [0o1237], [-0o1237] (octal representation)
- [0u9812], [-0u9812] (unsigned decimal representation - available from OCaml 4.03) *)letsign_and_signednessx=letlen=String.lengthxinletopenInt_replace_polymorphic_compareinletpos,sign=if0<lenthen(matchx.[0]with|'-'->1,`Neg|'+'->1,`Pos|_->0,`Pos)else0,`Posinifpos+2<lenthen(letc1=x.[pos]inletc2=x.[pos+1]inmatchc1,c2with|'0','0'..'9'->sign,true|'0',_->sign,false|_->sign,true)elsesign,true;;letto_stringx=Caml.Int64.to_string(unwrapx)letof_stringstr=tryletsign,signedness=sign_and_signednessstrinifsignednessthenof_int64_exn(Caml.Int64.of_stringstr)else(letpos_str=matchsignwith|`Neg->String.substr~pos:1~len:(String.lengthstr-1)|`Pos->strinletint64=Caml.Int64.of_stringpos_strin(* unsigned 63-bit int must parse as a positive signed 64-bit int *)ifInt64_replace_polymorphic_compare.(<)int640Ltheninvalid_strstr;letint63=wrap_moduloint64inmatchsignwith|`Neg->negint63|`Pos->int63)with|_->invalid_strstr;;letbswap16t=wrap_modulo(Int64.bswap16(unwrapt))letbswap32t=wrap_modulo(Int64.bswap32(unwrapt))letbswap48t=wrap_modulo(Int64.bswap48(unwrapt))endincludeTletnum_bits=63letfloat_lower_bound=Float0.lower_bound_for_intnum_bitsletfloat_upper_bound=Float0.upper_bound_for_intnum_bitsletshift_right_logical=shift_right_logicalletshift_right=shift_rightletshift_left=shift_leftletbit_not=bit_notletbit_xor=bit_xorletbit_or=bit_orletbit_and=bit_andletpopcount=popcountletabs=absletpred=predletsucc=succletpow=powletrem=remletneg=negletmax_value=max_valueletmin_value=min_valueletminus_one=wrap_exnCaml.Int64.minus_oneletone=wrap_exnCaml.Int64.oneletzero=wrap_exnCaml.Int64.zeroletis_pow2=is_pow2letfloor_pow2=floor_pow2letceil_pow2=ceil_pow2letfloor_log2=floor_log2letceil_log2=ceil_log2letclz=clzletctz=ctzletto_floatx=Caml.Int64.to_float(unwrapx)letof_float_uncheckedx=wrap_modulo(Caml.Int64.of_floatx)letof_floatt=letopenFloat_replace_polymorphic_compareinift>=float_lower_bound&&t<=float_upper_boundthenwrap_modulo(Caml.Int64.of_floatt)elsePrintf.invalid_argf"Int63.of_float: argument (%f) is out of range or NaN"(Float0.boxt)();;letof_int64=of_int64letof_int64_exn=of_int64_exnletof_int64_trunc=of_int64_truncletto_int64=to_int64includeComparable.With_zero(structincludeTletzero=zeroend)letbetweent~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);;let(/)=divlet(*)=mullet(-)=sublet(+)=addlet(~-)=neglet(**)be=powbeletincrr=r:=!r+oneletdecrr=r:=!r-one(* We can reuse conversion function from/to int64 here. *)letof_intx=wrap_exn(Conv.int_to_int64x)letof_int_exnx=of_intxletto_intx=Conv.int64_to_int(unwrapx)letto_int_exnx=Conv.int64_to_int_exn(unwrapx)letto_int_truncx=Conv.int64_to_int_trunc(unwrapx)letof_int32x=wrap_exn(Conv.int32_to_int64x)letof_int32_exnx=of_int32xletto_int32x=Conv.int64_to_int32(unwrapx)letto_int32_exnx=Conv.int64_to_int32_exn(unwrapx)letto_int32_truncx=Conv.int64_to_int32_trunc(unwrapx)letof_nativeintx=of_int64(Conv.nativeint_to_int64x)letof_nativeint_exnx=wrap_exn(Conv.nativeint_to_int64x)letof_nativeint_truncx=of_int64_trunc(Conv.nativeint_to_int64x)letto_nativeintx=Conv.int64_to_nativeint(unwrapx)letto_nativeint_exnx=Conv.int64_to_nativeint_exn(unwrapx)letto_nativeint_truncx=Conv.int64_to_nativeint_trunc(unwrapx)includeConv.Make(T)includeConv.Make_hex(structtypet=T.t[@@deriving_inlinecompare,hash]letcompare=(T.compare:t->t->int)let(hash_fold_t:Ppx_hash_lib.Std.Hash.state->t->Ppx_hash_lib.Std.Hash.state)=T.hash_fold_tand(hash:t->Ppx_hash_lib.Std.Hash.hash_value)=letfunc=T.hashinfunx->funcx;;[@@@end]letzero=zeroletneg=(~-)let(<)=(<)letto_stringi=(* the use of [unwrap_unsigned] here is important for the case of [min_value] *)Printf.sprintf"%Lx"(unwrap_unsignedi);;letof_strings=of_string("0x"^s)letmodule_name="Base.Int63.Hex"end)includePretty_printer.Register(structtypenonrect=tletto_stringx=to_stringxletmodule_name="Base.Int63"end)modulePre_O=structlet(+)=(+)let(-)=(-)let(*)=(*)let(/)=(/)let(~-)=(~-)let(**)=(**)include(Int64_replace_polymorphic_compare:Comparisons.Infixwithtypet:=t)letabs=absletneg=negletzero=zeroletof_int_exn=of_int_exnendmoduleO=structincludePre_OincludeInt_math.Make(structtypenonrect=tincludePre_Oletrem=remletto_float=to_floatletof_float=of_floatletof_string=T.of_stringletto_string=T.to_stringend)let(land)=bit_andlet(lor)=bit_orlet(lxor)=bit_xorletlnot=bit_notlet(lsl)=shift_leftlet(asr)=shift_rightlet(lsr)=shift_right_logicalendincludeO(* [Int63] and [Int63.O] agree value-wise *)moduleRepr=structtypeemulated=ttype('underlying_type,'intermediate_type)t=|Int:(int,int)t|Int64:(int64,emulated)tendletrepr=Repr.Int64(* Include type-specific [Replace_polymorphic_compare] at the end, after
including functor application that could shadow its definitions. This is
here so that efficient versions of the comparison functions are exported by
this module. *)includeInt64_replace_polymorphic_compare