Blame src/enum.ml

rpm-build 0f2925
(* 
rpm-build 0f2925
 * Enum - Enumeration over abstract collection of elements.
rpm-build 0f2925
 * Copyright (C) 2003 Nicolas Cannasse
rpm-build 0f2925
 * 
rpm-build 0f2925
 * This library is free software; you can redistribute it and/or
rpm-build 0f2925
 * modify it under the terms of the GNU Lesser General Public
rpm-build 0f2925
 * License as published by the Free Software Foundation; either
rpm-build 0f2925
 * version 2.1 of the License, or (at your option) any later version,
rpm-build 0f2925
 * with the special exception on linking described in file LICENSE.
rpm-build 0f2925
 *
rpm-build 0f2925
 * This library is distributed in the hope that it will be useful,
rpm-build 0f2925
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
rpm-build 0f2925
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
rpm-build 0f2925
 * Lesser General Public License for more details.
rpm-build 0f2925
 *
rpm-build 0f2925
 * You should have received a copy of the GNU Lesser General Public
rpm-build 0f2925
 * License along with this library; if not, write to the Free Software
rpm-build 0f2925
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
rpm-build 0f2925
 *)
rpm-build 0f2925
rpm-build 0f2925
type 'a t = {
rpm-build 0f2925
  mutable count : unit -> int;
rpm-build 0f2925
  mutable next : unit -> 'a;
rpm-build 0f2925
  mutable clone : unit -> 'a t;
rpm-build 0f2925
  mutable fast : bool;
rpm-build 0f2925
}
rpm-build 0f2925
rpm-build 0f2925
(* raised by 'next' functions, should NOT go outside the API *)
rpm-build 0f2925
exception No_more_elements
rpm-build 0f2925
rpm-build 0f2925
let _dummy () = assert false
rpm-build 0f2925
rpm-build 0f2925
let make ~next ~count ~clone =
rpm-build 0f2925
  {
rpm-build 0f2925
    count = count;
rpm-build 0f2925
    next = next;
rpm-build 0f2925
    clone = clone;
rpm-build 0f2925
    fast = true;
rpm-build 0f2925
  }
rpm-build 0f2925
rpm-build 0f2925
let rec init n f =
rpm-build 0f2925
  if n < 0 then invalid_arg "Enum.init";
rpm-build 0f2925
  let count = ref n in
rpm-build 0f2925
  {
rpm-build 0f2925
    count = (fun () -> !count);
rpm-build 0f2925
    next = (fun () ->
rpm-build 0f2925
      match !count with
rpm-build 0f2925
      | 0 -> raise No_more_elements
rpm-build 0f2925
      | _ ->
rpm-build 0f2925
        decr count;
rpm-build 0f2925
        f (n - 1 - !count));
rpm-build 0f2925
    clone = (fun () -> init !count f);
rpm-build 0f2925
    fast = true;
rpm-build 0f2925
  }      
rpm-build 0f2925
rpm-build 0f2925
let rec empty () =
rpm-build 0f2925
  {
rpm-build 0f2925
    count = (fun () -> 0);
rpm-build 0f2925
    next = (fun () -> raise No_more_elements);
rpm-build 0f2925
    clone = (fun () -> empty());
rpm-build 0f2925
    fast = true;
rpm-build 0f2925
  }
rpm-build 0f2925
rpm-build 0f2925
type 'a _mut_list = {
rpm-build 0f2925
  hd : 'a;
rpm-build 0f2925
  mutable tl : 'a _mut_list;
rpm-build 0f2925
}
rpm-build 0f2925
rpm-build 0f2925
let force t =
rpm-build 0f2925
  let rec clone enum count =
rpm-build 0f2925
    let enum = ref !enum
rpm-build 0f2925
    and  count = ref !count in
rpm-build 0f2925
    {
rpm-build 0f2925
      count = (fun () -> !count);
rpm-build 0f2925
      next = (fun () ->
rpm-build 0f2925
        match !enum with
rpm-build 0f2925
        | [] -> raise No_more_elements
rpm-build 0f2925
        | h :: t -> decr count; enum := t; h);
rpm-build 0f2925
      clone = (fun () ->
rpm-build 0f2925
        let enum = ref !enum
rpm-build 0f2925
        and count = ref !count in
rpm-build 0f2925
        clone enum count);
rpm-build 0f2925
      fast = true;
rpm-build 0f2925
    }
rpm-build 0f2925
  in
rpm-build 0f2925
  let count = ref 0 in
rpm-build 0f2925
  let _empty = Obj.magic [] in
rpm-build 0f2925
  let rec loop dst =
