(*
 * BatInt64 - Extended 64-bit integers
 * Copyright (C) 2007 Bluestorm <bluestorm dot dylc on-the-server gmail dot com>
 *               2008 David Teller
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version,
 * with the special exception on linking described in file LICENSE.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 *)


module BaseInt64 = struct
  include Int64

  let modulo = rem
  let pow = BatNumber.generic_pow ~zero ~one ~div_two:(fun n -> shift_right n 1) ~mod_two:(logand one) ~mul
end

include BatNumber.MakeNumeric(BaseInt64)

let min_int = Int64.min_int
let max_int = Int64.max_int
let minus_one = Int64.minus_one
let lognot = Int64.lognot
external neg : int64 -> int64 = "%int64_neg"
external add : int64 -> int64 -> int64 = "%int64_add"
external sub : int64 -> int64 -> int64 = "%int64_sub"
external mul : int64 -> int64 -> int64 = "%int64_mul"
external div : int64 -> int64 -> int64 = "%int64_div"
external rem : int64 -> int64 -> int64 = "%int64_mod"
external logand : int64 -> int64 -> int64 = "%int64_and"
external logor : int64 -> int64 -> int64 = "%int64_or"
external logxor : int64 -> int64 -> int64 = "%int64_xor"
external shift_left : int64 -> int -> int64 = "%int64_lsl"
external shift_right : int64 -> int -> int64 = "%int64_asr"
external shift_right_logical : int64 -> int -> int64 = "%int64_lsr"
external of_int : int -> int64 = "%int64_of_int"
external to_int : int64 -> int = "%int64_to_int"
external of_float : float -> int64 = "caml_int64_of_float"
##V>=4.3## "caml_int64_of_float_unboxed" [@@unboxed] [@@noalloc]
external to_float : int64 -> float = "caml_int64_to_float"
##V>=4.3## "caml_int64_to_float_unboxed" [@@unboxed] [@@noalloc]
external of_int32 : int32 -> int64 = "%int64_of_int32"
external to_int32 : int64 -> int32 = "%int64_to_int32"
external of_nativeint : nativeint -> int64 = "%int64_of_nativeint"
external to_nativeint : int64 -> nativeint = "%int64_to_nativeint"
external of_string : string -> int64 = "caml_int64_of_string"
##V>=4.5##let of_string_opt = Int64.of_string_opt
##V<4.5##let of_string_opt n = try Some (Int64.of_string n) with _ -> None
external bits_of_float : float -> int64 = "caml_int64_bits_of_float"
##V>=4.3## "caml_int64_bits_of_float_unboxed" [@@unboxed] [@@noalloc]
external float_of_bits : int64 -> float = "caml_int64_float_of_bits"
##V>=4.3## "caml_int64_float_of_bits_unboxed" [@@unboxed] [@@noalloc]
external format : string -> int64 -> string = "caml_int64_format"

##V>=4.08##let unsigned_compare = Int64.unsigned_compare
##V>=4.08##let unsigned_to_int = Int64.unsigned_to_int
##V>=4.08##let unsigned_rem = Int64.unsigned_rem
##V>=4.08##let unsigned_div = Int64.unsigned_div

let print out t = BatInnerIO.nwrite out (to_string t)
let print_hex out t = BatPrintf.fprintf out "%Lx" t

let min (x: t) (y: t): t =
  if x <= y then x else y

let max (x: t) (y: t): t =
  if x >= y then x else y

##V>=5.1##let seeded_hash = Int64.seeded_hash
##V>=5.1##let hash = Int64.hash

##V>=5.5##let fdiv = Int64.fdiv
##V>=5.5##let cdiv = Int64.cdiv
##V>=5.5##let ediv = Int64.ediv
##V>=5.5##let erem = Int64.erem
##V>=5.5##let succ = Int64.succ
##V>=5.5##let popcount = Int64.popcount
##V>=5.5##let unsigned_bitsize = Int64.unsigned_bitsize
##V>=5.5##let signed_bitsize = Int64.signed_bitsize
##V>=5.5##let leading_zeros = Int64.leading_zeros
##V>=5.5##let leading_sign_bits = Int64.leading_sign_bits
##V>=5.5##let trailing_zeros = Int64.trailing_zeros
