summaryrefslogtreecommitdiffstats
path: root/stdlib/stream.ml
blob: ebb10f181436bb605788f48966e17f2e3ef295c2 (plain)
1
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
(***********************************************************************)
(*                                                                     *)
(*                           Objective Caml                            *)
(*                                                                     *)
(*        Daniel de Rauglaudre, projet Cristal, INRIA Rocquencourt     *)
(*                                                                     *)
(*  Copyright 1996 Institut National de Recherche en Informatique et   *)
(*  Automatique.  Distributed only by permission.                      *)
(*                                                                     *)
(***********************************************************************)

(* $Id$ *)

(* The fields of type t are not mutable to preserve polymorphism of
   the empty stream. This is type safe because the empty stream is never
   patched. *)

type 'a t = {(*mutable*) count : int; (*mutable*) data : 'a data}
and 'a data =
    Sempty
  | Scons of 'a * 'a data
  | Sapp of 'a data * 'a data
  | Slazy of (unit -> 'a data)
  | Sgen of 'a gen
  | Sbuffio of buffio
and 'a gen =
  {mutable curr : 'a option option; func : int -> 'a option}
and buffio =
  {ic : in_channel; buff : string; mutable len : int; mutable ind : int}
exception Parse_failure
exception Parse_error of string

let count s = s.count

let fill_buff b =
  b.len <- input b.ic b.buff 0 (String.length b.buff);
  b.ind <- 0

let rec get_data =
  function
    Sempty -> None
  | Scons (a, d) -> Some (a, d)
  | Sapp (d1, d2) ->
      begin match get_data d1 with
        Some (a, d) -> Some (a, Sapp (d, d2))
      | None -> get_data d2
      end
  | Slazy f -> get_data (f ())
  | _ -> invalid_arg "illegal stream concatenation"

let rec peek s =
  match s.data with
    Sempty -> None
  | Scons (a, _) -> Some a
  | Sapp (d1, d2) ->
      begin match get_data d1 with
        Some (a, d) ->
          Obj.set_field (Obj.repr s) 1 (Obj.repr (Scons (a, Sapp (d, d2))));
          Some a
      | None ->
          Obj.set_field (Obj.repr s) 1 (Obj.repr d2);
          peek s
      end
  | Slazy f ->
      begin match f () with
        Sgen _ | Sbuffio _ -> invalid_arg "illegal stream concatenation"
      | x -> Obj.set_field (Obj.repr s) 1 (Obj.repr x); peek s
      end
  | Sgen {curr = Some a} -> a
  | Sgen g -> let x = g.func s.count in g.curr <- Some x; x
  | Sbuffio b ->
      if b.ind >= b.len then fill_buff b;
      if b.len == 0 then begin
        Obj.set_field (Obj.repr s) 1 (Obj.repr Sempty); None
      end
      else Some (Obj.magic b.buff.[b.ind])

let rec junk s =
  match s.data with
    Scons (_, s') ->
      Obj.set_field (Obj.repr s) 0 (Obj.repr (succ s.count));
      Obj.set_field (Obj.repr s) 1 (Obj.repr s')
  | Sgen {curr=Some None} -> ()
  | Sgen ({curr=Some _} as g) ->
      Obj.set_field (Obj.repr s) 0 (Obj.repr (succ s.count)); g.curr <- None
  | Sbuffio b ->
      Obj.set_field (Obj.repr s) 0 (Obj.repr (succ s.count));
      b.ind <- succ b.ind
  | _ -> match peek s with None -> () | Some _ -> junk s

let next s =
  match peek s with
    Some a -> junk s; a
  | None -> raise Parse_failure

let empty s =
  match peek s with
    Some _  -> raise Parse_failure
  | None -> ()

let iter f strm =
  let rec do_rec () =
    match peek strm with
      Some a -> junk strm; f a; do_rec ()
    | None -> ()
  in
  do_rec ()

(* Stream building functions *)

let from f = {count = 0; data = Sgen {curr = None; func = f}}

let of_list l =
  {count = 0; data = List.fold_right (fun x l -> Scons (x, l)) l Sempty}

let of_string s =
  from (fun c -> if c < String.length s then Some s.[c] else None)

let of_channel ic =
  {count = 0;
   data = Sbuffio {ic = ic; buff = String.create 4096; len = 0; ind = 0}}

(* Stream expressions builders *)

let sempty = {count = 0; data = Sempty}
let scons f s = {count = 0; data = Slazy (fun _ -> Scons (f (), s.data))}
let sapp f s =
  match s.data with
    Sempty -> {count = 0; data = Slazy (fun _ -> (f ()).data)}
  | d -> {count = 0; data = Slazy (fun _-> Sapp ((f ()).data, d))}

(* For debugging use *)

let rec dump f s =
  print_string "{count = "; print_int s.count; print_string "; data = ";
  dump_data f s.data; print_string "}"; print_newline ()
and dump_data f =
  function
    Sempty -> print_string "Sempty"
  | Scons (a, d) ->
      print_string "Scons ("; f a; print_string ", "; dump_data f d;
      print_string ")"
  | Sapp (d1, d2) ->
      print_string "Sapp ("; dump_data f d1; print_string ", ";
      dump_data f d2; print_string ")"
  | Slazy f -> print_string "Slazy"
  | Sgen _ -> print_string "Sgen"
  | Sbuffio b -> print_string "Sbuffio"