rpm-build 0f2925
    let x = { hd = t.next(); tl = _empty } in
rpm-build 0f2925
    incr count;
rpm-build 0f2925
    dst.tl <- x;
rpm-build 0f2925
    loop x
rpm-build 0f2925
  in
rpm-build 0f2925
  let enum = ref _empty  in 
rpm-build 0f2925
  (try
rpm-build 0f2925
    enum := { hd = t.next(); tl = _empty };
rpm-build 0f2925
    incr count;
rpm-build 0f2925
    loop !enum;
rpm-build 0f2925
  with No_more_elements -> ());
rpm-build 0f2925
  let tc = clone (Obj.magic enum) count in
rpm-build 0f2925
  t.clone <- tc.clone;
rpm-build 0f2925
  t.next <- tc.next;
rpm-build 0f2925
  t.count <- tc.count;
rpm-build 0f2925
  t.fast <- true
rpm-build 0f2925
rpm-build 0f2925
let from f =
rpm-build 0f2925
  let e = {
rpm-build 0f2925
    next = f;
rpm-build 0f2925
    count = _dummy;
rpm-build 0f2925
    clone = _dummy;
rpm-build 0f2925
    fast = false;
rpm-build 0f2925
  } in
rpm-build 0f2925
  e.count <- (fun () -> force e; e.count());
rpm-build 0f2925
  e.clone <- (fun () -> force e; e.clone());
rpm-build 0f2925
  e
rpm-build 0f2925
rpm-build 0f2925
let from2 next clone =
rpm-build 0f2925
  let e = {
rpm-build 0f2925
    next = next;
rpm-build 0f2925
    count = _dummy;
rpm-build 0f2925
    clone = clone;
rpm-build 0f2925
    fast = false;
rpm-build 0f2925
  } in
rpm-build 0f2925
  e.count <- (fun () -> force e; e.count());
rpm-build 0f2925
  e
rpm-build 0f2925
rpm-build 0f2925
let next t = t.next ()
rpm-build 0f2925
rpm-build 0f2925
let get t =
rpm-build 0f2925
  try
rpm-build 0f2925
    Some (t.next())
rpm-build 0f2925
  with
rpm-build 0f2925
    No_more_elements -> None
rpm-build 0f2925
rpm-build 0f2925
let push t e =
rpm-build 0f2925
  let rec make t =
rpm-build 0f2925
    let fnext = t.next in
rpm-build 0f2925
    let fcount = t.count in
rpm-build 0f2925
    let fclone = t.clone in
rpm-build 0f2925
    let next_called = ref false in
rpm-build 0f2925
    t.next <- (fun () ->
rpm-build 0f2925
      next_called := true;
rpm-build 0f2925
      t.next <- fnext;
rpm-build 0f2925
      t.count <- fcount;
rpm-build 0f2925
      t.clone <- fclone;
rpm-build 0f2925
      e);
rpm-build 0f2925
    t.count <- (fun () ->
rpm-build 0f2925
      let n = fcount() in
rpm-build 0f2925
      if !next_called then n else n+1);
rpm-build 0f2925
    t.clone <- (fun () ->
rpm-build 0f2925
      let tc = fclone() in
rpm-build 0f2925
      if not !next_called then make tc;
rpm-build 0f2925
      tc);
rpm-build 0f2925
  in
rpm-build 0f2925
  make t
rpm-build 0f2925
rpm-build 0f2925
let peek t =
rpm-build 0f2925
  match get t with
rpm-build 0f2925
  | None -> None
rpm-build 0f2925
  | Some x ->
rpm-build 0f2925
    push t x;
rpm-build 0f2925
    Some x
rpm-build 0f2925
rpm-build 0f2925
let junk t =
rpm-build 0f2925
  try
rpm-build 0f2925
    ignore(t.next())
rpm-build 0f2925
  with
rpm-build 0f2925
    No_more_elements -> ()
rpm-build 0f2925
rpm-build 0f2925
let is_empty t =
rpm-build 0f2925
  if t.fast then
rpm-build 0f2925
    t.count() = 0
rpm-build 0f2925
  else
rpm-build 0f2925
    peek t = None
rpm-build 0f2925
rpm-build 0f2925
let count t =
rpm-build 0f2925
  t.count()
rpm-build 0f2925
rpm-build 0f2925
let fast_count t =
rpm-build 0f2925
  t.fast
rpm-build 0f2925
rpm-build 0f2925
let clone t =
rpm-build 0f2925
  t.clone()
rpm-build 0f2925
rpm-build 0f2925
let iter f t =
rpm-build 0f2925
  let rec loop () =
rpm-build 0f2925
    f (t.next());
