Import Upstream version 20180207
[hcoop/debian/mlton.git] / basis-library / integer / int-inf.sml
CommitLineData
7f918cf1
CE
1(* Copyright (C) 2013-2014 Matthew Fluet.
2 * Copyright (C) 1999-2007 Henry Cejtin, Matthew Fluet, Suresh
3 * Jagannathan, and Stephen Weeks.
4 * Copyright (C) 1997-2000 NEC Research Institute.
5 *
6 * MLton is released under a BSD-style license.
7 * See the file MLton-LICENSE for details.
8 *)
9
10structure IntInf: INT_INF_EXTRA =
11 struct
12 open Primitive.IntInf
13 type t = int
14
15 structure BigWord = C_MPLimb
16 structure SmallInt = ObjptrInt
17
18 structure W = ObjptrWord
19 structure I = ObjptrInt
20 structure MPLimb = C_MPLimb
21
22 val precision: Int.int option = NONE
23
24 fun sign (arg: int): Int.int =
25 case compare (arg, zero) of
26 LESS => ~1
27 | EQUAL => 0
28 | GREATER => 1
29
30 fun sameSign (x, y) = sign x = sign y
31
32 local
33 val maxShift32 = Word32.<< (0wx1, 0w30)
34 val maxShift = Word32.toWord maxShift32
35 fun make f (arg, shift) =
36 let
37 fun body loop (arg, shift) =
38 if Word.<= (shift, maxShift)
39 then f (arg, Word32.fromWord shift)
40 else loop (f (arg, maxShift32),
41 Word.- (shift, maxShift))
42 fun loop (arg, shift) = body loop (arg, shift)
43 in
44 body loop (arg, shift)
45 end
46 in
47 val << = make <<
48 val ~>> = make ~>>
49 end
50
51 val fromInt = schckFromInt
52 val toInt = schckToInt
53 val fromLarge = schckFromLargeInt
54 val toLarge = schckToLargeInt
55
56 local
57 open StringCvt
58
59 val binCvt = mkCvt {base = 2, smallCvt = I.fmt BIN}
60 val octCvt = mkCvt {base = 8, smallCvt = I.fmt OCT}
61 val decCvt = mkCvt {base = 10, smallCvt = I.fmt DEC}
62 val hexCvt = mkCvt {base = 16, smallCvt = I.fmt HEX}
63 in
64 fun fmt radix =
65 case radix of
66 BIN => binCvt
67 | OCT => octCvt
68 | DEC => decCvt
69 | HEX => hexCvt
70 val toString = fmt DEC
71 end
72
73 local
74 open StringCvt
75
76 (*
77 * Given a char, if it is a digit in the appropriate base,
78 * convert it to a word. Otherwise, return NONE.
79 * Note, both a-f and A-F are accepted as hexadecimal digits.
80 *)
81 fun binDig (ch: char): W.word option =
82 case ch of
83 #"0" => SOME 0w0
84 | #"1" => SOME 0w1
85 | _ => NONE
86
87 local
88 val op <= = Char.<=
89 in
90 fun octDig (ch: char): W.word option =
91 if #"0" <= ch andalso ch <= #"7"
92 then SOME (W.fromInt (Int.- (Char.ord ch,
93 Char.ord #"0")))
94 else NONE
95
96 fun decDig (ch: char): W.word option =
97 if #"0" <= ch andalso ch <= #"9"
98 then SOME (W.fromInt (Int.- (Char.ord ch,
99 Char.ord #"0")))
100 else NONE
101
102 fun hexDig (ch: char): W.word option =
103 if #"0" <= ch andalso ch <= #"9"
104 then SOME (W.fromInt (Int.- (Char.ord ch,
105 Char.ord #"0")))
106 else if #"a" <= ch andalso ch <= #"f"
107 then SOME (W.fromInt (Int.- (Char.ord ch,
108 Int.- (Char.ord #"a", 0xa))))
109 else if #"A" <= ch andalso ch <= #"F"
110 then SOME (W.fromInt (Int.- (Char.ord ch,
111 Int.- (Char.ord #"A", 0xA))))
112 else NONE
113 end
114
115 (*
116 * Given a digit converter and a char reader, return a digit
117 * reader.
118 *)
119 fun toDigR (charToDig: char -> W.word option,
120 cread: (char, 'a) reader)
121 (s: 'a)
122 : (W.word * 'a) option =
123 case cread s of
124 NONE => NONE
125 | SOME (ch, s') =>
126 case charToDig ch of
127 NONE => NONE
128 | SOME dig => SOME (dig, s')
129
130 (*
131 * A chunk represents the result of processing some digits.
132 * more is a bool indicating if there might be more digits.
133 * shift is base raised to the number-of-digits-seen power.
134 * chunk is the value of the digits seen.
135 *)
136 type chunk = {more: bool,
137 shift: W.word,
138 chunk: W.word}
139 (*
140 * Given the base and a digit reader,
141 * return a chunk reader.
142 *)
143 fun toChunkR (base: W.word,
144 dread: (W.word, 'a) reader)
145 : (chunk, 'a) reader =
146 let
147 fun loop {left: Int32.int,
148 shift: W.word,
149 chunk: W.word,
150 s: 'a}
151 : chunk * 'a =
152 if Int32.<= (left, 0)
153 then ({more = true,
154 shift = shift,
155 chunk = chunk},
156 s)
157 else
158 case dread s of
159 NONE => ({more = false,
160 shift = shift,
161 chunk = chunk},
162 s)
163 | SOME (dig, s') =>
164 loop {left = Int32.- (left, 1),
165 shift = W.* (base, shift),
166 chunk = W.+ (W.* (base, chunk), dig),
167 s = s'}
168 (* digitsPerChunk = floor((W.wordSize - 3) / (log2 base)) *)
169 val digitsPerChunk : Int32.t =
170 case (W.wordSize, base) of
171 (64, 0w16) => 15
172 | (64, 0w10) => 18
173 | (64, 0w8) => 20
174 | (64, 0w2) => 61
175 | (32, 0w16) => 7
176 | (32, 0w10) => 8
177 | (32, 0w8) => 9
178 | (32, 0w2) => 29
179 | _ => raise (Fail "IntInf.scan:digitsPerChunk")
180 fun reader (s: 'a): (chunk * 'a) option =
181 case dread s of
182 NONE => NONE
183 | SOME (dig, next) =>
184 SOME (loop {left = Int32.- (digitsPerChunk, 1),
185 shift = base,
186 chunk = dig,
187 s = next})
188 in
189 reader
190 end
191
192 (*
193 * Given a chunk reader, return an unsigned reader.
194 *)
195 fun toUnsR (ckread: (chunk, 'a) reader): (int, 'a) reader =
196 let
197 fun loop (more: bool, acc: int, s: 'a) =
198 if more
199 then case ckread s of
200 NONE => (acc, s)
201 | SOME ({more, shift, chunk}, s') =>
202 loop (more,
203 ((W.toLargeInt shift) * acc)
204 + (W.toLargeInt chunk),
205 s')
206 else (acc, s)
207 fun reader (s: 'a): (int * 'a) option =
208 case ckread s of
209 NONE => NONE
210 | SOME ({more, chunk, ...}, s') =>
211 SOME (loop (more,
212 W.toLargeInt chunk,
213 s'))
214 in
215 reader
216 end
217
218 (*
219 * Given a char reader and an unsigned reader, return an unsigned
220 * reader that includes skipping the option hex '0x'.
221 *)
222 fun toHexR (cread: (char, 'a) reader, uread: (int, 'a) reader) s =
223 case cread s of
224 NONE => NONE
225 | SOME (c1, s1) =>
226 if c1 = #"0" then
227 case cread s1 of
228 NONE => SOME (zero, s1)
229 | SOME (c2, s2) =>
230 if c2 = #"x" orelse c2 = #"X" then
231 case uread s2 of
232 NONE => SOME (zero, s1)
233 | SOME x => SOME x
234 else uread s
235 else uread s
236
237 (*
238 * Given a char reader and an unsigned reader, return a signed
239 * reader. This includes skipping any initial white space.
240 *)
241 fun toSign (cread: (char, 'a) reader, uread: (int, 'a) reader)
242 : (int, 'a) reader =
243 let
244 fun reader (s: 'a): (int * 'a) option =
245 let val s = StringCvt.skipWS cread s in
246 case cread s of
247 NONE => NONE
248 | SOME (ch, s') =>
249 let
250 val (isNeg, s'') =
251 case ch of
252 #"+" => (false, s')
253 | #"-" => (true, s')
254 | #"~" => (true, s')
255 | _ => (false, s)
256 in
257 if isNeg
258 then case uread s'' of
259 NONE => NONE
260 | SOME (abs, s''') => SOME (~ abs, s''')
261 else uread s''
262 end
263 end
264 in
265 reader
266 end
267
268 (*
269 * Base-specific conversions from char readers to
270 * int readers.
271 *)
272 local
273 fun reader (base, dig)
274 (cread: (char, 'a) reader)
275 : (int, 'a) reader =
276 let
277 val dread = toDigR (dig, cread)
278 val ckread = toChunkR (base, dread)
279 val uread = toUnsR ckread
280 val hread = if base = 0w16 then toHexR (cread, uread) else uread
281 val reader = toSign (cread, hread)
282 in
283 reader
284 end
285 in
286 fun binReader z = reader (0w2, binDig) z
287 fun octReader z = reader (0w8, octDig) z
288 fun decReader z = reader (0w10, decDig) z
289 fun hexReader z = reader (0w16, hexDig) z
290 end
291 in
292 fun scan radix =
293 case radix of
294 BIN => binReader
295 | OCT => octReader
296 | DEC => decReader
297 | HEX => hexReader
298 end
299
300 val fromString = StringCvt.scanString (scan StringCvt.DEC)
301
302 local
303 fun isEven (n: Int.int) = Int.andb (n, 0x1) = 0
304 in
305 fun pow (i: int, j: Int.int): int =
306 if Int.< (j, 0) then
307 if i = zero then
308 raise Div
309 else
310 if i = one then one
311 else if i = negOne then if isEven j then one else negOne
312 else zero
313 else
314 if j = 0 then one
315 else
316 let
317 fun square (n: int): int = n * n
318 (* pow (j) returns (i ^ j) *)
319 fun pow (j: Int.int): int =
320 if Int.<= (j, 0) then one
321 else if isEven j then evenPow j
322 else i * evenPow (Int.- (j, 1))
323 (* evenPow (j) returns (i ^ j), assuming j is even *)
324 and evenPow (j: Int.int): int =
325 square (pow (Int.div (j, 2)))
326 in
327 pow j
328 end
329 end
330
331 val log2 =
332 mkLog2 {fromSmall = fn {smallLog2} => Int32.toInt smallLog2,
333 fromLarge = fn {numLimbsMinusOne, mostSigLimbLog2} =>
334 Int.+ (Int.* (MPLimb.wordSize, SeqIndex.toInt numLimbsMinusOne),
335 Int32.toInt mostSigLimbLog2)}
336 end