Release coccinelle-0.2.0
[bpt/coccinelle.git] / commons / ocamlextra / enum.ml
CommitLineData
34e49164
C
1(* \r
2 * Enum - Enumeration over abstract collection of elements.\r
3 * Copyright (C) 2003 Nicolas Cannasse\r
4 * \r
5 * This library is free software; you can redistribute it and/or\r
6 * modify it under the terms of the GNU Lesser General Public\r
7 * License as published by the Free Software Foundation; either\r
8 * version 2.1 of the License, or (at your option) any later version,\r
9 * with the special exception on linking described in file LICENSE.\r
10 *\r
11 * This library is distributed in the hope that it will be useful,\r
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of\r
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU\r
14 * Lesser General Public License for more details.\r
15 *\r
16 * You should have received a copy of the GNU Lesser General Public\r
17 * License along with this library; if not, write to the Free Software\r
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA\r
19 *)\r
20\r
21type 'a t = {\r
22 mutable count : unit -> int;\r
23 mutable next : unit -> 'a;\r
24 mutable clone : unit -> 'a t;\r
25 mutable fast : bool;\r
26}\r
27\r
28(* raised by 'next' functions, should NOT go outside the API *)\r
29exception No_more_elements\r
30\r
31let _dummy () = assert false\r
32\r
33let make ~next ~count ~clone =\r
34 {\r
35 count = count;\r
36 next = next;\r
37 clone = clone;\r
38 fast = true;\r
39 }\r
40\r
41let rec init n f =\r
42 if n < 0 then invalid_arg "Enum.init";\r
43 let count = ref n in\r
44 {\r
45 count = (fun () -> !count);\r
46 next = (fun () ->\r
47 match !count with\r
48 | 0 -> raise No_more_elements\r
49 | _ ->\r
50 decr count;\r
51 f (n - 1 - !count));\r
52 clone = (fun () -> init !count f);\r
53 fast = true;\r
54 } \r
55\r
56let rec empty () =\r
57 {\r
58 count = (fun () -> 0);\r
59 next = (fun () -> raise No_more_elements);\r
60 clone = (fun () -> empty());\r
61 fast = true;\r
62 }\r
63\r
64type 'a _mut_list = {\r
65 hd : 'a;\r
66 mutable tl : 'a _mut_list;\r
67}\r
68\r
69let force t =\r
70 let rec clone enum count =\r
71 let enum = ref !enum\r
72 and count = ref !count in\r
73 {\r
74 count = (fun () -> !count);\r
75 next = (fun () ->\r
76 match !enum with\r
77 | [] -> raise No_more_elements\r
78 | h :: t -> decr count; enum := t; h);\r
79 clone = (fun () ->\r
80 let enum = ref !enum\r
81 and count = ref !count in\r
82 clone enum count);\r
83 fast = true;\r
84 }\r
85 in\r
86 let count = ref 0 in\r
87 let _empty = Obj.magic [] in\r
88 let rec loop dst =\r
89 let x = { hd = t.next(); tl = _empty } in\r
90 incr count;\r
91 dst.tl <- x;\r
92 loop x\r
93 in\r
94 let enum = ref _empty in \r
95 (try\r
96 enum := { hd = t.next(); tl = _empty };\r
97 incr count;\r
98 loop !enum;\r
99 with No_more_elements -> ());\r
100 let tc = clone (Obj.magic enum) count in\r
101 t.clone <- tc.clone;\r
102 t.next <- tc.next;\r
103 t.count <- tc.count;\r
104 t.fast <- true\r
105\r
106let from f =\r
107 let e = {\r
108 next = f;\r
109 count = _dummy;\r
110 clone = _dummy;\r
111 fast = false;\r
112 } in\r
113 e.count <- (fun () -> force e; e.count());\r
114 e.clone <- (fun () -> force e; e.clone());\r
115 e\r
116\r
117let from2 next clone =\r
118 let e = {\r
119 next = next;\r
120 count = _dummy;\r
121 clone = clone;\r
122 fast = false;\r
123 } in\r
124 e.count <- (fun () -> force e; e.count());\r
125 e\r
126\r
127let get t =\r
128 try\r
129 Some (t.next())\r
130 with\r
131 No_more_elements -> None\r
132\r
133let push t e =\r
134 let rec make t =\r
135 let fnext = t.next in\r
136 let fcount = t.count in\r
137 let fclone = t.clone in\r
138 let next_called = ref false in\r
139 t.next <- (fun () ->\r
140 next_called := true;\r
141 t.next <- fnext;\r
142 t.count <- fcount;\r
143 t.clone <- fclone;\r
144 e);\r
145 t.count <- (fun () ->\r
146 let n = fcount() in\r
147 if !next_called then n else n+1);\r
148 t.clone <- (fun () ->\r
149 let tc = fclone() in\r
150 if not !next_called then make tc;\r
151 tc);\r
152 in\r
153 make t\r
154\r
155let peek t =\r
156 match get t with\r
157 | None -> None\r
158 | Some x ->\r
159 push t x;\r
160 Some x\r
161\r
162let junk t =\r
163 try\r
164 ignore(t.next())\r
165 with\r
166 No_more_elements -> ()\r
167\r
168let is_empty t =\r
169 if t.fast then\r
170 t.count() = 0\r
171 else\r
172 peek t = None\r
173\r
174let count t =\r
175 t.count()\r
176\r
177let fast_count t =\r
178 t.fast\r
179\r
180let clone t =\r
181 t.clone()\r
182\r
183let iter f t =\r
184 let rec loop () =\r
185 f (t.next());\r
186 loop();\r
187 in\r
188 try\r
189 loop();\r
190 with\r
191 No_more_elements -> ()\r
192\r
193let iteri f t =\r
194 let rec loop idx =\r
195 f idx (t.next());\r
196 loop (idx+1);\r
197 in\r
198 try\r
199 loop 0;\r
200 with\r
201 No_more_elements -> ()\r
202\r
203let iter2 f t u =\r
204 let push_t = ref None in\r
205 let rec loop () =\r
206 push_t := None;\r
207 let e = t.next() in\r
208 push_t := Some e;\r
209 f e (u.next());\r
210 loop ()\r
211 in\r
212 try\r
213 loop ()\r
214 with\r
215 No_more_elements ->\r
216 match !push_t with\r
217 | None -> ()\r
218 | Some e ->\r
219 push t e\r
220\r
221let iter2i f t u =\r
222 let push_t = ref None in\r
223 let rec loop idx =\r
224 push_t := None;\r
225 let e = t.next() in\r
226 push_t := Some e;\r
227 f idx e (u.next());\r
228 loop (idx + 1)\r
229 in\r
230 try\r
231 loop 0\r
232 with\r
233 No_more_elements ->\r
234 match !push_t with\r
235 | None -> ()\r
236 | Some e -> push t e\r
237\r
238let fold f init t =\r
239 let acc = ref init in\r
240 let rec loop() =\r
241 acc := f (t.next()) !acc;\r
242 loop()\r
243 in\r
244 try\r
245 loop()\r
246 with\r
247 No_more_elements -> !acc\r
248\r
249let foldi f init t =\r
250 let acc = ref init in\r
251 let rec loop idx =\r
252 acc := f idx (t.next()) !acc;\r
253 loop (idx + 1)\r
254 in\r
255 try\r
256 loop 0\r
257 with\r
258 No_more_elements -> !acc\r
259\r
260let fold2 f init t u =\r
261 let acc = ref init in\r
262 let push_t = ref None in\r
263 let rec loop() =\r
264 push_t := None;\r
265 let e = t.next() in\r
266 push_t := Some e;\r
267 acc := f e (u.next()) !acc;\r
268 loop()\r
269 in\r
270 try\r
271 loop()\r
272 with\r
273 No_more_elements ->\r
274 match !push_t with\r
275 | None -> !acc\r
276 | Some e ->\r
277 push t e;\r
278 !acc\r
279\r
280let fold2i f init t u =\r
281 let acc = ref init in\r
282 let push_t = ref None in\r
283 let rec loop idx =\r
284 push_t := None;\r
285 let e = t.next() in\r
286 push_t := Some e;\r
287 acc := f idx e (u.next()) !acc;\r
288 loop (idx + 1)\r
289 in\r
290 try\r
291 loop 0\r
292 with\r
293 No_more_elements ->\r
294 match !push_t with\r
295 | None -> !acc\r
296 | Some e ->\r
297 push t e;\r
298 !acc\r
299\r
300let find f t =\r
301 let rec loop () =\r
302 let x = t.next() in\r
303 if f x then x else loop()\r
304 in\r
305 try\r
306 loop()\r
307 with\r
308 No_more_elements -> raise Not_found\r
309\r
310let rec map f t =\r
311 {\r
312 count = t.count;\r
313 next = (fun () -> f (t.next()));\r
314 clone = (fun () -> map f (t.clone()));\r
315 fast = t.fast;\r
316 }\r
317\r
318let rec mapi f t =\r
319 let idx = ref (-1) in\r
320 {\r
321 count = t.count;\r
322 next = (fun () -> incr idx; f !idx (t.next()));\r
323 clone = (fun () -> mapi f (t.clone()));\r
324 fast = t.fast;\r
325 }\r
326\r
327let rec filter f t =\r
328 let rec next() =\r
329 let x = t.next() in\r
330 if f x then x else next()\r
331 in\r
332 from2 next (fun () -> filter f (t.clone()))\r
333\r
334let rec filter_map f t =\r
335 let rec next () =\r
336 match f (t.next()) with\r
337 | None -> next()\r
338 | Some x -> x\r
339 in\r
340 from2 next (fun () -> filter_map f (t.clone()))\r
341\r
342let rec append ta tb = \r
343 let t = {\r
344 count = (fun () -> ta.count() + tb.count());\r
345 next = _dummy;\r
346 clone = (fun () -> append (ta.clone()) (tb.clone()));\r
347 fast = ta.fast && tb.fast;\r
348 } in\r
349 t.next <- (fun () ->\r
350 try\r
351 ta.next()\r
352 with\r
353 No_more_elements ->\r
354 (* add one indirection because tb can mute *)\r
355 t.next <- (fun () -> tb.next());\r
356 t.count <- (fun () -> tb.count());\r
357 t.clone <- (fun () -> tb.clone());\r
358 t.fast <- tb.fast;\r
359 t.next()\r
360 );\r
361 t\r
362\r
363let rec concat t =\r
364 let concat_ref = ref _dummy in\r
365 let rec concat_next() =\r
366 let tn = t.next() in\r
367 concat_ref := (fun () ->\r
368 try\r
369 tn.next()\r
370 with\r
371 No_more_elements ->\r
372 concat_next());\r
373 !concat_ref ()\r
374 in\r
375 concat_ref := concat_next;\r
376 from2 (fun () -> !concat_ref ()) (fun () -> concat (t.clone()))\r