rpm-build 0f2925
    loop();
rpm-build 0f2925
  in
rpm-build 0f2925
  try
rpm-build 0f2925
    loop();
rpm-build 0f2925
  with
rpm-build 0f2925
    No_more_elements -> ()
rpm-build 0f2925
rpm-build 0f2925
let iteri f t =
rpm-build 0f2925
  let rec loop idx =
rpm-build 0f2925
    f idx (t.next());
rpm-build 0f2925
    loop (idx+1);
rpm-build 0f2925
  in
rpm-build 0f2925
  try
rpm-build 0f2925
    loop 0;
rpm-build 0f2925
  with
rpm-build 0f2925
    No_more_elements -> ()
rpm-build 0f2925
rpm-build 0f2925
let iter2 f t u =
rpm-build 0f2925
  let push_t = ref None in
rpm-build 0f2925
  let rec loop () =
rpm-build 0f2925
    push_t := None;
rpm-build 0f2925
    let e = t.next() in
rpm-build 0f2925
    push_t := Some e;
rpm-build 0f2925
    f e (u.next());
rpm-build 0f2925
    loop ()
rpm-build 0f2925
  in
rpm-build 0f2925
  try
rpm-build 0f2925
    loop ()
rpm-build 0f2925
  with
rpm-build 0f2925
    No_more_elements ->
rpm-build 0f2925
      match !push_t with
rpm-build 0f2925
      | None -> ()
rpm-build 0f2925
      | Some e ->
rpm-build 0f2925
        push t e
rpm-build 0f2925
rpm-build 0f2925
let iter2i f t u =
rpm-build 0f2925
  let push_t = ref None in
rpm-build 0f2925
  let rec loop idx =
rpm-build 0f2925
    push_t := None;
rpm-build 0f2925
    let e = t.next() in
rpm-build 0f2925
    push_t := Some e;
rpm-build 0f2925
    f idx e (u.next());
rpm-build 0f2925
    loop (idx + 1)
rpm-build 0f2925
  in
rpm-build 0f2925
  try
rpm-build 0f2925
    loop 0
rpm-build 0f2925
  with
rpm-build 0f2925
    No_more_elements ->
rpm-build 0f2925
      match !push_t with
rpm-build 0f2925
      | None -> ()
rpm-build 0f2925
      | Some e -> push t e
rpm-build 0f2925
rpm-build 0f2925
let fold f init t =
rpm-build 0f2925
  let acc = ref init in
rpm-build 0f2925
  let rec loop() =
rpm-build 0f2925
    acc := f (t.next()) !acc;
rpm-build 0f2925
    loop()
rpm-build 0f2925
  in
rpm-build 0f2925
  try
rpm-build 0f2925
    loop()
rpm-build 0f2925
  with
rpm-build 0f2925
    No_more_elements -> !acc
rpm-build 0f2925
rpm-build 0f2925
let foldi f init t =
rpm-build 0f2925
  let acc = ref init in
rpm-build 0f2925
  let rec loop idx =
rpm-build 0f2925
    acc := f idx (t.next()) !acc;
rpm-build 0f2925
    loop (idx + 1)
rpm-build 0f2925
  in
rpm-build 0f2925
  try
rpm-build 0f2925
    loop 0
rpm-build 0f2925
  with
rpm-build 0f2925
    No_more_elements -> !acc
rpm-build 0f2925
rpm-build 0f2925
let fold2 f init t u =
rpm-build 0f2925
  let acc = ref init in
rpm-build 0f2925
  let push_t = ref None in
rpm-build 0f2925
  let rec loop() =
rpm-build 0f2925
    push_t := None;
rpm-build 0f2925
    let e = t.next() in
rpm-build 0f2925
    push_t := Some e;
rpm-build 0f2925
    acc := f e (u.next()) !acc;
rpm-build 0f2925
    loop()
rpm-build 0f2925
  in
rpm-build 0f2925
  try
rpm-build 0f2925
    loop()
rpm-build 0f2925
  with
rpm-build 0f2925
    No_more_elements ->
rpm-build 0f2925
      match !push_t with
rpm-build 0f2925
      | None -> !acc
rpm-build 0f2925
      | Some e ->
rpm-build 0f2925
        push t e;
rpm-build 0f2925
        !acc
rpm-build 0f2925
rpm-build 0f2925
let fold2i f init t u =
rpm-build 0f2925
  let acc = ref init in
rpm-build 0f2925
  let push_t = ref None in
rpm-build 0f2925
  let rec loop idx =
rpm-build 0f2925
    push_t := None;
rpm-build 0f2925
    let e = t.next() in
