-
Notifications
You must be signed in to change notification settings - Fork 21
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feat: add small signed integers #49
base: master
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,4 +1,5 @@ | ||
*~ | ||
_build | ||
_opam | ||
integers.install | ||
.merlin |
Original file line number | Diff line number | Diff line change | ||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
@@ -6,6 +6,9 @@ | |||||||||||||
* See the file LICENSE for details. | ||||||||||||||
*) | ||||||||||||||
|
||||||||||||||
external int_size' : unit -> int = "integers_int_size" | ||||||||||||||
let int_size = int_size' () | ||||||||||||||
|
||||||||||||||
module type Infix = sig | ||||||||||||||
type t | ||||||||||||||
include Unsigned.Infix with type t := t | ||||||||||||||
|
@@ -62,8 +65,93 @@ struct | |||||||||||||
let (asr) = shift_right | ||||||||||||||
end | ||||||||||||||
|
||||||||||||||
module type Small = sig | ||||||||||||||
val bits : int | ||||||||||||||
|
||||||||||||||
val min : unit -> int | ||||||||||||||
val max : unit -> int | ||||||||||||||
val of_string : string -> int | ||||||||||||||
val to_string : int -> string | ||||||||||||||
val to_hexstring : int -> string | ||||||||||||||
end | ||||||||||||||
|
||||||||||||||
module MakeSmall(S : Small) = | ||||||||||||||
struct | ||||||||||||||
open S | ||||||||||||||
|
||||||||||||||
let fix i = (i lsl (int_size - bits)) asr (int_size - bits) | ||||||||||||||
|
||||||||||||||
module Basics = | ||||||||||||||
struct | ||||||||||||||
type t = int | ||||||||||||||
external to_int : t -> int = "%identity" | ||||||||||||||
let min_int = S.min () | ||||||||||||||
let max_int = S.max () | ||||||||||||||
let of_string = of_string | ||||||||||||||
let to_string = to_string | ||||||||||||||
let to_hexstring = to_hexstring | ||||||||||||||
Comment on lines
+90
to
+92
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
(for consistency with |
||||||||||||||
|
||||||||||||||
let add : t -> t -> t = fun x y -> fix (x + y) | ||||||||||||||
let sub : t -> t -> t = fun x y -> fix (x - y) | ||||||||||||||
let mul : t -> t -> t = fun x y -> fix (x * y) | ||||||||||||||
let div : t -> t -> t = ( / ) | ||||||||||||||
let rem : t -> t -> t = ( mod ) | ||||||||||||||
let logand : t -> t -> t = ( land ) | ||||||||||||||
let logor : t -> t -> t = ( lor ) | ||||||||||||||
let logxor : t -> t -> t = ( lxor ) | ||||||||||||||
let shift_left : t -> int -> t = fun x y -> fix (x lsl y) | ||||||||||||||
let shift_right : t -> int -> t = ( asr ) | ||||||||||||||
let shift_right_logical : t -> int -> t = fun x y -> | ||||||||||||||
((x lsl (int_size - bits)) lsr y) asr (int_size - bits) | ||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is done to handle the case of preservation when the RHS is 0 -- it's a bit ugly so if there's a better way to do it I'm all ears. |
||||||||||||||
let of_int : int -> t = fix | ||||||||||||||
let of_string_opt s = try Some (of_string s) with Failure _ -> None | ||||||||||||||
let zero = 0 | ||||||||||||||
let one = 1 | ||||||||||||||
let minus_one = -1 | ||||||||||||||
let lognot = lnot | ||||||||||||||
let succ : t -> t = fun x -> fix (Stdlib.succ x) | ||||||||||||||
let pred : t -> t = fun x -> fix (Stdlib.pred x) | ||||||||||||||
let compare : t -> t -> int = Stdlib.compare | ||||||||||||||
let equal : t -> t -> bool = Stdlib.( = ) | ||||||||||||||
let min : t -> t -> t = Stdlib.min | ||||||||||||||
let max : t -> t -> t = Stdlib.max | ||||||||||||||
end | ||||||||||||||
include Basics | ||||||||||||||
module Infix = MakeInfix(Basics) | ||||||||||||||
let pp fmt x = Format.fprintf fmt "%s" (to_string x) | ||||||||||||||
let pp_hex fmt x = Format.fprintf fmt "%s" (to_hexstring x) | ||||||||||||||
let neg = fun x -> fix (- x) | ||||||||||||||
let abs = fun x -> fix (abs x) | ||||||||||||||
let of_int64 = fun x -> fix (Int64.to_int x) | ||||||||||||||
let to_int64 = Int64.of_int | ||||||||||||||
let of_nativeint = fun x -> fix (Nativeint.to_int x) | ||||||||||||||
let to_nativeint = Nativeint.of_int | ||||||||||||||
end | ||||||||||||||
|
||||||||||||||
external format_int : string -> int -> string = "caml_format_int" | ||||||||||||||
|
||||||||||||||
module Int8 = MakeSmall( | ||||||||||||||
struct | ||||||||||||||
let bits = 8 | ||||||||||||||
|
||||||||||||||
external of_string : string -> int = "integers_int8_of_string" | ||||||||||||||
external to_string : int -> string = "integers_int8_to_string" | ||||||||||||||
external to_hexstring : int -> string = "integers_int8_to_hexstring" | ||||||||||||||
external max : unit -> int = "integers_int8_max" | ||||||||||||||
external min : unit -> int = "integers_int8_min" | ||||||||||||||
end) | ||||||||||||||
|
||||||||||||||
module Int16 = MakeSmall( | ||||||||||||||
struct | ||||||||||||||
let bits = 16 | ||||||||||||||
|
||||||||||||||
external of_string : string -> int = "integers_int16_of_string" | ||||||||||||||
external to_string : int -> string = "integers_int16_to_string" | ||||||||||||||
external to_hexstring : int -> string = "integers_int16_to_hexstring" | ||||||||||||||
external max : unit -> int = "integers_int16_max" | ||||||||||||||
external min : unit -> int = "integers_int16_min" | ||||||||||||||
end) | ||||||||||||||
|
||||||||||||||
module Int = | ||||||||||||||
struct | ||||||||||||||
module Basics = | ||||||||||||||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,143 @@ | ||
#if !__USE_MINGW_ANSI_STDIO && (defined(__MINGW32__) || defined(__MINGW64__)) | ||
#define __USE_MINGW_ANSI_STDIO 1 | ||
#endif | ||
|
||
#include <caml/mlvalues.h> | ||
#include <caml/custom.h> | ||
#include <caml/alloc.h> | ||
#include <caml/intext.h> | ||
#include <caml/fail.h> | ||
|
||
#include <inttypes.h> | ||
#include <stdint.h> | ||
#include <limits.h> | ||
#include <stdio.h> | ||
|
||
#define OCAML_INTEGERS_INTERNAL 1 | ||
#include "ocaml_integers.h" | ||
|
||
CAMLprim value integers_int_size(value unit) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'd prefer to update the minimum requirement to OCaml 4.03 and call the function from the distribution |
||
{ | ||
return Val_long(8 * sizeof(value) - 1) ; | ||
} | ||
|
||
#define INT_SMALL_DECLS(BITS) \ | ||
/* of_string : string -> t */ \ | ||
extern value integers_int ## BITS ## _of_string(value a); \ | ||
/* to_string : t -> string */ \ | ||
extern value integers_int ## BITS ## _to_string(value a); \ | ||
/* max : unit -> t */ \ | ||
extern value integers_int ## BITS ## _max(value a); | ||
|
||
INT_SMALL_DECLS(8) | ||
INT_SMALL_DECLS(16) | ||
|
||
#define TYPE(SIZE) int ## SIZE ## _t | ||
#define UTYPE(SIZE) uint ## SIZE ## _t | ||
#define BUF_SIZE(TYPE) ((sizeof(TYPE) * CHAR_BIT + 2) / 3 + 2) | ||
|
||
#define INT_OF_STRING(BITS, COPY) \ | ||
value integers_int ## BITS ## _of_string(value a) \ | ||
{ \ | ||
TYPE(BITS) i, max_prefix; \ | ||
const char *pos = String_val(a); \ | ||
int base = 10, d, sign = 1, signedness = 1; \ | ||
\ | ||
/* Detect sign, if given */ \ | ||
if (*pos == '-') { \ | ||
sign = -1; \ | ||
pos++; \ | ||
} else if (*pos == '+') { \ | ||
pos++; \ | ||
} \ | ||
if (*pos == '0') { \ | ||
switch (pos[1]) { \ | ||
case 'x': case 'X': \ | ||
base = 16; pos += 2; break; \ | ||
case 'o': case 'O': \ | ||
base = 8; pos += 2; break; \ | ||
case 'b': case 'B': \ | ||
base = 2; pos += 2; break; \ | ||
case 'u': case 'U': /* Unsigned prefix. No-op for unsigned types */ \ | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I left this comment in place because I'm still not 100% sure what the behavior here should be after reading the comments in |
||
signedness = 0; pos += 2; break; \ | ||
} \ | ||
} \ | ||
\ | ||
max_prefix = ((UTYPE(BITS)) -1) / base; \ | ||
\ | ||
d = parse_digit(*pos); \ | ||
if (d < 0 || d >= base) { \ | ||
caml_failwith("Int"#BITS".of_string"); \ | ||
} \ | ||
i = sign < 0 ? (TYPE(BITS)) (- d) : (TYPE(BITS)) d; \ | ||
pos++; \ | ||
\ | ||
for (;; pos++) { \ | ||
if (*pos == '_') continue; \ | ||
d = parse_digit(*pos); \ | ||
/* Halt if the digit isn't valid (or this is the string terminator) */ \ | ||
if (d < 0 || d >= base) break; \ | ||
/* Check that we can add another digit */ \ | ||
if (i > max_prefix) break; \ | ||
i = (sign < 0 ? (- d) : d) + i * base; \ | ||
/* Check for overflow */ \ | ||
if (sign < 0) { \ | ||
if (i > ((TYPE(BITS)) (- d))) break; \ | ||
} else { \ | ||
if (i < (TYPE(BITS)) d) break; \ | ||
} \ | ||
} \ | ||
\ | ||
if (pos != String_val(a) + caml_string_length(a)){ \ | ||
caml_failwith("Int"#BITS".of_string"); \ | ||
} \ | ||
\ | ||
return COPY(i); \ | ||
} \ | ||
|
||
#define INT_SMALL_DEFS(BITS) \ | ||
/* of_string : string -> t */ \ | ||
INT_OF_STRING(BITS, Integers_val_int ## BITS) \ | ||
\ | ||
/* to_string : t -> string */ \ | ||
value integers_int ## BITS ## _to_string(value a) \ | ||
{ \ | ||
char buf[BUF_SIZE(TYPE(BITS))]; \ | ||
if (sprintf(buf, "%" PRId ## BITS , Int ## BITS ##_val(a)) < 0) \ | ||
caml_failwith("Int ## BITS ## .to_string"); \ | ||
else \ | ||
return caml_copy_string(buf); \ | ||
} \ | ||
\ | ||
/* to_hexstring : t -> string */ \ | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The specification of
(see #33 (comment)). which means, e.g.: # Printf.sprintf "%x" (-15);;
- : string = "7ffffffffffffff1" |
||
value integers_int ## BITS ## _to_hexstring(value a) \ | ||
{ \ | ||
char buf[BUF_SIZE(TYPE(BITS))]; \ | ||
char* c = buf; \ | ||
/* Use intnat in case d is MIN_INT(BITS) */ \ | ||
intnat d = Int_val(a); \ | ||
if (d < 0) { \ | ||
*c = '-'; \ | ||
c++; \ | ||
d = (- d); \ | ||
} \ | ||
if (sprintf(c, "%" PRIx ## BITS , (TYPE(BITS)) d) < 0) \ | ||
caml_failwith("Int ## BITS ## .to_hexstring"); \ | ||
else \ | ||
return caml_copy_string(buf); \ | ||
} \ | ||
\ | ||
/* max : unit -> t */ \ | ||
value integers_int ## BITS ## _max(value unit) \ | ||
{ \ | ||
return Integers_val_int ## BITS(~(1 << (BITS - 1))); \ | ||
} \ | ||
\ | ||
/* min : unit -> t */ \ | ||
value integers_int ## BITS ## _min(value unit) \ | ||
{ \ | ||
return Integers_val_int ## BITS((- 1) << (BITS - 1)); \ | ||
} | ||
|
||
INT_SMALL_DEFS(8) | ||
INT_SMALL_DEFS(16) |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,5 +1,5 @@ | ||
(tests | ||
(package integers) | ||
(libraries integers) | ||
(names hexprinting uint64conversions uint32conversions)) | ||
(names hexprinting uint64conversions uint32conversions smallsint)) | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
(see suggestion to use qualified names below)