Commit | Line | Data |
---|---|---|
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 | |
21 | type '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 | |
29 | exception No_more_elements\r | |
30 | \r | |
31 | let _dummy () = assert false\r | |
32 | \r | |
33 | let 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 | |
41 | let 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 | |
56 | let 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 | |
64 | type 'a _mut_list = {\r | |
65 | hd : 'a;\r | |
66 | mutable tl : 'a _mut_list;\r | |
67 | }\r | |
68 | \r | |
69 | let 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 | |
106 | let 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 | |
117 | let 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 | |
127 | let get t =\r | |
128 | try\r | |
129 | Some (t.next())\r | |
130 | with\r | |
131 | No_more_elements -> None\r | |
132 | \r | |
133 | let 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 | |
155 | let 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 | |
162 | let junk t =\r | |
163 | try\r | |
164 | ignore(t.next())\r | |
165 | with\r | |
166 | No_more_elements -> ()\r | |
167 | \r | |
168 | let 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 | |
174 | let count t =\r | |
175 | t.count()\r | |
176 | \r | |
177 | let fast_count t =\r | |
178 | t.fast\r | |
179 | \r | |
180 | let clone t =\r | |
181 | t.clone()\r | |
182 | \r | |
183 | let 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 | |
193 | let 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 | |
203 | let 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 | |
221 | let 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 | |
238 | let 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 | |
249 | let 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 | |
260 | let 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 | |
280 | let 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 | |
300 | let 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 | |
310 | let 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 | |
318 | let 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 | |
327 | let 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 | |
334 | let 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 | |
342 | let 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 | |
363 | let 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 |