1 (***********************************************************************)
5 (* Daniel de Rauglaudre, projet Cristal, INRIA Rocquencourt *)
7 (* Copyright 1997 Institut National de Recherche en Informatique et *)
8 (* en Automatique. All rights reserved. This file is distributed *)
9 (* under the terms of the GNU Library General Public License, with *)
10 (* the special exception on linking described in file ../LICENSE. *)
12 (***********************************************************************)
14 (* $Id: stream.ml 8893 2008-06-18 15:35:02Z mauny $ *)
16 (* The fields of type t are not mutable to preserve polymorphism of
17 the empty stream. This is type safe because the empty stream is never
20 type 'a t = { count : int; data : 'a data }
23 | Scons of 'a * 'a data
24 | Sapp of 'a data * 'a data
25 | Slazy of 'a data Lazy.t
28 and 'a gen = { mutable curr : 'a option option; func : int -> 'a option }
30 { ic : in_channel; buff : string; mutable len : int; mutable ind : int }
33 exception Error of string;;
35 external count : 'a t -> int = "%field0";;
36 external set_count : 'a t -> int -> unit = "%setfield0";;
37 let set_data (s : 'a t) (d : 'a data) =
38 Obj.set_field (Obj.repr s) 1 (Obj.repr d)
42 b.len <- input b.ic b.buff 0 (String.length b.buff); b.ind <- 0
45 let rec get_data count d = match d with
46 (* Returns either Sempty or Scons(a, _) even when d is a generator
47 or a buffer. In those cases, the item a is seen as extracted from
49 The count parameter is used for calling `Sgen-functions'. *)
50 Sempty | Scons (_, _) -> d
52 begin match get_data count d1 with
53 Scons (a, d11) -> Scons (a, Sapp (d11, d2))
54 | Sempty -> get_data count d2
57 | Sgen {curr = Some None; func = _ } -> Sempty
58 | Sgen ({curr = Some(Some a); func = f} as g) ->
59 g.curr <- None; Scons(a, d)
61 begin match g.func count with
62 None -> g.curr <- Some(None); Sempty
63 | Some a -> Scons(a, d)
64 (* Warning: anyone using g thinks that an item has been read *)
67 if b.ind >= b.len then fill_buff b;
68 if b.len == 0 then Sempty else
69 let r = Obj.magic (String.unsafe_get b.buff b.ind) in
70 (* Warning: anyone using g thinks that an item has been read *)
71 b.ind <- succ b.ind; Scons(r, d)
72 | Slazy f -> get_data count (Lazy.force f)
76 (* consult the first item of s *)
79 | Scons (a, _) -> Some a
81 begin match get_data s.count s.data with
82 Scons(a, _) as d -> set_data s d; Some a
86 | Slazy f -> set_data s (Lazy.force f); peek s
87 | Sgen {curr = Some a} -> a
88 | Sgen g -> let x = g.func s.count in g.curr <- Some x; x
90 if b.ind >= b.len then fill_buff b;
91 if b.len == 0 then begin set_data s Sempty; None end
92 else Some (Obj.magic (String.unsafe_get b.buff b.ind))
97 Scons (_, d) -> set_count s (succ s.count); set_data s d
98 | Sgen ({curr = Some _} as g) -> set_count s (succ s.count); g.curr <- None
99 | Sbuffio b -> set_count s (succ s.count); b.ind <- succ b.ind
107 if n <= 0 then [], s.data, 0
112 let (al, d, k) = nget (pred n) s in a :: al, Scons (a, d), succ k
113 | None -> [], s.data, 0
117 let (al, d, len) = nget n s in set_count s (s.count - len); set_data s d; al
123 | None -> raise Failure
128 Some _ -> raise Failure
135 Some a -> junk strm; ignore(f a); do_rec ()
141 (* Stream building functions *)
143 let from f = {count = 0; data = Sgen {curr = None; func = f}};;
146 {count = 0; data = List.fold_right (fun x l -> Scons (x, l)) l Sempty}
150 from (fun c -> if c < String.length s then Some s.[c] else None)
155 data = Sbuffio {ic = ic; buff = String.create 4096; len = 0; ind = 0}}
158 (* Stream expressions builders *)
160 let iapp i s = {count = 0; data = Sapp (i.data, s.data)};;
161 let icons i s = {count = 0; data = Scons (i, s.data)};;
162 let ising i = {count = 0; data = Scons (i, Sempty)};;
165 {count = 0; data = Slazy (lazy(Sapp ((f ()).data, s.data)))}
167 let lcons f s = {count = 0; data = Slazy (lazy(Scons (f (), s.data)))};;
168 let lsing f = {count = 0; data = Slazy (lazy(Scons (f (), Sempty)))};;
170 let sempty = {count = 0; data = Sempty};;
171 let slazy f = {count = 0; data = Slazy (lazy(f ()).data)};;
173 (* For debugging use *)
176 print_string "{count = ";
178 print_string "; data = ";
184 Sempty -> print_string "Sempty"
186 print_string "Scons (";
192 print_string "Sapp (";
197 | Slazy _ -> print_string "Slazy"
198 | Sgen _ -> print_string "Sgen"
199 | Sbuffio b -> print_string "Sbuffio"