Commits

camlspotter committed d5a5418

Sbuffer.substr added

Comments (0)

Files changed (3)

 
 module Simple_string = Simple(struct type t = string end)
 
-include Make(struct
+module M = struct
   type elem = char
-  type t = { buf : Simple_string.t;
-	     offset : int }
+  type t = { 
+    buf : Simple_string.t;
+    rel_pos : int; (* from the buf head *)
+    abs_pos : int; (* from the first *)
+  }
 
-  let empty = { buf = Simple_string.empty;
-		offset = 0 }
+  let empty = 
+    { buf = Simple_string.empty;
+      rel_pos = 0;
+      abs_pos = 0; }
 
   let rec take : t -> (elem * t) option = fun t -> 
     Option.bind (Simple_string.take t.buf)
       (fun (elem, buf') ->
-	if t.offset >= String.length elem then
-	  take { buf = buf'; offset = t.offset - String.length elem }
-	else Some (elem.[t.offset],
-		  { t with offset = t.offset + 1}))
+	if t.rel_pos >= String.length elem then
+	  take { buf = buf'; 
+		 rel_pos = t.rel_pos - String.length elem;
+		 abs_pos = t.abs_pos }
+	else Some (elem.[t.rel_pos],
+		  { t with rel_pos = t.rel_pos + 1;
+		           abs_pos = t.abs_pos + 1 }))
 
   type gen = Simple_string.gen
   let create gen = { buf = Simple_string.create gen;
-		     offset = 0 }
-end)
+		     rel_pos = 0;
+		     abs_pos = 0; }
 
+  let substr t start_abs_pos len =
+    if t.abs_pos > start_abs_pos then failwith "Sbuffer.substr: start_abs_pos is over";
+    let buffer = Buffer.create len in
+    let rec substr buf buf_pos pos len =
+      if len = 0 then ()
+      else match Simple_string.take buf with
+      | None -> failwith "Sbuffer.substr: end of stream"
+      | Some (string, buf') ->
+	  let len_string = String.length string in
+	  let buf_pos' = buf_pos + len_string in
+	  if buf_pos' <= pos then substr buf' buf_pos' pos len
+	  else 
+	    let start = pos - buf_pos in
+	    let copy_len = min len (len_string - buf_pos) in
+	    if copy_len <= 0 then ()
+	    else begin
+	      Buffer.add_substring buffer string start copy_len;
+	      let len' = len - copy_len in
+	      substr buf' buf_pos' buf_pos' len'
+	    end
+    in
+    Buffer.contents buffer
+end
+
+include Make(M)
+let substr = M.substr
 include Stream.S with type elem = char
                  and  type gen  = string Stream.simple_gen
+val substr : t -> int -> int -> string
+
+
   val is_empty : t -> bool
 end
 
-module Make(S0 : S0) : S with type elem = S0.elem and type gen = S0.gen
+module Make(S0 : S0) : S with type elem = S0.elem and type t = S0.t and type gen = S0.gen
 
 type 'a simple_gen = unit -> [ `None | `Some of 'a * 'a simple_gen ]