Skip to content

Commit

Permalink
Merge pull request #46 from darlentar/master
Browse files Browse the repository at this point in the history
add of_substring.
  • Loading branch information
rgrinberg authored Jun 29, 2020
2 parents 0785788 + a777def commit 48f97cd
Show file tree
Hide file tree
Showing 6 changed files with 80 additions and 49 deletions.
1 change: 1 addition & 0 deletions lib/stdint.ml
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,7 @@ module type Int = sig
val of_uint128 : uint128 -> t
val to_uint128 : t -> uint128

val of_substring : string -> pos:int -> (t * int)
val of_string : string -> t
val to_string : t -> string

Expand Down
9 changes: 9 additions & 0 deletions lib/stdint.mli
Original file line number Diff line number Diff line change
Expand Up @@ -279,6 +279,15 @@ module type Int = sig
(** Convert an integer of type [t] to an integer of type [uint128]. *)
(** {6 String conversion functions} *)

val of_substring : string -> pos:int -> (t * int)
(** Convert the given substring starting at the given offset [pos]
to an integer of type [t] and return the offset.
The string is read in decimal (by default) or in hexadecimal, octal
or binary if the string begins with [0x], [0o] or [0b] respectively.
Raise [Failure "*_of_substring"] 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 [t]. *)

val of_string : string -> t
(** Convert the given string to an integer of type [t].
The string is read in decimal (by default) or in hexadecimal, octal
Expand Down
53 changes: 35 additions & 18 deletions lib/str_conv.ml
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ end

module type S = sig
type t
val of_substring : string -> pos:int -> (t * int)
val of_string : string -> t
val to_string : t -> string
val to_string_bin : t -> string
Expand All @@ -30,26 +31,22 @@ end
module Make (I : IntSig) : S with type t = I.t = struct
type t = I.t

let digit_of_char c =
let disp =
if c >= '0' && c <= '9' then 48
else if c >= 'A' && c <= 'F' then 55
else if c >= 'a' && c <= 'f' then 87
else failwith (I.name ^ ".of_string") in
int_of_char c - disp
exception NotDigit of I.t * int

let of_string s =
let fail () = invalid_arg (I.name ^ ".of_string") in
let len = String.length s in
(** Base function for *of_string* and *of_substring*
* functions *)
let _of_substring start_off s func_name =
let fail () = invalid_arg (I.name ^ func_name) in
let len = String.length s - start_off in
(* is this supposed to be a negative number? *)
let negative, off =
if len = 0 then fail ();
if s.[0] = '-' then
true, 1
else if s.[0] = '+' then
false, 1
if len <= 0 then fail ();
if s.[start_off] = '-' then
true, 1+start_off
else if s.[start_off] = '+' then
false, 1+start_off
else
false, 0 in
false, start_off in
(* does the string have a base-prefix and what base is it? *)
let base, off =
if len - off < 3 then (* no space for a prefix in there *)
Expand All @@ -73,11 +70,19 @@ module Make (I : IntSig) : S with type t = I.t = struct
(I.divmod I.max_int base, I.add, -1) in
let rec loop off (n : I.t) =
if off = len then
n
n, off
else begin
let c = s.[off] in
if c <> '_' then begin
let d = I.of_int (digit_of_char c) in
let disp =
if c >= '0' && c <= '9' then 48
else if c >= 'A' && c <= 'F' then 55
else if c >= 'a' && c <= 'f' then 87
else raise (NotDigit (n, off)) in
let disp = int_of_char c - disp in
let d = I.of_int disp in
(* do not accept digit larger than the base *)
if d >= base then fail () ;
(* will we overflow? *)
(match compare n thresh with
| 0 ->
Expand All @@ -93,6 +98,18 @@ module Make (I : IntSig) : S with type t = I.t = struct
in
loop off I.zero

let of_substring s ~pos =
try
_of_substring pos s ".of_substring"
with
| NotDigit (n, off) -> n, off

let of_string s =
try
let n, _ = _of_substring 0 s ".of_string" in n
with
| NotDigit _ -> invalid_arg (I.name ^ ".of_string")

let to_string_base base prefix x =
let prefixlen = String.length prefix in
let base = I.of_int base in
Expand Down
1 change: 1 addition & 0 deletions lib/str_conv.mli
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ end

module type S = sig
type t
val of_substring : string -> pos:int -> (t * int)
val of_string : string -> t
val to_string : t -> string
val to_string_bin : t -> string
Expand Down
46 changes: 19 additions & 27 deletions stdint.opam
Original file line number Diff line number Diff line change
@@ -1,5 +1,23 @@
# This file is generated by dune, edit dune-project instead
opam-version: "2.0"
build: [
["dune" "subst"] {pinned}
["dune" "build" "-p" name "-j" jobs]
["dune" "runtest" "-p" name "-j" jobs] {with-test}
["dune" "build" "-p" name "@doc"] {with-doc}
]
maintainer: ["Markus W. Weissmann <markus.weissmann@in.tum.de>"]
authors: [
"Andre Nathan <andre@digirati.com.br>"
"Jeff Shaw <shawjef3@msu.edu>"
"Markus W. Weissmann <markus.weissmann@in.tum.de>"
"Florian Pichlmeier <florian.pichlmeier@mytum.de>"
]
bug-reports: "https://github.com/andrenth/ocaml-stdint/issues"
homepage: "https://github.com/andrenth/ocaml-stdint"
doc: "https://andrenth.github.io/ocaml-stdint/"
license: "MIT"
dev-repo: "git+https://github.com/andrenth/ocaml-stdint.git"
synopsis: "Signed and unsigned integer types having specified widths"
description: """
The stdint library provides signed and unsigned integer types of various fixed
Expand All @@ -11,33 +29,7 @@ like maximum and minimum values, infix operators conversion to and from every
other integer type (including int, float and nativeint), parsing from and
conversion to readable strings (binary, octal, decimal, hexademical), conversion
to and from buffers in both big endian and little endian byte order."""
maintainer: ["Markus W. Weissmann <markus.weissmann@in.tum.de>"]
authors: [
"Andre Nathan <andre@digirati.com.br>"
"Jeff Shaw <shawjef3@msu.edu>"
"Markus W. Weissmann <markus.weissmann@in.tum.de>"
"Florian Pichlmeier <florian.pichlmeier@mytum.de>"
]
license: "MIT"
homepage: "https://github.com/andrenth/ocaml-stdint"
doc: "https://andrenth.github.io/ocaml-stdint/"
bug-reports: "https://github.com/andrenth/ocaml-stdint/issues"
depends: [
"ocaml" {>= "4.03"}
"dune" {>= "1.4"}
"dune" {>= "1.10"}
]
build: [
["dune" "subst"] {pinned}
[
"dune"
"build"
"-p"
name
"-j"
jobs
"@install"
"@runtest" {with-test}
"@doc" {with-doc}
]
]
dev-repo: "git+https://github.com/andrenth/ocaml-stdint.git"
19 changes: 15 additions & 4 deletions tests/stdint_test.ml
Original file line number Diff line number Diff line change
Expand Up @@ -94,16 +94,20 @@ struct
let max_str = I.(to_string max_int)
let max_str_len = String.length max_str

let str_gen =
let integer_str_gen =
QCheck.(string_gen_of_size (Gen.return max_str_len) Gen.numeral |>
map_same_type (fun s ->
if s <= max_str then s else String.sub s 1 (max_str_len - 1)))

let str_gen =
QCheck.pair integer_str_gen (
QCheck.(string_gen_of_size (Gen.return 1) (Gen.oneofl ['k';'!'])))

open I

let tests = [
test "An integer should be converted from strings correctly"
str_gen (fun s ->
integer_str_gen (fun s ->
let str = Str.(replace_first (regexp "^0+") "" s) in
to_string (of_string str) = str &&
(try
Expand All @@ -112,15 +116,22 @@ struct
with e -> true)) ;

test "An integer should be converted from signed (+) strings correctly"
str_gen (fun s ->
integer_str_gen (fun s ->
let str = Str.(replace_first (regexp "^0+") "" s) in
to_string (of_string ("+" ^ str)) = str) ;

test "An integer should be converted from signed (-) strings correctly"
str_gen (fun s ->
integer_str_gen (fun s ->
let str = "-" ^ Str.(replace_first (regexp "^0+") "" s) in
min_int = zero ||
to_string (of_string str) = str) ;

test "An integer should be converted from strings with right offset correctly"
str_gen (fun (i, s) ->
let i_str = Str.(replace_first (regexp "^0+") "" i) in
let str = i_str ^ s in
let s, o = of_substring ~pos:0 str in
to_string s = i_str && o = String.length i_str) ;
]
end

Expand Down

0 comments on commit 48f97cd

Please sign in to comment.