Merge branch 'local-ocamlbuild' into local-trunk
[SXSI/xpathcomp.git] / src / hlist.ml
diff --git a/src/hlist.ml b/src/hlist.ml
new file mode 100644 (file)
index 0000000..300c6a1
--- /dev/null
@@ -0,0 +1,101 @@
+INCLUDE "utils.ml"
+module type S = sig
+  type elt
+  type 'a node = Nil | Cons of elt * 'a
+
+  module rec Node :
+  sig
+    include Hcons.S with type data = Data.t
+  end
+  and Data : sig
+    include Hashtbl.HashedType with type t = Node.t node
+  end
+  type data = Data.t
+  type t = Node.t
+  val hash : t -> int
+  val uid : t -> Uid.t
+  val make : data -> t
+  val equal : t -> t -> bool
+  val nil : t
+  val node : t -> t node
+  val cons : elt -> t -> t
+  val hd : t -> elt
+  val tl : t -> t
+  val fold : (elt -> 'a -> 'a) -> t -> 'a -> 'a
+  val map : (elt -> elt) -> t -> t
+  val iter : (elt -> 'a) -> t -> unit
+  val rev : t -> t
+  val rev_map : (elt -> elt) -> t -> t
+  val length : t -> int
+  val mem : elt -> t -> bool
+
+end
+
+module Make (H : Hcons.SA) : S with type elt = H.t =
+struct
+  type elt = H.t
+  type 'a node = Nil | Cons of elt * 'a
+  module rec Node : Hcons.S with type data = Data.t = Hcons.Make (Data)
+  and Data : Hashtbl.HashedType  with type t = Node.t node =
+  struct
+    type t = Node.t node
+    let equal x y =
+      match x,y with
+       | _,_ when x==y -> true
+       | Cons (a,aa), Cons(b,bb) -> (aa==bb) && (H.equal a b)
+       | _ -> false
+    let hash = function
+      | Nil -> 0
+      | Cons(a,aa) -> HASHINT3(PRIME3,Uid.to_int (H.uid a),Uid.to_int( aa.Node.id))
+  end
+  type data = Data.t
+  type t = Node.t
+  let make = Node.make
+  let node x = x.Node.node
+  let hash x = x.Node.key
+  let equal = Node.equal
+  let uid x= x.Node.id
+  let nil = Node.make Nil
+
+  (* doing sorted insertion allows to make better use of hash consing *)
+  let rec cons e l =
+    match l.Node.node with
+      |        Nil -> Node.make (Cons(e, l))
+      | Cons (x, ll) ->
+         if H.uid e < H.uid x
+         then Node.make (Cons(e, l))
+         else Node.make (Cons(x, cons e ll))
+
+  let hd = function { Node.node = Cons(a,_) } -> a | _ -> failwith "hd"
+  let tl = function { Node.node = Cons(_,a) } -> a | _ -> failwith "tl"
+
+  let fold f l acc =
+    let rec loop acc l = match l.Node.node with
+      | Nil -> acc
+      | Cons (a, aa) -> loop (f a acc) aa
+    in
+      loop acc l
+
+  let map f l  =
+    let rec loop l = match l.Node.node with
+      | Nil -> nil
+      | Cons(a, aa) -> cons (f a) (loop aa)
+    in
+      loop l
+
+  let iter f l =
+    let rec loop l = match l.Node.node with
+      | Nil -> ()
+      | Cons(a,aa) ->  (f a);(loop aa)
+    in
+      loop l
+
+  let rev l = fold cons l nil
+  let rev_map f l = fold (fun x acc -> cons (f x) acc) l nil
+  let length l = fold (fun _ c -> c+1) l 0
+  let rec mem e l =
+    match l.Node.node with
+      | Nil -> false
+      | Cons (x, ll) -> x == e || mem e ll
+
+end