diff --git a/src/core/CCInt.ml b/src/core/CCInt.ml index 547ecee9..5f1b49ae 100644 --- a/src/core/CCInt.ml +++ b/src/core/CCInt.ml @@ -3,9 +3,35 @@ open CCShims_ +include CCShimsInt_ + type t = int type 'a iter = ('a -> unit) -> unit +let zero = 0 + +let one = 1 + +let minus_one = -1 + +let add = (+) + +let sub = (-) + +let mul = ( * ) + +let div = (/) + +let succ = succ + +let pred = pred + +let abs = abs + +let max_int = max_int + +let min_int = min_int + let equal (a:int) b = Stdlib.(=) a b let compare (a:int) b = compare a b @@ -45,10 +71,7 @@ let range' i j yield = [5;4;3] (range' 5 2 |> Iter.to_list) *) -let sign i = - if i < 0 then -1 - else if i>0 then 1 - else 0 +let sign i = compare i 0 let neg i = -i @@ -211,6 +234,8 @@ let of_string s = let of_string_exn = Stdlib.int_of_string +let to_float = float_of_int + let of_float = int_of_float (*$= @@ -267,7 +292,7 @@ let range_by ~step i j yield = ) in if step = 0 then - raise (Invalid_argument "CCList.range_by") + raise (Invalid_argument "CCInt.range_by") else if (if step > 0 then i>j else i t -> t +(** [add x y] is [x + y]. + @since NEXT_RELEASE *) + +val sub : t -> t -> t +(** [sub x y] is [x - y]. + @since NEXT_RELEASE *) + +val mul : t -> t -> t +(** [mul x y] is [x * y]. + @since NEXT_RELEASE *) + +val div : t -> t -> t +(** [div x y] is [x / y] + @since NEXT_RELEASE *) + +val succ : t -> t +(** [succ x] is [x + 1]. + @since NEXT_RELEASE *) + +val pred : t -> t +(** [pred x] is [x - 1]. + @since NEXT_RELEASE *) + +val abs : t -> t +(** [abs x] is the absolute value of [x]. It is [x] if [x] is positive + and [neg x] otherwise. + @since NEXT_RELEASE *) + +val max_int : t +(** [max_int] is the maximum integer. + @since NEXT_RELEASE *) + +val min_int : t +(** [min_int] is the minimum integer. + @since NEXT_RELEASE *) + val compare : t -> t -> int -(** [compare x y] is the comparison function for integers +(** [compare x y] is the comparison function for integers with the same specification as {!Stdlib.compare}. *) val equal : t -> t -> bool @@ -15,9 +66,10 @@ val equal : t -> t -> bool val hash : t -> int (** [hash x] computes the hash of [x]. *) - + val sign : t -> int -(** [sign x] is one of [-1, 0, 1]. *) +(** [sign x] return [0] if [x = 0], [-1] if [x < 0] and [1] if [x > 0]. + Same as [compare x 0].*) val neg : t -> t (** [neg x] is [- x]. @@ -49,7 +101,15 @@ val random_small : t random_gen val random_range : int -> int -> t random_gen val pp : t printer -(** [pp ppf x] prints the integer [x] on [ppf]. *) +(** [pp ppf x] prints the integer [x] on [ppf]. *) + +val to_float : t -> float +(** [to_float] is the same as [float_of_int] + @since NEXT_RELEASE*) + +val of_float : float -> t +(** [to_float] is the same as [int_of_float] + @since NEXT_RELEASE*) val to_string : t -> string (** [to_string x] returns the string representation of the integer [x], in signed decimal. @@ -109,6 +169,34 @@ val popcount : t -> int (** Number of bits set to 1 @since NEXT_RELEASE *) +val logand : t -> t -> t +(** [logand] is the same as [(land)]. + @since NEXT_RELEASE *) + +val logor : t -> t -> t +(** [logand] is the same as [(lor)]. + @since NEXT_RELEASE *) + +val logxor : t -> t -> t +(** [logxor] is the same as [(lxor)]. + @since NEXT_RELEASE *) + +val lognot : t -> t +(** [logand] is the same as [lnot]. + @since NEXT_RELEASE *) + +val shift_left : t -> int -> t +(** [shift_left] is the same as [(lsl)]. + @since NEXT_RELEASE *) + +val shift_right : t -> int -> t +(** [shift_right] is the same as [(asr)]. + @since NEXT_RELEASE *) + +val shift_right_logical : t -> int -> t +(** [shift_right_logical] is the same as [(lsr)]. + @since NEXT_RELEASE *) + (** {2 Infix Operators} @since 0.17 *) diff --git a/src/core/CCInt32.ml b/src/core/CCInt32.ml index dbe198db..2abe36cd 100644 --- a/src/core/CCInt32.ml +++ b/src/core/CCInt32.ml @@ -3,6 +3,200 @@ open CCShims_ include Int32 + +let min : t -> t -> t = Stdlib.min +let max : t -> t -> t = Stdlib.max + +let hash x = Stdlib.abs (to_int x) + +let sign i = compare i zero + +let pow a b = + let rec aux acc = function + | 1l -> acc + | n -> + if equal (rem n 2l) zero + then aux (mul acc acc) (div n 2l) + else mul acc (aux (mul acc acc) (div n 2l)) + in + match b with + | 0l -> if equal a 0l then raise (Invalid_argument "pow: undefined value 0^0") else 1l + | b when compare b 0l < 0 -> raise (Invalid_argument "pow: can't raise int to negative power") + | b -> aux a b + +(*$T + pow 2l 10l = 1024l + pow 2l 15l = 32768l + pow 10l 5l = 100000l + pow 42l 0l = 1l + pow 0l 1l = 0l +*) + +let floor_div a n = + if compare a 0l < 0 && compare n 0l >= 0 then + sub (div (add a 1l) n) 1l + else if compare a 0l > 0 && compare n 0l < 0 then + sub (div (sub a 1l) n) 1l + else + div a n + +(*$T + (floor_div 3l 5l = 0l) + (floor_div 5l 5l = 1l) + (floor_div 20l 5l = 4l) + (floor_div 12l 5l = 2l) + (floor_div 0l 5l = 0l) + (floor_div (-1l) 5l = -1l) + (floor_div (-5l) 5l = -1l) + (floor_div (-12l) 5l = -3l) + + (floor_div 0l (-5l) = 0l) + (floor_div 3l (-5l) = -1l) + (floor_div 5l (-5l) = -1l) + (floor_div 9l (-5l) = -2l) + (floor_div 20l (-5l) = -4l) + (floor_div (-2l) (-5l) = 0l) + (floor_div (-8l) (-5l) = 1l) + (floor_div (-35l) (-5l) = 7l) + + try ignore (floor_div 12l 0l); false with Division_by_zero -> true + try ignore (floor_div (-12l) 0l); false with Division_by_zero -> true +*) + +(*$Q + (Q.pair (Q.map of_int Q.small_signed_int) (Q.map of_int Q.small_nat)) \ + (fun (n, m) -> let m = m + 1l in \ + floor_div n m = of_float @@ floor (to_float n /. to_float m)) + (Q.pair (Q.map of_int Q.small_signed_int) (Q.map of_int Q.small_nat)) \ + (fun (n, m) -> let m = m + 1l in \ + floor_div n (-m) = of_float @@ floor (to_float n /. to_float (-m))) +*) + +type 'a printer = Format.formatter -> 'a -> unit +type 'a random_gen = Random.State.t -> 'a +type 'a iter = ('a -> unit) -> unit + +let range i j yield = + let rec up i j yield = + if equal i j then yield i + else ( + yield i; + up (add i 1l) j yield + ) + and down i j yield = + if equal i j then yield i + else ( + yield i; + down (sub i 1l) j yield + ) + in + if compare i j <= 0 then up i j yield else down i j yield + +(*$= & ~printer:Q.Print.(list to_string) + [0l;1l;2l;3l;4l;5l] (range 0l 5l |> Iter.to_list) + [0l] (range 0l 0l |> Iter.to_list) + [5l;4l;3l;2l] (range 5l 2l |> Iter.to_list) +*) + +let range' i j yield = + if compare i j < 0 then range i (sub j 1l) yield + else if equal i j then () + else range i (add j 1l) yield + +let range_by ~step i j yield = + let rec range i j yield = + if equal i j then yield i + else ( + yield i; + range (add i step) j yield + ) + in + if equal step 0l then + raise (Invalid_argument "CCInt32.range_by") + else if (if compare step 0l > 0 then compare i j > 0 else compare i j < 0) then () + else range i (add (mul (div (sub j i) step) step) i) yield + +(* note: the last test checks that no error occurs due to overflows. *) +(*$= & ~printer:Q.Print.(list to_string) + [0l] (range_by ~step:1l 0l 0l |> Iter.to_list) + [] (range_by ~step:1l 5l 0l |> Iter.to_list) + [] (range_by ~step:2l 1l 0l |> Iter.to_list) + [0l;2l;4l] (range_by ~step:2l 0l 4l |> Iter.to_list) + [0l;2l;4l] (range_by ~step:2l 0l 5l |> Iter.to_list) + [0l] (range_by ~step:(neg 1l) 0l 0l |> Iter.to_list) + [] (range_by ~step:(neg 1l) 0l 5l |> Iter.to_list) + [] (range_by ~step:(neg 2l) 0l 1l |> Iter.to_list) + [5l;3l;1l] (range_by ~step:(neg 2l) 5l 1l |> Iter.to_list) + [5l;3l;1l] (range_by ~step:(neg 2l) 5l 0l |> Iter.to_list) + [0l] (range_by ~step:max_int 0l 2l |> Iter.to_list) +*) + +(*$Q + Q.(pair (map of_int small_int) (map of_int small_int)) (fun (i,j) -> \ + let i = min i j and j = max i j in \ + CCList.equal CCInt32.equal \ + (CCInt32.range_by ~step:1l i j |> Iter.to_list) \ + (CCInt32.range i j |> Iter.to_list) ) +*) + +let random n st = Random.State.int32 st n +let random_small = random 100l +let random_range i j st = add i (random (sub j i) st) + + +(** {2 Conversion} *) + +let of_string_exn = of_string + +let of_string x = try Some (of_string_exn x) with Failure _ -> None +let of_string_opt = of_string + +let most_significant_bit = + logxor (neg 1l) (shift_right_logical (neg 1l) 1) + +type output = char -> unit + +(* abstract printer *) +let to_binary_gen (out:output) n = + let n = if compare n 0l <0 then (out '-'; neg n) else n in + out '0'; out 'b'; + let rec loop started bit n = + if equal bit 0l then ( + if not started then out '0' + ) else ( + let b = logand n bit in + if equal b 0l then ( + if started then out '0'; + loop started (shift_right_logical bit 1) n + ) else ( + out '1'; + loop true (shift_right_logical bit 1) n + ) + ) + in + loop false most_significant_bit n + +let to_string_binary n = + let buf = Buffer.create 16 in + to_binary_gen (Buffer.add_char buf) n; + Buffer.contents buf + +(*$= & ~printer:CCFun.id + "0b111" (to_string_binary 7l) + "-0b111" (to_string_binary (-7l)) + "0b0" (to_string_binary 0l) +*) + +(** {2 Printing} *) + +let pp out n = Format.pp_print_string out (to_string n) + +let pp_binary out n = + to_binary_gen (Format.pp_print_char out) n + + +(** {2 Infix Operators} *) + module Infix = struct let (+) = add @@ -14,6 +208,12 @@ module Infix = struct let (/) = div + let ( ** ) = pow + + let (--) = range + + let (--^) = range' + let (mod) = rem let (land) = logand @@ -39,12 +239,3 @@ module Infix = struct let (>=) = Stdlib.(>=) end include Infix - -let hash x = Stdlib.abs (to_int x) - -(** {2 Conversion} *) - -let of_string_exn = of_string - -let of_string x = try Some (of_string_exn x) with Failure _ -> None -let of_string_opt = of_string diff --git a/src/core/CCInt32.mli b/src/core/CCInt32.mli index 3af4e1ec..6cf7e6c0 100644 --- a/src/core/CCInt32.mli +++ b/src/core/CCInt32.mli @@ -17,116 +17,69 @@ include module type of struct include Int32 end -val ( + ) : t -> t -> t -(** [x + y] is the sum of [x] and [y]. - Addition. *) +val min : t -> t -> t +(** [min x y] returns the minimum of the two integers [x] and [y]. + @since NEXT_RELEASE *) -val ( - ) : t -> t -> t -(** [x - y] is the difference of [x] and [y]. - Subtraction. *) - -val ( ~- ) : t -> t -(** [~- x] is the negation of [x]. - Unary negation. *) - -val ( * ) : t -> t -> t -(** [ x * y] is the product of [x] and [y]. - Multiplication. *) - -val ( / ) : t -> t -> t -(** [x / y] is the integer quotient of [x] and [y]. - Integer division. Raise [Division_by_zero] if the second - argument [y] is zero. This division rounds the real quotient of - its arguments towards zero, as specified for {!Stdlib.(/)}. *) - -val ( mod ) : t -> t -> t -(** [x mod y] is the integer remainder of [x / y]. - If [y <> zero], the result of [x mod y] satisfies the following property: - [x = ((x / y) * y) + (x mod y)]. - If [y = 0], [x mod y] raises [Division_by_zero]. *) - -val ( land ) : t -> t -> t -(** [x land y] is the bitwise logical and of [x] and [y]. *) - -val ( lor ) : t -> t -> t -(** [x lor y] is the bitwise logical or of [x] and [y]. *) - -val ( lxor ) : t -> t -> t -(** [x lxor y] is the bitwise logical exclusive or of [x] and [y]. *) - -val lnot : t -> t -(** [lnot x] is the bitwise logical negation of [x] (the bits of [x] are inverted). *) - -val ( lsl ) : t -> int -> t -(** [ x lsl y] shifts [x] to the left by [y] bits, filling in with zeroes. - The result is unspecified if [y < 0] or [y >= 32]. *) - -val ( lsr ) : t -> int -> t -(** [x lsr y] shifts [x] to the right by [y] bits. - This is a logical shift: zeroes are inserted in the vacated bits - regardless of the sign of [x]. - The result is unspecified if [y < 0] or [y >= 32]. *) - -val ( asr ) : t -> int -> t -(** [x asr y] shifts [x] to the right by [y] bits. - This is an arithmetic shift: the sign bit of [x] is replicated - and inserted in the vacated bits. - The result is unspecified if [y < 0] or [y >= 32]. *) - -module Infix : sig - val (+) : t -> t -> t - val (-) : t -> t -> t - val (~-) : t -> t - val ( * ) : t -> t -> t - val (/) : t -> t -> t - val (mod) : t -> t -> t - val (land) : t -> t -> t - val (lor) : t -> t -> t - val (lxor) : t -> t -> t - val lnot : t -> t - val (lsl) : t -> int -> t - val (lsr) : t -> int -> t - val (asr) : t -> int -> t - val (=) : t -> t -> bool - val (<>) : t -> t -> bool - val (>) : t -> t -> bool - val (>=) : t -> t -> bool - val (<=) : t -> t -> bool - val (<) : t -> t -> bool -end - -include module type of Infix +val max : t -> t -> t +(** [max x y] returns the maximum of the two integers [x] and [y]. + @since NEXT_RELEASE *) val hash : t -> int (** [hash x] computes the hash of [x]. Like {!Stdlib.abs (to_int x)}. *) +val sign : t -> int +(** [sign x] return [0] if [x = 0], [-1] if [x < 0] and [1] if [x > 0]. + Same as [compare x zero]. + @since NEXT_RELEASE*) + +val pow : t -> t -> t +(** [pow base exponent] returns [base] raised to the power of [exponent]. + [pow x y = x^y] for positive integers [x] and [y]. + Raises [Invalid_argument] if [x = y = 0] or [y] < 0. + @since 0.11 *) + +val floor_div : t -> t -> t +(** [floor_div x n] is integer division rounding towards negative infinity. + It satisfies [x = m * floor_div x n + rem x n]. + @since NEXT_RELEASE *) + +type 'a printer = Format.formatter -> 'a -> unit +type 'a random_gen = Random.State.t -> 'a +type 'a iter = ('a -> unit) -> unit + + +val range_by : step:t -> t -> t -> t iter +(** [range_by ~step i j] iterates on integers from [i] to [j] included, + where the difference between successive elements is [step]. + Use a negative [step] for a decreasing list. + @raise Invalid_argument if [step=0]. + @since NEXT_RELEASE *) + +val range : t -> t -> t iter +(** [range i j] iterates on integers from [i] to [j] included . It works + both for decreasing and increasing ranges. + @since NEXT_RELEASE *) + +val range' : t -> t -> t iter +(** [range' i j] is like {!range} but the second bound [j] is excluded. + For instance [range' 0 5 = Iter.of_list [0;1;2;3;4]]. + @since NEXT_RELEASE *) + +val random : t -> t random_gen +val random_small : t random_gen +val random_range : t -> t -> t random_gen + + (** {2 Conversion} *) -val to_int : t -> int -(** [to_int x] converts the given 32-bit integer [x] (type [int32]) into an - integer (type [int]). On 32-bit platforms, the 32-bit integer - is taken modulo 2{^31}, i.e. the high-order bit is lost - during the conversion. On 64-bit platforms, the conversion is exact. *) +val of_string : string -> t option +(** [of_string s] is the safe version of {!of_string_exn}. + Like {!of_string_exn}, but return [None] instead of raising. *) -val of_int : int -> t -(** [of_int x] converts the given integer [x] (type [int]) into an - 32-bit integer (type [int32]). - Alias to {!Int32.of_int}. *) - -val to_float : t -> float -(** [to_float x] converts the given 32-bit integer [x] - into a floating-point number (type [float]). *) - -val of_float : float -> t -(** [of_float x] converts the given floating-point number [x] into a 32-bit integer, - discarding the fractional part (truncate towards 0). - The result of the conversion is undefined if, after truncation, the number - is outside the range \[{!CCInt32.min_int}, {!CCInt32.max_int}\]. - Alias to {!Int32.of_float}. *) - -val to_string : t -> string -(** [to_string x] returns the string representation of its argument [x], in signed decimal. *) +val of_string_opt : string -> t option +(** [of_string_opt s] is an alias to {!of_string}. *) val of_string_exn : string -> t (** [of_string_exn s] converts the given string [s] into a 32-bit integer. @@ -146,9 +99,101 @@ val of_string_exn : string -> t a valid representation of an integer, or if the integer represented exceeds the range of integers representable in type [int32]. *) -val of_string : string -> t option -(** [of_string s] is the safe version of {!of_string_exn}. - Like {!of_string_exn}, but return [None] instead of raising. *) +val to_string_binary : t -> string +(** [to_string_binary x] returns the string representation of the integer [x], in binary. + @since NEXT_RELEASE *) -val of_string_opt : string -> t option -(** [of_string_opt s] is an alias to {!of_string}. *) + +(** {2 Printing} *) + +val pp : t printer +(** [pp ppf x] prints the integer [x] on [ppf]. + @since NEXT_RELEASE *) + +val pp_binary : t printer +(** [pp_binary ppf x] prints [x] on [ppf]. + Print as "0b00101010". + @since NEXT_RELEASE *) + + +(** {2 Infix Operators} *) + +module Infix : sig + val ( + ) : t -> t -> t + (** [x + y] is the sum of [x] and [y]. + Addition. *) + + val ( - ) : t -> t -> t + (** [x - y] is the difference of [x] and [y]. + Subtraction. *) + + val ( ~- ) : t -> t + (** [~- x] is the negation of [x]. + Unary negation. *) + + val ( * ) : t -> t -> t + (** [ x * y] is the product of [x] and [y]. + Multiplication. *) + + val ( / ) : t -> t -> t + (** [x / y] is the integer quotient of [x] and [y]. + Integer division. Raise [Division_by_zero] if the second + argument [y] is zero. This division rounds the real quotient of + its arguments towards zero, as specified for {!Stdlib.(/)}. *) + + val ( mod ) : t -> t -> t + (** [x mod y] is the integer remainder of [x / y]. + If [y <> zero], the result of [x mod y] satisfies the following properties: + [zero <= x mod y < abs y] and + [x = ((x / y) * y) + (x mod y)]. + If [y = 0], [x mod y] raises [Division_by_zero]. *) + + val ( ** ) : t -> t -> t + (** Alias to {!pow} + @since NEXT_RELEASE *) + + val (--) : t -> t -> t iter + (** Alias to {!range}. + @since NEXT_RELEASE *) + + val (--^) : t -> t -> t iter + (** Alias to {!range'}. + @since NEXT_RELEASE *) + + val ( land ) : t -> t -> t + (** [x land y] is the bitwise logical and of [x] and [y]. *) + + val ( lor ) : t -> t -> t + (** [x lor y] is the bitwise logical or of [x] and [y]. *) + + val ( lxor ) : t -> t -> t + (** [x lxor y] is the bitwise logical exclusive or of [x] and [y]. *) + + val lnot : t -> t + (** [lnot x] is the bitwise logical negation of [x] (the bits of [x] are inverted). *) + + val ( lsl ) : t -> int -> t + (** [ x lsl y] shifts [x] to the left by [y] bits, filling in with zeroes. + The result is unspecified if [y < 0] or [y >= 32]. *) + + val ( lsr ) : t -> int -> t + (** [x lsr y] shifts [x] to the right by [y] bits. + This is a logical shift: zeroes are inserted in the vacated bits + regardless of the sign of [x]. + The result is unspecified if [y < 0] or [y >= 32]. *) + + val ( asr ) : t -> int -> t + (** [x asr y] shifts [x] to the right by [y] bits. + This is an arithmetic shift: the sign bit of [x] is replicated + and inserted in the vacated bits. + The result is unspecified if [y < 0] or [y >= 32]. *) + + val (=) : t -> t -> bool + val (<>) : t -> t -> bool + val (>) : t -> t -> bool + val (>=) : t -> t -> bool + val (<=) : t -> t -> bool + val (<) : t -> t -> bool +end + +include module type of Infix diff --git a/src/core/CCInt64.ml b/src/core/CCInt64.ml index 1a769c94..ab290798 100644 --- a/src/core/CCInt64.ml +++ b/src/core/CCInt64.ml @@ -3,6 +3,200 @@ open CCShims_ include Int64 + +let min : t -> t -> t = Stdlib.min +let max : t -> t -> t = Stdlib.max + +let hash x = Stdlib.abs (to_int x) + +let sign i = compare i zero + +let pow a b = + let rec aux acc = function + | 1L -> acc + | n -> + if equal (rem n 2L) zero + then aux (mul acc acc) (div n 2L) + else mul acc (aux (mul acc acc) (div n 2L)) + in + match b with + | 0L -> if equal a 0L then raise (Invalid_argument "pow: undefined value 0^0") else 1L + | b when compare b 0L < 0 -> raise (Invalid_argument "pow: can't raise int to negative power") + | b -> aux a b + +(*$T + pow 2L 10L = 1024L + pow 2L 15L = 32768L + pow 10L 5L = 100000L + pow 42L 0L = 1L + pow 0L 1L = 0L +*) + +let floor_div a n = + if compare a 0L < 0 && compare n 0L >= 0 then + sub (div (add a 1L) n) 1L + else if compare a 0L > 0 && compare n 0L < 0 then + sub (div (sub a 1L) n) 1L + else + div a n + +(*$T + (floor_div 3L 5L = 0L) + (floor_div 5L 5L = 1L) + (floor_div 20L 5L = 4L) + (floor_div 12L 5L = 2L) + (floor_div 0L 5L = 0L) + (floor_div (-1L) 5L = -1L) + (floor_div (-5L) 5L = -1L) + (floor_div (-12L) 5L = -3L) + + (floor_div 0L (-5L) = 0L) + (floor_div 3L (-5L) = -1L) + (floor_div 5L (-5L) = -1L) + (floor_div 9L (-5L) = -2L) + (floor_div 20L (-5L) = -4L) + (floor_div (-2L) (-5L) = 0L) + (floor_div (-8L) (-5L) = 1L) + (floor_div (-35L) (-5L) = 7L) + + try ignore (floor_div 12L 0L); false with Division_by_zero -> true + try ignore (floor_div (-12L) 0L); false with Division_by_zero -> true +*) + +(*$Q + (Q.pair (Q.map of_int Q.small_signed_int) (Q.map of_int Q.small_nat)) \ + (fun (n, m) -> let m = m + 1L in \ + floor_div n m = of_float @@ floor (to_float n /. to_float m)) + (Q.pair (Q.map of_int Q.small_signed_int) (Q.map of_int Q.small_nat)) \ + (fun (n, m) -> let m = m + 1L in \ + floor_div n (-m) = of_float @@ floor (to_float n /. to_float (-m))) +*) + +type 'a printer = Format.formatter -> 'a -> unit +type 'a random_gen = Random.State.t -> 'a +type 'a iter = ('a -> unit) -> unit + +let range i j yield = + let rec up i j yield = + if equal i j then yield i + else ( + yield i; + up (add i 1L) j yield + ) + and down i j yield = + if equal i j then yield i + else ( + yield i; + down (sub i 1L) j yield + ) + in + if compare i j <= 0 then up i j yield else down i j yield + +(*$= & ~printer:Q.Print.(list to_string) + [0L;1L;2L;3L;4L;5L] (range 0L 5L |> Iter.to_list) + [0L] (range 0L 0L |> Iter.to_list) + [5L;4L;3L;2L] (range 5L 2L |> Iter.to_list) +*) + +let range' i j yield = + if compare i j < 0 then range i (sub j 1L) yield + else if equal i j then () + else range i (add j 1L) yield + +let range_by ~step i j yield = + let rec range i j yield = + if equal i j then yield i + else ( + yield i; + range (add i step) j yield + ) + in + if equal step 0L then + raise (Invalid_argument "CCInt64.range_by") + else if (if compare step 0L > 0 then compare i j > 0 else compare i j < 0) then () + else range i (add (mul (div (sub j i) step) step) i) yield + +(* note: the last test checks that no error occurs due to overflows. *) +(*$= & ~printer:Q.Print.(list to_string) + [0L] (range_by ~step:1L 0L 0L |> Iter.to_list) + [] (range_by ~step:1L 5L 0L |> Iter.to_list) + [] (range_by ~step:2L 1L 0L |> Iter.to_list) + [0L;2L;4L] (range_by ~step:2L 0L 4L |> Iter.to_list) + [0L;2L;4L] (range_by ~step:2L 0L 5L |> Iter.to_list) + [0L] (range_by ~step:(neg 1L) 0L 0L |> Iter.to_list) + [] (range_by ~step:(neg 1L) 0L 5L |> Iter.to_list) + [] (range_by ~step:(neg 2L) 0L 1L |> Iter.to_list) + [5L;3L;1L] (range_by ~step:(neg 2L) 5L 1L |> Iter.to_list) + [5L;3L;1L] (range_by ~step:(neg 2L) 5L 0L |> Iter.to_list) + [0L] (range_by ~step:max_int 0L 2L |> Iter.to_list) +*) + +(*$Q + Q.(pair (map of_int small_int) (map of_int small_int)) (fun (i,j) -> \ + let i = min i j and j = max i j in \ + CCList.equal CCInt64.equal \ + (CCInt64.range_by ~step:1L i j |> Iter.to_list) \ + (CCInt64.range i j |> Iter.to_list) ) +*) + +let random n st = Random.State.int64 st n +let random_small = random 100L +let random_range i j st = add i (random (sub j i) st) + + +(** {2 Conversion} *) + +let of_string_exn = of_string + +let of_string x = try Some (of_string_exn x) with Failure _ -> None +let of_string_opt = of_string + +let most_significant_bit = + logxor (neg 1L) (shift_right_logical (neg 1L) 1) + +type output = char -> unit + +(* abstract printer *) +let to_binary_gen (out:output) n = + let n = if compare n 0L <0 then (out '-'; neg n) else n in + out '0'; out 'b'; + let rec loop started bit n = + if equal bit 0L then ( + if not started then out '0' + ) else ( + let b = logand n bit in + if equal b 0L then ( + if started then out '0'; + loop started (shift_right_logical bit 1) n + ) else ( + out '1'; + loop true (shift_right_logical bit 1) n + ) + ) + in + loop false most_significant_bit n + +let to_string_binary n = + let buf = Buffer.create 16 in + to_binary_gen (Buffer.add_char buf) n; + Buffer.contents buf + +(*$= & ~printer:CCFun.id + "0b111" (to_string_binary 7L) + "-0b111" (to_string_binary (-7L)) + "0b0" (to_string_binary 0L) +*) + +(** {2 Printing} *) + +let pp out n = Format.pp_print_string out (to_string n) + +let pp_binary out n = + to_binary_gen (Format.pp_print_char out) n + + +(** {2 Infix Operators} *) + module Infix = struct let (+) = add @@ -14,6 +208,12 @@ module Infix = struct let (/) = div + let ( ** ) = pow + + let (--) = range + + let (--^) = range' + let (mod) = rem let (land) = logand @@ -38,14 +238,4 @@ module Infix = struct let (>) = Stdlib.(>) let (>=) = Stdlib.(>=) end - include Infix - -let hash x = Stdlib.abs (to_int x) - -(** {2 Conversion} *) - -let of_string_exn = of_string - -let of_string x = try Some (of_string_exn x) with Failure _ -> None -let of_string_opt = of_string diff --git a/src/core/CCInt64.mli b/src/core/CCInt64.mli index 7373ef00..a7c4307c 100644 --- a/src/core/CCInt64.mli +++ b/src/core/CCInt64.mli @@ -2,169 +2,81 @@ (** {1 Int64} - Helpers for 64-bit integers + Helpers for 64-bit integers. + + This module provides operations on the type int64 of signed 64-bit integers. + Unlike the built-in int type, the type int64 is guaranteed to be exactly + 64-bit wide on all platforms. All arithmetic operations over int64 are taken + modulo 2{^64}. + + Performance notice: values of type int64 occupy more memory space than values + of type int, and arithmetic operations on int64 are generally slower than + those on int. Use int64 only when the application requires exact 64-bit arithmetic. @since 0.13 *) include module type of struct include Int64 end -val ( + ) : t -> t -> t -(** [x + y] is the sum of [x] and [y]. - Addition. *) +val min : t -> t -> t +(** [min x y] returns the minimum of the two integers [x] and [y]. + @since NEXT_RELEASE *) -val ( - ) : t -> t -> t -(** [x - y] is the difference of [x] and [y]. - Subtraction. *) - -val ( ~- ) : t -> t -(** [~- x] is the negation of [x]. - Unary negation. *) - -val ( * ) : t -> t -> t -(** [ x * y] is the product of [x] and [y]. - Multiplication. *) - -val ( / ) : t -> t -> t -(** [x / y] is the integer quotient of [x] and [y]. - Integer division. Raise [Division_by_zero] if the second - argument [y] is zero. This division rounds the real quotient of - its arguments towards zero, as specified for {!Stdlib.(/)}. *) - -val ( mod ) : t -> t -> t -(** [x mod y] is the integer remainder of [x / y]. - If [y <> zero], the result of [x mod y] satisfies the following property: - [x = ((x / y) * y) + (x mod y)]. - If [y = 0], [x mod y] raises [Division_by_zero]. *) - -val abs : t -> t -(** [abs x] returns the absolute value (or magnitude) of its argument [x]. *) - -val max_int : t -(** [max_int] is the greatest representable 64-bit integer, 2{^63} - 1 = [9_223_372_036_854_775_807]. *) - -val min_int : t -(** [min_int] is the smallest representable 64-bit integer, -2{^63} = [-9_223_372_036_854_775_808]. *) - -val ( land ) : t -> t -> t -(** [x land y] is the bitwise logical and of [x] and [y]. *) - -val ( lor ) : t -> t -> t -(** [x lor y] is the bitwise logical or of [x] and [y]. *) - -val ( lxor ) : t -> t -> t -(** [x lxor y] is the bitwise logical exclusive or of [x] and [y]. *) - -val lnot : t -> t -(** [lnot x] is the bitwise logical negation of [x] (the bits of [x] are inverted). *) - -val ( lsl ) : t -> int -> t -(** [ x lsl y] shifts [x] to the left by [y] bits, filling in with zeroes. - The result is unspecified if [y < 0] or [y >= 64]. *) - -val ( lsr ) : t -> int -> t -(** [x lsr y] shifts [x] to the right by [y] bits. - This is a logical shift: zeroes are inserted in the vacated bits - regardless of the sign of [x]. - The result is unspecified if [y < 0] or [y >= 64]. *) - -val ( asr ) : t -> int -> t -(** [x asr y] shifts [x] to the right by [y] bits. - This is an arithmetic shift: the sign bit of [x] is replicated - and inserted in the vacated bits. - The result is unspecified if [y < 0] or [y >= 64]. *) - -(** Infix operators - @since 2.1 *) -module Infix : sig - val (+) : t -> t -> t - val (-) : t -> t -> t - val (~-) : t -> t - val ( * ) : t -> t -> t - val (/) : t -> t -> t - val (mod) : t -> t -> t - val (land) : t -> t -> t - val (lor) : t -> t -> t - val (lxor) : t -> t -> t - val lnot : t -> t - val (lsl) : t -> int -> t - val (lsr) : t -> int -> t - val (asr) : t -> int -> t - val (=) : t -> t -> bool - val (<>) : t -> t -> bool - val (>) : t -> t -> bool - val (>=) : t -> t -> bool - val (<=) : t -> t -> bool - val (<) : t -> t -> bool -end - -include module type of Infix - -val compare : t -> t -> int -(** [compare x y] is the comparison function for 64-bit integers, with the same specification as - {!Stdlib.compare}. Along with the type [t], this function [compare] - allows the module [CCInt64] to be passed as argument to the functors - {!Set.Make} and {!Map.Make}. *) +val max : t -> t -> t +(** [max x y] returns the maximum of the two integers [x] and [y]. + @since NEXT_RELEASE *) val hash : t -> int (** [hash x] computes the hash of [x]. Like {!Stdlib.abs (to_int x)}. *) - + +val sign : t -> int +(** [sign x] return [0] if [x = 0], [-1] if [x < 0] and [1] if [x > 0]. + Same as [compare x zero]. + @since NEXT_RELEASE*) + +val pow : t -> t -> t +(** [pow base exponent] returns [base] raised to the power of [exponent]. + [pow x y = x^y] for positive integers [x] and [y]. + Raises [Invalid_argument] if [x = y = 0] or [y] < 0. + @since 0.11 *) + +val floor_div : t -> t -> t +(** [floor_div x n] is integer division rounding towards negative infinity. + It satisfies [x = m * floor_div x n + rem x n]. + @since NEXT_RELEASE *) + +type 'a printer = Format.formatter -> 'a -> unit +type 'a random_gen = Random.State.t -> 'a +type 'a iter = ('a -> unit) -> unit + + +val range_by : step:t -> t -> t -> t iter +(** [range_by ~step i j] iterates on integers from [i] to [j] included, + where the difference between successive elements is [step]. + Use a negative [step] for a decreasing list. + @raise Invalid_argument if [step=0]. + @since NEXT_RELEASE *) + +val range : t -> t -> t iter +(** [range i j] iterates on integers from [i] to [j] included . It works + both for decreasing and increasing ranges. + @since NEXT_RELEASE *) + +val range' : t -> t -> t iter +(** [range' i j] is like {!range} but the second bound [j] is excluded. + For instance [range' 0 5 = Iter.of_list [0;1;2;3;4]]. + @since NEXT_RELEASE *) + +val random : t -> t random_gen +val random_small : t random_gen +val random_range : t -> t -> t random_gen + + (** {2 Conversion} *) -val to_int : t -> int -(** [to_int x] converts the given 64-bit integer [x] (type [int64]) into an - integer (type [int]). On 64-bit platforms, the 64-bit integer - is taken modulo 2{^63}, i.e. the high-order bit is lost - during the conversion. On 32-bit platforms, the 64-bit integer - is taken modulo 2{^31}, i.e. the top 33 bits are lost - during the conversion. *) - -val of_int : int -> t -(** [of_int x] converts the given integer [x] (type [int]) into an - 64-bit integer (type [int64]). - Alias to {!Int64.of_int}. - NOTE: used to return an option, but the function actually never fails. *) - -val to_int32 : t -> int32 -(** [to_int32 x] converts the given 64-bit integer [x] (type [int64]) to a - 32-bit integer (type [int32]). The 64-bit integer - is taken modulo 2{^32}, i.e. the top 32 bits are lost - during the conversion. *) - -val of_int32 : int32 -> t -(** [of_int32 x] converts the given 32-bit integer [x] (type [int32]) into an - 64-bit integer (type [int64]). - Alias to {!Int64.of_int32}. - NOTE: use to return an option, but the function actually never fails. *) - -val to_nativeint : t -> nativeint -(** [to_nativeint x] converts the given 64-bit integer [x] (type [int64]) into a - native integer. On 32-bit platforms, the 64-bit integer - is taken modulo 2{^32}. On 64-bit platforms, - the conversion is exact. *) - -val of_nativeint : nativeint -> t -(** [of_nativeint x] converts the given nativeint integer [x] (type [nativeint]) into an - 64-bit integer (type [int64]). - Alias to {!Int64.of_nativeint}. - NOTE: use to return an option, but the function actually never fails. *) - -val to_float : t -> float -(** [to_float x] converts the given 64-bit integer [x] into a floating-point number. *) - -val of_float : float -> t -(** [of_float x] converts the given floating-point number [x] into a 64-bit integer, - discarding the fractional part (truncate towards 0). - The result of the conversion is undefined if, after truncation, - the number is outside the range \[{!CCInt64.min_int}, {!CCInt64.max_int}\]. - Alias to {!Int64.of_float}. - NOTE: used to return an option, but the function never fails. *) - -val to_string : t -> string -(** [to_string x] returns the string representation of its argument [x], in decimal. *) - val of_string : string -> t option -(** [of_string s] is the safe version of {!of_string_exn}. *) +(** [of_string s] is the safe version of {!of_string_exn}. + Like {!of_string_exn}, but return [None] instead of raising. *) val of_string_opt : string -> t option (** [of_string_opt s] is an alias to {!of_string}. @@ -187,3 +99,104 @@ val of_string_exn : string -> t Raise [Failure "Int64.of_string"] if the given string is not a valid representation of an integer, or if the integer represented exceeds the range of integers representable in type [int64]. *) + +val to_string_binary : t -> string +(** [to_string_binary x] returns the string representation of the integer [x], in binary. + @since NEXT_RELEASE *) + + +(** {2 Printing} *) + +val pp : t printer +(** [pp ppf x] prints the integer [x] on [ppf]. + @since NEXT_RELEASE *) + +val pp_binary : t printer +(** [pp_binary ppf x] prints [x] on [ppf]. + Print as "0b00101010". + @since NEXT_RELEASE *) + + +(** {2 Infix Operators} *) +(** Infix operators + @since 2.1 *) + +module Infix : sig + val ( + ) : t -> t -> t + (** [x + y] is the sum of [x] and [y]. + Addition. *) + + val ( - ) : t -> t -> t + (** [x - y] is the difference of [x] and [y]. + Subtraction. *) + + val ( ~- ) : t -> t + (** [~- x] is the negation of [x]. + Unary negation. *) + + val ( * ) : t -> t -> t + (** [ x * y] is the product of [x] and [y]. + Multiplication. *) + + val ( / ) : t -> t -> t + (** [x / y] is the integer quotient of [x] and [y]. + Integer division. Raise [Division_by_zero] if the second + argument [y] is zero. This division rounds the real quotient of + its arguments towards zero, as specified for {!Stdlib.(/)}. *) + + val ( mod ) : t -> t -> t + (** [x mod y] is the integer remainder of [x / y]. + If [y <> zero], the result of [x mod y] satisfies the following properties: + [zero <= x mod y < abs y] and + [x = ((x / y) * y) + (x mod y)]. + If [y = 0], [x mod y] raises [Division_by_zero]. *) + + val ( ** ) : t -> t -> t + (** Alias to {!pow} + @since NEXT_RELEASE *) + + val (--) : t -> t -> t iter + (** Alias to {!range}. + @since NEXT_RELEASE *) + + val (--^) : t -> t -> t iter + (** Alias to {!range'}. + @since NEXT_RELEASE *) + + val ( land ) : t -> t -> t + (** [x land y] is the bitwise logical and of [x] and [y]. *) + + val ( lor ) : t -> t -> t + (** [x lor y] is the bitwise logical or of [x] and [y]. *) + + val ( lxor ) : t -> t -> t + (** [x lxor y] is the bitwise logical exclusive or of [x] and [y]. *) + + val lnot : t -> t + (** [lnot x] is the bitwise logical negation of [x] (the bits of [x] are inverted). *) + + val ( lsl ) : t -> int -> t + (** [ x lsl y] shifts [x] to the left by [y] bits, filling in with zeroes. + The result is unspecified if [y < 0] or [y >= 64]. *) + + val ( lsr ) : t -> int -> t + (** [x lsr y] shifts [x] to the right by [y] bits. + This is a logical shift: zeroes are inserted in the vacated bits + regardless of the sign of [x]. + The result is unspecified if [y < 0] or [y >= 64]. *) + + val ( asr ) : t -> int -> t + (** [x asr y] shifts [x] to the right by [y] bits. + This is an arithmetic shift: the sign bit of [x] is replicated + and inserted in the vacated bits. + The result is unspecified if [y < 0] or [y >= 64]. *) + + val (=) : t -> t -> bool + val (<>) : t -> t -> bool + val (>) : t -> t -> bool + val (>=) : t -> t -> bool + val (<=) : t -> t -> bool + val (<) : t -> t -> bool +end + +include module type of Infix diff --git a/src/core/CCNativeint.ml b/src/core/CCNativeint.ml index f13cf27d..030bb811 100644 --- a/src/core/CCNativeint.ml +++ b/src/core/CCNativeint.ml @@ -3,6 +3,200 @@ open CCShims_ include Nativeint + +let min : t -> t -> t = Stdlib.min +let max : t -> t -> t = Stdlib.max + +let hash x = Stdlib.abs (to_int x) + +let sign i = compare i zero + +let pow a b = + let rec aux acc = function + | 1n -> acc + | n -> + if equal (rem n 2n) zero + then aux (mul acc acc) (div n 2n) + else mul acc (aux (mul acc acc) (div n 2n)) + in + match b with + | 0n -> if equal a 0n then raise (Invalid_argument "pow: undefined value 0^0") else 1n + | b when compare b 0n < 0 -> raise (Invalid_argument "pow: can't raise int to negative power") + | b -> aux a b + +(*$T + pow 2n 10n = 1024n + pow 2n 15n = 32768n + pow 10n 5n = 100000n + pow 42n 0n = 1n + pow 0n 1n = 0n +*) + +let floor_div a n = + if compare a 0n < 0 && compare n 0n >= 0 then + sub (div (add a 1n) n) 1n + else if compare a 0n > 0 && compare n 0n < 0 then + sub (div (sub a 1n) n) 1n + else + div a n + +(*$T + (floor_div 3n 5n = 0n) + (floor_div 5n 5n = 1n) + (floor_div 20n 5n = 4n) + (floor_div 12n 5n = 2n) + (floor_div 0n 5n = 0n) + (floor_div (-1n) 5n = -1n) + (floor_div (-5n) 5n = -1n) + (floor_div (-12n) 5n = -3n) + + (floor_div 0n (-5n) = 0n) + (floor_div 3n (-5n) = -1n) + (floor_div 5n (-5n) = -1n) + (floor_div 9n (-5n) = -2n) + (floor_div 20n (-5n) = -4n) + (floor_div (-2n) (-5n) = 0n) + (floor_div (-8n) (-5n) = 1n) + (floor_div (-35n) (-5n) = 7n) + + try ignore (floor_div 12n 0n); false with Division_by_zero -> true + try ignore (floor_div (-12n) 0n); false with Division_by_zero -> true +*) + +(*$Q + (Q.pair (Q.map of_int Q.small_signed_int) (Q.map of_int Q.small_nat)) \ + (fun (n, m) -> let m = m + 1n in \ + floor_div n m = of_float @@ floor (to_float n /. to_float m)) + (Q.pair (Q.map of_int Q.small_signed_int) (Q.map of_int Q.small_nat)) \ + (fun (n, m) -> let m = m + 1n in \ + floor_div n (-m) = of_float @@ floor (to_float n /. to_float (-m))) +*) + +type 'a printer = Format.formatter -> 'a -> unit +type 'a random_gen = Random.State.t -> 'a +type 'a iter = ('a -> unit) -> unit + +let range i j yield = + let rec up i j yield = + if equal i j then yield i + else ( + yield i; + up (add i 1n) j yield + ) + and down i j yield = + if equal i j then yield i + else ( + yield i; + down (sub i 1n) j yield + ) + in + if compare i j <= 0 then up i j yield else down i j yield + +(*$= & ~printer:Q.Print.(list to_string) + [0n;1n;2n;3n;4n;5n] (range 0n 5n |> Iter.to_list) + [0n] (range 0n 0n |> Iter.to_list) + [5n;4n;3n;2n] (range 5n 2n |> Iter.to_list) +*) + +let range' i j yield = + if compare i j < 0 then range i (sub j 1n) yield + else if equal i j then () + else range i (add j 1n) yield + +let range_by ~step i j yield = + let rec range i j yield = + if equal i j then yield i + else ( + yield i; + range (add i step) j yield + ) + in + if equal step 0n then + raise (Invalid_argument "CCNativeint.range_by") + else if (if compare step 0n > 0 then compare i j > 0 else compare i j < 0) then () + else range i (add (mul (div (sub j i) step) step) i) yield + +(* note: the last test checks that no error occurs due to overflows. *) +(*$= & ~printer:Q.Print.(list to_string) + [0n] (range_by ~step:1n 0n 0n |> Iter.to_list) + [] (range_by ~step:1n 5n 0n |> Iter.to_list) + [] (range_by ~step:2n 1n 0n |> Iter.to_list) + [0n;2n;4n] (range_by ~step:2n 0n 4n |> Iter.to_list) + [0n;2n;4n] (range_by ~step:2n 0n 5n |> Iter.to_list) + [0n] (range_by ~step:(neg 1n) 0n 0n |> Iter.to_list) + [] (range_by ~step:(neg 1n) 0n 5n |> Iter.to_list) + [] (range_by ~step:(neg 2n) 0n 1n |> Iter.to_list) + [5n;3n;1n] (range_by ~step:(neg 2n) 5n 1n |> Iter.to_list) + [5n;3n;1n] (range_by ~step:(neg 2n) 5n 0n |> Iter.to_list) + [0n] (range_by ~step:max_int 0n 2n |> Iter.to_list) +*) + +(*$Q + Q.(pair (map of_int small_int) (map of_int small_int)) (fun (i,j) -> \ + let i = min i j and j = max i j in \ + CCList.equal CCNativeint.equal \ + (CCNativeint.range_by ~step:1n i j |> Iter.to_list) \ + (CCNativeint.range i j |> Iter.to_list) ) +*) + +let random n st = Random.State.nativeint st n +let random_small = random 100n +let random_range i j st = add i (random (sub j i) st) + + +(** {2 Conversion} *) + +let of_string_exn = of_string + +let of_string x = try Some (of_string_exn x) with Failure _ -> None +let of_string_opt = of_string + +let most_significant_bit = + logxor (neg 1n) (shift_right_logical (neg 1n) 1) + +type output = char -> unit + +(* abstract printer *) +let to_binary_gen (out:output) n = + let n = if compare n 0n <0 then (out '-'; neg n) else n in + out '0'; out 'b'; + let rec loop started bit n = + if equal bit 0n then ( + if not started then out '0' + ) else ( + let b = logand n bit in + if equal b 0n then ( + if started then out '0'; + loop started (shift_right_logical bit 1) n + ) else ( + out '1'; + loop true (shift_right_logical bit 1) n + ) + ) + in + loop false most_significant_bit n + +let to_string_binary n = + let buf = Buffer.create 16 in + to_binary_gen (Buffer.add_char buf) n; + Buffer.contents buf + +(*$= & ~printer:CCFun.id + "0b111" (to_string_binary 7n) + "-0b111" (to_string_binary (-7n)) + "0b0" (to_string_binary 0n) +*) + +(** {2 Printing} *) + +let pp out n = Format.pp_print_string out (to_string n) + +let pp_binary out n = + to_binary_gen (Format.pp_print_char out) n + + +(** {2 Infix Operators} *) + module Infix = struct let (+) = add @@ -14,6 +208,12 @@ module Infix = struct let (/) = div + let ( ** ) = pow + + let (--) = range + + let (--^) = range' + let (mod) = rem let (land) = logand @@ -39,12 +239,3 @@ module Infix = struct let (>=) = Stdlib.(>=) end include Infix - -let hash x = Stdlib.abs (to_int x) - -(** {2 Conversion} *) - -let of_string_exn = of_string - -let of_string x = try Some (of_string_exn x) with Failure _ -> None -let of_string_opt = of_string diff --git a/src/core/CCNativeint.mli b/src/core/CCNativeint.mli index f299c0d9..7929a680 100644 --- a/src/core/CCNativeint.mli +++ b/src/core/CCNativeint.mli @@ -18,110 +18,73 @@ include module type of struct include Nativeint end -val ( + ) : t -> t -> t -(** Addition. *) +val min : t -> t -> t +(** [min x y] returns the minimum of the two integers [x] and [y]. + @since NEXT_RELEASE *) -val ( - ) : t -> t -> t -(** Subtraction. *) - -val ( ~- ) : t -> t -(** Unary negation. *) - -val ( * ) : t -> t -> t -(** Multiplication. *) - -val ( / ) : t -> t -> t -(** Integer division. Raise [Division_by_zero] if the second - argument is zero. This division rounds the real quotient of - its arguments towards zero, as specified for {!Stdlib.(/)}. *) - -val ( mod ) : t -> t -> t -(** [x mod y ] is the integer remainder. - If [y <> zero], the result of [x mod y] satisfies the following properties: - [zero <= x mod y < abs y] and - [x = ((x / y) * y) + (x mod y)]. - If [y = 0], [x mod y] raises [Division_by_zero]. *) - -val ( land ) : t -> t -> t -(** Bitwise logical and. *) - -val ( lor ) : t -> t -> t -(** Bitwise logical or. *) - -val ( lxor ) : t -> t -> t -(** Bitwise logical exclusive or. *) - -val lnot : t -> t -(** Bitwise logical negation. *) - -val ( lsl ) : t -> int -> t -(** [ x lsl y] shifts [x] to the left by [y] bits. - The result is unspecified if [y < 0] or [y >= bitsize], where [bitsize] is [32] on a 32-bit platform - and [64] on a 64-bit platform. *) - -val ( lsr ) : t -> int -> t -(** [x lsr y] shifts [x] to the right by [y] bits. - This is a logical shift: zeroes are inserted in the vacated bits - regardless of the sign of [x]. - The result is unspecified if [y < 0] or [y >= bitsize]. *) - -val ( asr ) : t -> int -> t -(** [x asr y] shifts [x] to the right by [y] bits. - This is an arithmetic shift: the sign bit of [x] is replicated - and inserted in the vacated bits. - The result is unspecified if [y < 0] or [y >= bitsize]. *) - -module Infix : sig - val (+) : t -> t -> t - val (-) : t -> t -> t - val (~-) : t -> t - val ( * ) : t -> t -> t - val (/) : t -> t -> t - val (mod) : t -> t -> t - val (land) : t -> t -> t - val (lor) : t -> t -> t - val (lxor) : t -> t -> t - val lnot : t -> t - val (lsl) : t -> int -> t - val (lsr) : t -> int -> t - val (asr) : t -> int -> t - val (=) : t -> t -> bool - val (<>) : t -> t -> bool - val (>) : t -> t -> bool - val (>=) : t -> t -> bool - val (<=) : t -> t -> bool - val (<) : t -> t -> bool -end +val max : t -> t -> t +(** [max x y] returns the maximum of the two integers [x] and [y]. + @since NEXT_RELEASE *) val hash : t -> int -(** Like {!Stdlib.abs (to_int x)}. *) +(** [hash x] computes the hash of [x]. + Like {!Stdlib.abs (to_int x)}. *) + +val sign : t -> int +(** [sign x] return [0] if [x = 0], [-1] if [x < 0] and [1] if [x > 0]. + Same as [compare x zero]. + @since NEXT_RELEASE*) + +val pow : t -> t -> t +(** [pow base exponent] returns [base] raised to the power of [exponent]. + [pow x y = x^y] for positive integers [x] and [y]. + Raises [Invalid_argument] if [x = y = 0] or [y] < 0. + @since 0.11 *) + +val floor_div : t -> t -> t +(** [floor_div x n] is integer division rounding towards negative infinity. + It satisfies [x = m * floor_div x n + rem x n]. + @since NEXT_RELEASE *) + +type 'a printer = Format.formatter -> 'a -> unit +type 'a random_gen = Random.State.t -> 'a +type 'a iter = ('a -> unit) -> unit + + +val range_by : step:t -> t -> t -> t iter +(** [range_by ~step i j] iterates on integers from [i] to [j] included, + where the difference between successive elements is [step]. + Use a negative [step] for a decreasing list. + @raise Invalid_argument if [step=0]. + @since NEXT_RELEASE *) + +val range : t -> t -> t iter +(** [range i j] iterates on integers from [i] to [j] included . It works + both for decreasing and increasing ranges. + @since NEXT_RELEASE *) + +val range' : t -> t -> t iter +(** [range' i j] is like {!range} but the second bound [j] is excluded. + For instance [range' 0 5 = Iter.of_list [0;1;2;3;4]]. + @since NEXT_RELEASE *) + +val random : t -> t random_gen +val random_small : t random_gen +val random_range : t -> t -> t random_gen + (** {2 Conversion} *) -val to_int : t -> int -(** Convert the given native integer (type [nativeint]) to an - integer (type [int]). The high-order bit is lost - during the conversion. *) +val of_string : string -> t option +(** [of_string s] is the safe version of {!of_string_exn}. + Like {!of_string_exn}, but return [None] instead of raising. *) -val of_int : int -> t -(** Alias to {!Nativeint.of_int}. - Convert the given integer (type [int]) to a native integer (type [nativeint]). *) - -val to_float : t -> float -(** Convert the given native integer to a floating-point number. *) - -val of_float : float -> t -(** Alias to {!Nativeint.of_float}. - Convert the given floating-point number to a native integer, - discarding the fractional part (truncate towards 0). - The result of the conversion is undefined if, after truncation, the number - is outside the range \[{!CCNativeint.min_int}, {!CCNativeint.max_int}\]. *) - -val to_string : t -> string -(** Return the string representation of its argument, in decimal. *) +val of_string_opt : string -> t option +(** [of_string_opt s] is an alias to {!of_string}. *) val of_string_exn : string -> t -(** Alias to {!Nativeint.of_string}. +(** [of_string_exn s] converts the given string [s] into a native integer. + Alias to {!Nativeint.of_string}. Convert the given string to a native integer. The string is read in decimal (by default, or if the string begins with [0u]) or in hexadecimal, octal or binary if the @@ -136,9 +99,102 @@ val of_string_exn : string -> t a valid representation of an integer, or if the integer represented exceeds the range of integers representable in type [nativeint]. *) -val of_string : string -> t option -(** Safe version of {!of_string_exn}. - Like {!of_string_exn}, but return [None] instead of raising. *) +val to_string_binary : t -> string +(** [to_string_binary x] returns the string representation of the integer [x], in binary. + @since NEXT_RELEASE *) -val of_string_opt : string -> t option -(** Alias to {!of_string}. *) + +(** {2 Printing} *) + +val pp : t printer +(** [pp ppf x] prints the integer [x] on [ppf]. + @since NEXT_RELEASE *) + +val pp_binary : t printer +(** [pp_binary ppf x] prints [x] on [ppf]. + Print as "0b00101010". + @since NEXT_RELEASE *) + + +(** {2 Infix Operators} *) + +module Infix : sig + val ( + ) : t -> t -> t + (** [x + y] is the sum of [x] and [y]. + Addition. *) + + val ( - ) : t -> t -> t + (** [x - y] is the difference of [x] and [y]. + Subtraction. *) + + val ( ~- ) : t -> t + (** [~- x] is the negation of [x]. + Unary negation. *) + + val ( * ) : t -> t -> t + (** [ x * y] is the product of [x] and [y]. + Multiplication. *) + + val ( / ) : t -> t -> t + (** [x / y] is the integer quotient of [x] and [y]. + Integer division. Raise [Division_by_zero] if the second + argument [y] is zero. This division rounds the real quotient of + its arguments towards zero, as specified for {!Stdlib.(/)}. *) + + val ( mod ) : t -> t -> t + (** [x mod y] is the integer remainder of [x / y]. + If [y <> zero], the result of [x mod y] satisfies the following properties: + [zero <= x mod y < abs y] and + [x = ((x / y) * y) + (x mod y)]. + If [y = 0], [x mod y] raises [Division_by_zero]. *) + + val ( ** ) : t -> t -> t + (** Alias to {!pow} + @since NEXT_RELEASE *) + + val (--) : t -> t -> t iter + (** Alias to {!range}. + @since NEXT_RELEASE *) + + val (--^) : t -> t -> t iter + (** Alias to {!range'}. + @since NEXT_RELEASE *) + + val ( land ) : t -> t -> t + (** [x land y] is the bitwise logical and of [x] and [y]. *) + + val ( lor ) : t -> t -> t + (** [x lor y] is the bitwise logical or of [x] and [y]. *) + + val ( lxor ) : t -> t -> t + (** [x lxor y] is the bitwise logical exclusive or of [x] and [y]. *) + + val lnot : t -> t + (** [lnot x] is the bitwise logical negation of [x] (the bits of [x] are inverted). *) + + val ( lsl ) : t -> int -> t + (** [ x lsl y] shifts [x] to the left by [y] bits. + The result is unspecified if [y < 0] or [y >= bitsize], where [bitsize] is [32] on a 32-bit platform + and [64] on a 64-bit platform. *) + + val ( lsr ) : t -> int -> t + (** [x lsr y] shifts [x] to the right by [y] bits. + This is a logical shift: zeroes are inserted in the vacated bits + regardless of the sign of [x]. + The result is unspecified if [y < 0] or [y >= bitsize]. *) + + val ( asr ) : t -> int -> t + (** [x asr y] shifts [x] to the right by [y] bits. + This is an arithmetic shift: the sign bit of [x] is replicated + and inserted in the vacated bits. + The result is unspecified if [y < 0] or [y >= bitsize]. *) + + val (=) : t -> t -> bool + val (<>) : t -> t -> bool + val (>) : t -> t -> bool + val (>=) : t -> t -> bool + val (<=) : t -> t -> bool + val (<) : t -> t -> bool +end + +include module type of Infix diff --git a/src/core/dune b/src/core/dune index 0b99c77d..3831a985 100644 --- a/src/core/dune +++ b/src/core/dune @@ -6,7 +6,8 @@ (rule (targets CCShims_.ml CCShimsList_.ml CCShimsFun_.ml CCShimsFun_.mli - CCShimsArray_.ml CCShimsFormat_.ml CCShimsMkLet_.ml CCShimsArrayLabels_.ml) + CCShimsArray_.ml CCShimsFormat_.ml CCShimsMkLet_.ml CCShimsArrayLabels_.ml + CCShimsInt_.ml) (deps ./mkshims.exe) (action (run ./mkshims.exe))) diff --git a/src/core/mkshims.ml b/src/core/mkshims.ml index 8f018966..f0b615bd 100644 --- a/src/core/mkshims.ml +++ b/src/core/mkshims.ml @@ -150,6 +150,9 @@ let shims_let_op_post_408 = end[@@inline] " +let shims_int_pre_408 = "" +let shims_int_post_408 = "include Int" + let () = C.main ~name:"mkshims" (fun c -> let version = C.ocaml_config_var_exn c "version" in @@ -168,4 +171,5 @@ let () = write_file "CCShimsFun_.ml" (if (major, minor) >= (4,8) then shims_fun_post_408 else shims_fun_pre_408); write_file "CCShimsFun_.mli" (if (major, minor) >= (4,8) then shims_fun_mli_post_408 else shims_fun_mli_pre_408); write_file "CCShimsMkLet_.ml" (if (major, minor) >= (4,8) then shims_let_op_post_408 else shims_let_op_pre_408); + write_file "CCShimsInt_.ml" (if (major, minor) >= (4,8) then shims_int_post_408 else shims_int_pre_408); )