Legend:
Page
Library
Module
Module type
Parameter
Class
Class type
Source
Page
Library
Module
Module type
Parameter
Class
Class type
Source
str_conv.ml1 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 165module type IntSig = sig type t val name : string val fmt : string val zero : t val max_int : t val min_int : t val bits : int val of_int : int -> t val to_int : t -> int val add : t -> t -> t val sub : t -> t -> t val mul : t -> t -> t val divmod : t -> t -> t * t 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 val to_string_oct : t -> string val to_string_hex : t -> string val printer : Format.formatter -> t -> unit val printer_bin : Format.formatter -> t -> unit val printer_oct : Format.formatter -> t -> unit val printer_hex : Format.formatter -> t -> unit end module Make (I : IntSig) : S with type t = I.t = struct type t = I.t exception EndOfNumber of I.t * int (** 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 if start_off >= String.length s then fail (); (* is this supposed to be a negative number? *) let negative, off = if s.[start_off] = '-' then true, 1+start_off else if s.[start_off] = '+' then false, 1+start_off else false, start_off in let len = String.length s in if len <= off then fail (); (* does the string have a base-prefix and what base is it? *) let base, off = let is_digit ~base c = if base <= 10 then ( Char.(code c - code '0') < base ) else ( (c >= '0' && c <= '9') || (10 + Char.(code (lowercase_ascii c) - code 'a') < base) ) in if len - off < 3 then (* no space for a prefix in there *) 10, off else if s.[off] = '0' then match Char.lowercase_ascii s.[off + 1] with | 'b' when is_digit ~base:2 s.[off+2] -> 2, off + 2 | 'o' when is_digit ~base:8 s.[off+2] -> 8, off + 2 | 'x' when is_digit ~base:16 s.[off+2] -> 16, off + 2 | _ -> 10, off else 10, off in let base = I.of_int base in (* operators that are different for parsing negative and positive numbers *) let (thresh, rem), join, cmp_safe = if negative then (I.divmod I.min_int base, I.sub, 1) else (I.divmod I.max_int base, I.add, -1) in let rec loop off (n : I.t) = if off = len then n, off else begin let c = s.[off] in if c <> '_' then begin 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 (EndOfNumber (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 raise (EndOfNumber (n, off)); (* will we overflow? *) (match compare n thresh with | 0 -> let r = compare d rem in if r <> cmp_safe && r <> 0 then raise (EndOfNumber (n, off)); | r -> if r <> cmp_safe then raise (EndOfNumber (n, off))); (* shift the existing number, join the new digit *) let res = join (I.mul n base) d in loop (off + 1) res end else loop (off + 1) n end in loop off I.zero let of_substring s ~pos = try _of_substring pos s ".of_substring" with | EndOfNumber (n, off) -> n, off let of_string s = try let n, _ = _of_substring 0 s ".of_string" in n with | EndOfNumber _ -> 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 let conv = "0123456789abcdef" in if x = I.zero then prefix ^ "0" else begin (* worst-case: 1 (signed) + length prefix + 1 char-per-bit *) let maxlen = 1 + prefixlen + I.bits in let buffer = Bytes.create maxlen in (* create the number starting at the end of the buffer, working towards * its start. *) let off = ref (maxlen - 1) in let rec loop n = if n <> I.zero then begin let n', digit = I.divmod n base in let digit = (I.to_int digit) in Bytes.set buffer !off conv.[abs digit]; decr off; loop n' end in loop x; (* add prefix -- in reverse order *) for i = prefixlen - 1 downto 0 do Bytes.set buffer !off (String.get prefix i); decr off done; if x < I.zero then begin Bytes.set buffer !off '-'; decr off end; Bytes.sub_string buffer (!off + 1) (maxlen - !off - 1) end let to_string = to_string_base 10 "" let to_string_bin = to_string_base 2 "0b" let to_string_oct = to_string_base 8 "0o" let to_string_hex = to_string_base 16 "0x" let print_with f fmt x = Format.fprintf fmt "@[%s@]" (f x ^ I.fmt) let printer = print_with to_string let printer_bin = print_with to_string_bin let printer_oct = print_with to_string_oct let printer_hex = print_with to_string_hex end