package base
Source file int63.ml
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210open! Import let raise_s = Error.raise_s module Repr = Int63_emul.Repr (* In a world where the compiler would understand [@@immediate64] attributes on type declarations, this module is how one would produce a [type t] with this attribute. *) module Immediate64 : sig module type Non_immediate = sig type t end module type Immediate = sig type t [@@immediate] end module Make (Immediate : Immediate) (Non_immediate : Non_immediate) : sig type t [@@immediate64] type 'a repr = | Immediate : Immediate.t repr | Non_immediate : Non_immediate.t repr val repr : t repr end end = struct module type Non_immediate = sig type t end module type Immediate = sig type t [@@immediate] end module Make (Immediate : Immediate) (Non_immediate : Non_immediate) = struct type t [@@immediate64] type 'a repr = | Immediate : Immediate.t repr | Non_immediate : Non_immediate.t repr external transparent_magic : ('a[@local_opt]) -> ('b[@local_opt]) = "%identity" let repr = (* [Obj.magic] involves opaqueness under Flambda 2 which will inhibit availability of functions defined in this module for later inlining (e.g. into float.ml). As such we explicitly use %identity here. *) match Word_size.word_size with | W64 -> (transparent_magic Immediate : t repr) | W32 -> (transparent_magic Non_immediate : t repr) ;; end [@@inline always] end include Immediate64.Make (Int) (Int63_emul) module Backend = struct module type S = sig type t include Int_intf.S with type t := t val of_int : int -> t val to_int : t -> int option val to_int_trunc : t -> int val of_int32 : int32 -> t val to_int32 : t -> Int32.t option val to_int32_trunc : t -> Int32.t val of_int64 : Int64.t -> t option val of_int64_trunc : Int64.t -> t val of_nativeint : nativeint -> t option val to_nativeint : t -> nativeint option val of_nativeint_trunc : nativeint -> t val to_nativeint_trunc : t -> nativeint val of_float_unchecked : float -> t val repr : (t, t) Int63_emul.Repr.t val bswap16 : t -> t val bswap32 : t -> t val bswap48 : t -> t end with type t := t module Native = struct include Int let to_int x = Some x let to_int_trunc x = x (* [of_int32_exn] is a safe operation on platforms with 64-bit word sizes. *) let of_int32 = of_int32_exn let to_nativeint_trunc x = to_nativeint x let to_nativeint x = Some (to_nativeint x) let repr = Int63_emul.Repr.Int let bswap32 t = Int64.to_int_trunc (Int64.bswap32 (Int64.of_int t)) let bswap48 t = Int64.to_int_trunc (Int64.bswap48 (Int64.of_int t)) end let impl : (module S) = match repr with | Immediate -> (module Native : S) | Non_immediate -> (module Int63_emul : S) ;; end include (val Backend.impl : Backend.S) module Overflow_exn = struct let ( + ) t u = let sum = t + u in if bit_or (bit_xor t u) (bit_xor t (bit_not sum)) < zero then sum else raise_s (Sexp.message "( + ) overflow" [ "t", sexp_of_t t; "u", sexp_of_t u; "sum", sexp_of_t sum ]) ;; let ( - ) t u = let diff = t - u in let pos_diff = t > u in if t <> u && Bool.( <> ) pos_diff (is_positive diff) then raise_s (Sexp.message "( - ) overflow" [ "t", sexp_of_t t; "u", sexp_of_t u; "diff", sexp_of_t diff ]) else diff ;; let negative_one = of_int (-1) let div_would_overflow t u = t = min_value && u = negative_one let ( * ) t u = let product = t * u in if u <> zero && (div_would_overflow product u || product / u <> t) then raise_s (Sexp.message "( * ) overflow" [ "t", sexp_of_t t; "u", sexp_of_t u; "product", sexp_of_t product ]) else product ;; let ( / ) t u = if div_would_overflow t u then raise_s (Sexp.message "( / ) overflow" [ "t", sexp_of_t t; "u", sexp_of_t u; "product", sexp_of_t (t / u) ]) else t / u ;; let abs t = if t = min_value then failwith "abs overflow" else abs t let neg t = if t = min_value then failwith "neg overflow" else neg t end let () = assert (Int.( = ) num_bits 63) let random_of_int ?(state = Random.State.default) bound = of_int (Random.State.int state (to_int_exn bound)) ;; let random_of_int64 ?(state = Random.State.default) bound = of_int64_exn (Random.State.int64 state (to_int64 bound)) ;; let random = match Word_size.word_size with | W64 -> random_of_int | W32 -> random_of_int64 ;; let random_incl_of_int ?(state = Random.State.default) lo hi = of_int (Random.State.int_incl state (to_int_exn lo) (to_int_exn hi)) ;; let random_incl_of_int64 ?(state = Random.State.default) lo hi = of_int64_exn (Random.State.int64_incl state (to_int64 lo) (to_int64 hi)) ;; let random_incl = match Word_size.word_size with | W64 -> random_incl_of_int | W32 -> random_incl_of_int64 ;; let floor_log2 t = match Word_size.word_size with | W64 -> t |> to_int_exn |> Int.floor_log2 | W32 -> if t <= zero then raise_s (Sexp.message "[Int.floor_log2] got invalid input" [ "", sexp_of_t t ]); let floor_log2 = ref (Int.( - ) num_bits 2) in while equal zero (bit_and t (shift_left one !floor_log2)) do floor_log2 := Int.( - ) !floor_log2 1 done; !floor_log2 ;; module Private = struct module Repr = Repr let repr = repr module Emul = Int63_emul end