rpm-build 0f2925
    push_t := Some e;
rpm-build 0f2925
    acc := f idx e (u.next()) !acc;
rpm-build 0f2925
    loop (idx + 1)
rpm-build 0f2925
  in
rpm-build 0f2925
  try
rpm-build 0f2925
    loop 0
rpm-build 0f2925
  with
rpm-build 0f2925
    No_more_elements ->
rpm-build 0f2925
      match !push_t with
rpm-build 0f2925
      | None -> !acc
rpm-build 0f2925
      | Some e ->
rpm-build 0f2925
        push t e;
rpm-build 0f2925
        !acc
rpm-build 0f2925
rpm-build 0f2925
let find f t =
rpm-build 0f2925
  let rec loop () =
rpm-build 0f2925
    let x = t.next() in
rpm-build 0f2925
    if f x then x else loop()
rpm-build 0f2925
  in
rpm-build 0f2925
  try
rpm-build 0f2925
    loop()
rpm-build 0f2925
  with
rpm-build 0f2925
    No_more_elements -> raise Not_found
rpm-build 0f2925
rpm-build 0f2925
let rec map f t =
rpm-build 0f2925
  {
rpm-build 0f2925
    count = t.count;
rpm-build 0f2925
    next = (fun () -> f (t.next()));
rpm-build 0f2925
    clone = (fun () -> map f (t.clone()));
rpm-build 0f2925
    fast = t.fast;
rpm-build 0f2925
  }
rpm-build 0f2925
rpm-build 0f2925
let rec mapi f t =
rpm-build 0f2925
  let idx = ref (-1) in
rpm-build 0f2925
  {
rpm-build 0f2925
    count = t.count;
rpm-build 0f2925
    next = (fun () -> incr idx; f !idx (t.next()));
rpm-build 0f2925
    clone = (fun () -> mapi f (t.clone()));
rpm-build 0f2925
    fast = t.fast;
rpm-build 0f2925
  }
rpm-build 0f2925
rpm-build 0f2925
let rec filter f t =
rpm-build 0f2925
  let rec next() =
rpm-build 0f2925
    let x = t.next() in
rpm-build 0f2925
    if f x then x else next()
rpm-build 0f2925
  in
rpm-build 0f2925
  from2 next (fun () -> filter f (t.clone()))
rpm-build 0f2925
rpm-build 0f2925
let rec filter_map f t =
rpm-build 0f2925
    let rec next () =
rpm-build 0f2925
        match f (t.next()) with
rpm-build 0f2925
        | None -> next()
rpm-build 0f2925
        | Some x -> x
rpm-build 0f2925
    in
rpm-build 0f2925
  from2 next (fun () -> filter_map f (t.clone()))
rpm-build 0f2925
rpm-build 0f2925
let rec append ta tb = 
rpm-build 0f2925
  let t = {
rpm-build 0f2925
    count = (fun () -> ta.count() + tb.count());
rpm-build 0f2925
    next = _dummy;
rpm-build 0f2925
    clone = (fun () -> append (ta.clone()) (tb.clone()));
rpm-build 0f2925
    fast = ta.fast && tb.fast;
rpm-build 0f2925
  } in
rpm-build 0f2925
  t.next <- (fun () ->
rpm-build 0f2925
    try
rpm-build 0f2925
      ta.next()
rpm-build 0f2925
    with
rpm-build 0f2925
      No_more_elements ->
rpm-build 0f2925
        (* add one indirection because tb can mute *)
rpm-build 0f2925
        t.next <- (fun () -> tb.next());
rpm-build 0f2925
        t.count <- (fun () -> tb.count());
rpm-build 0f2925
        t.clone <- (fun () -> tb.clone());
rpm-build 0f2925
        t.fast <- tb.fast;
rpm-build 0f2925
        t.next()
rpm-build 0f2925
  );
rpm-build 0f2925
  t
rpm-build 0f2925
rpm-build 0f2925
let rec concat t =
rpm-build 0f2925
  let concat_ref = ref _dummy in
rpm-build 0f2925
  let rec concat_next() =
rpm-build 0f2925
    let tn = t.next() in
rpm-build 0f2925
    concat_ref := (fun () ->
rpm-build 0f2925
      try
rpm-build 0f2925
        tn.next()
rpm-build 0f2925
      with
rpm-build 0f2925
        No_more_elements ->
rpm-build 0f2925
          concat_next());
rpm-build 0f2925
    !concat_ref ()
rpm-build 0f2925
  in
rpm-build 0f2925
  concat_ref := concat_next;
rpm-build 0f2925
  from2 (fun () -> !concat_ref ()) (fun () -> concat (t.clone()))