Random fixes
[SXSI/xpathcomp.git] / tree.ml
diff --git a/tree.ml b/tree.ml
index 780791a..7ea6f03 100644 (file)
--- a/tree.ml
+++ b/tree.ml
 (*  Copyright NICTA 2008                                                      *)
 (*  Distributed under the terms of the LGPL (see LICENCE)                     *)
 (******************************************************************************)
-INCLUDE "debug.ml"
-module type BINARY =
-sig
-  type node_content
-  type string_content
-  type descr = Nil | Node of node_content  |String of string_content 
-  type t
-  val parse_xml_uri : string -> t
-  val parse_xml_string : string -> t
-  val save : t -> string -> unit
-  val load : ?sample:int -> string -> t
-  val tag_pool : t -> Tag.pool
-  val string : t -> string
-  val descr : t -> descr
-  val is_node : t -> bool
-  val left : t -> t
-  val right : t -> t
-  val first_child : t -> t
-  val next_sibling : t -> t
-  val parent : t -> t
-  val root : t -> t
-  val is_root : t -> bool
-  val id : t -> int
-  val tag : t -> Tag.t
-  val print_xml_fast : out_channel -> t -> unit
-  val compare : t -> t -> int
-  val equal : t -> t -> bool
-  module DocIdSet :
-  sig 
-    include Set.S 
-  end
-    with type elt = string_content
-  val string_below : t -> string_content -> bool
-  val contains : t -> string -> DocIdSet.t
-  val contains_old : t -> string -> DocIdSet.t
-  val contains_iter : t -> string -> DocIdSet.t
-  val count_contains : t -> string -> int
-  val count : t -> string -> int
-  val dump : t -> unit
-  val get_string : t -> string_content -> string
-  val has_tagged_desc : t -> Tag.t -> bool
-  val has_tagged_foll : t -> Tag.t -> bool
-  val tagged_desc : t -> Tag.t -> t
-  val tagged_foll : t -> Tag.t -> t
-  val tagged_next : t -> Tag.t -> t
-  val subtree_tags : t -> Tag.t -> int
-  val is_left : t -> bool
-end
+INCLUDE "utils.ml"
 
-module XML = 
-struct
 
-  type t
-  type 'a node = int
-  type node_kind = [`Text | `Tree ]
+external init_lib : unit -> unit = "caml_init_lib"
 
-  let compare : 'a node -> 'a node -> int = (-)
-  let equal : 'a node -> 'a node -> bool = (==)
+exception CPlusPlusError of string
 
-        (* abstract type, values are pointers to a XMLTree C++ object *)
-    
-  external int_of_node : 'a node -> int = "%identity"
+let () = Callback.register_exception "CPlusPlusError" (CPlusPlusError "")
 
-  external parse_xml_uri : string -> int -> bool -> bool -> t = "caml_call_shredder_uri"         
-  external parse_xml_string :  string -> int -> bool -> bool -> t = "caml_call_shredder_string"
+let () =  init_lib ()
 
-  external save_tree : t -> string -> unit = "caml_xml_tree_save"
-  external load_tree : string -> int -> t = "caml_xml_tree_load"
 
+type tree
+type 'a node = private int
+type node_kind = [`Text | `Tree ]
 
-  module Text =
-  struct
-    let equal : [`Text] node -> [`Text] node -> bool = equal
-      
-    (* Todo *)
-    external nullt : unit -> [`Text ] node = "caml_xml_tree_nullt"
-    let nil = nullt ()
-    external get_text : t -> [`Text] node -> string = "caml_text_collection_get_text"
-
-(*    let get_text t n = 
-      if equal nil n then "" 
-      else  get_text t n
-*)
-               
-    external is_empty : t -> [`Text ] node -> bool = "caml_text_collection_empty_text"
-    let is_empty t n =
-      (equal nil n) || is_empty t n
+type t = { 
+  doc : tree;            
+  ttable : (Tag.t,(Ptset.Int.t*Ptset.Int.t*Ptset.Int.t*Ptset.Int.t)) Hashtbl.t;
+}
 
-    external get_cached_text : t -> [`Text ] node -> string = "caml_text_collection_get_cached_text"
-      
+external inode : 'a node -> int = "%identity"  
+external nodei : int -> 'a node = "%identity"  
+let compare_node x y = (inode x) - (inode y)
+let equal_node : 'a node -> 'a node -> bool = (==)
 
-    let get_text t n =
-      if (equal nil n) || is_empty t n then ""
-      else get_cached_text t n
+  
+external parse_xml_uri : string -> int -> bool -> bool -> tree = "caml_call_shredder_uri"         
+external parse_xml_string :  string -> int -> bool -> bool -> tree = "caml_call_shredder_string"
+external tree_print_xml_fast3 : tree -> [`Tree ] node -> Unix.file_descr ->unit = "caml_xml_tree_print"
+external tree_save : tree -> Unix.file_descr -> string -> unit = "caml_xml_tree_save"
+external tree_load : Unix.file_descr -> string -> bool -> int -> tree = "caml_xml_tree_load"
+  
+external nullt : unit -> 'a node = "caml_xml_tree_nullt"
 
-    external size : t -> int = "caml_text_collection_size"
-    external is_contains : t -> string -> bool = "caml_text_collection_is_contains"
-    external count_contains : t -> string -> int = "caml_text_collection_count_contains"
-    external count : t -> string -> int = "caml_text_collection_count"
-    external contains : t -> string -> [`Text ] node array = "caml_text_collection_contains"
-  end
+let nil : [`Tree ] node = nodei ~-1
+let nulldoc : [`Text ] node = nodei ~-1
+let root : [`Tree ] node = nodei 0
 
+external text_get_text : tree -> [`Text] node -> string = "caml_text_collection_get_text"              
+external text_is_empty : tree -> [`Text ] node -> bool = "caml_text_collection_empty_text" 
 
-  module Tree = 
-  struct
+let text_is_empty t n = (equal_node nulldoc n) || text_is_empty t n
 
-    let equal : [`Tree ] node -> [`Tree] node -> bool = equal
-    external serialize : t -> string -> unit = "caml_xml_tree_serialize"
-    external unserialize : string -> t = "caml_xml_tree_unserialize"
-      
-    external root : t -> [`Tree] node = "caml_xml_tree_root"
-    external nullt : unit -> [`Tree ] node = "caml_xml_tree_nullt"
+external text_is_prefix : tree -> string -> bool = "caml_text_collection_is_prefix" 
+external text_is_suffix : tree -> string -> bool = "caml_text_collection_is_suffix" 
+external text_is_equal : tree -> string -> bool = "caml_text_collection_is_equal" 
+external text_is_contains : tree -> string -> bool = "caml_text_collection_is_contains" 
+external text_is_lessthan : tree -> string -> bool = "caml_text_collection_is_lessthan" 
 
-    let nil = nullt ()
-    let is_nil x = equal x nil
+external text_count : tree -> string -> int = "caml_text_collection_count"
+external text_count_prefix : tree -> string -> int = "caml_text_collection_count_prefix"
+external text_count_suffix : tree -> string -> int = "caml_text_collection_count_suffix"
+external text_count_equal : tree -> string -> int = "caml_text_collection_count_equal"
+external text_count_contains : tree -> string -> int = "caml_text_collection_count_contains"
+external text_count_lessthan : tree -> string -> int = "caml_text_collection_count_lessthan"
 
-    external parent : t -> [`Tree] node -> [`Tree] node = "caml_xml_tree_parent"
-    external parent_doc : t -> [`Text ] node -> [`Tree ] node = "caml_xml_tree_parent_doc"
-    external first_child : t -> [`Tree] node -> [`Tree] node = "caml_xml_tree_first_child"
-      
+external text_prefix : tree -> string -> [`Text ] node array = "caml_text_collection_prefix"
+external text_suffix : tree -> string -> [`Text ] node array = "caml_text_collection_suffix"
+external text_equals : tree -> string -> [`Text ] node array = "caml_text_collection_equals"
+external text_contains : tree -> string -> [`Text ] node array = "caml_text_collection_contains"
+external text_lessthan : tree -> string -> [`Text ] node array = "caml_text_collection_lessthan"
 
-      
-    external next_sibling : t -> [`Tree] node -> [`Tree] node = "caml_xml_tree_next_sibling"
-
-    external is_leaf : t  -> [`Tree] node -> bool = "caml_xml_tree_is_leaf"
     
-(*    external tag : t -> [`Tree ] node -> T = "caml_xml_tree_tag"*)
-    external tag_id : t -> [`Tree ] node -> Tag.t = "caml_xml_tree_tag_id"
+external tree_root : tree -> [`Tree] node = "caml_xml_tree_root"  "noalloc"
+external tree_size : tree -> int = "caml_xml_tree_size" "noalloc"
+external tree_subtree_size : tree -> [`Tree] node -> int = "caml_xml_tree_subtree_size" "noalloc"
+external tree_subtree_elements : tree -> [`Tree] node -> int = "caml_xml_tree_subtree_elements" "noalloc"
+external tree_subtree_tags : tree -> [`Tree] node -> Tag.t -> int = "caml_xml_tree_subtree_elements" "noalloc"
 
-(*
-    let tag_hash = Hashtbl.create 4097
+let tree_is_nil x = equal_node x nil
+external tree_is_leaf : tree -> [`Tree ] node -> bool = "caml_xml_tree_is_leaf" "noalloc"
+external tree_is_ancestor : tree -> [`Tree ] node -> [`Tree ] node -> bool = "caml_xml_tree_is_ancestor" "noalloc"
+external tree_is_child : tree -> [`Tree ] node -> [`Tree ] node -> bool = "caml_xml_tree_is_child" "noalloc"
+external tree_is_first_child : tree -> [`Tree ] node -> bool = "caml_xml_tree_is_first_child" "noalloc"
+external tree_num_children : tree -> [`Tree ] node -> int = "caml_xml_tree_num_children" "noalloc"
+external tree_child_number : tree -> [`Tree ] node -> int = "caml_xml_tree_child_number" "noalloc"
+external tree_depth : tree -> [`Tree ] node -> int = "caml_xml_tree_depth" "noalloc"
+external tree_preorder : tree -> [`Tree ] node -> int = "caml_xml_tree_preorder" "noalloc"
+external tree_postorder : tree -> [`Tree ] node -> int = "caml_xml_tree_postorder" "noalloc"
+external tree_tag : tree -> [`Tree ] node -> Tag.t = "caml_xml_tree_tag" "noalloc"
+external tree_doc_ids : tree -> [`Tree ] node -> [`Text] node*[`Text] node = "caml_xml_tree_doc_ids"
 
-    let tag_id t id = 
-      try 
-       Hashtbl.find tag_hash id
-      with
-       | Not_found -> 
-           let tag = tag_id t id in
-             Hashtbl.add tag_hash id tag;tag
-*)
+external tree_parent : tree -> [`Tree] node -> [`Tree] node = "caml_xml_tree_parent" "noalloc"
+external tree_child : tree -> [`Tree] node -> int -> [`Tree] node = "caml_xml_tree_child" "noalloc"
+external tree_first_child : tree -> [`Tree] node -> [`Tree] node = "caml_xml_tree_first_child" "noalloc"
+external tree_first_element : tree -> [`Tree] node -> [`Tree] node = "caml_xml_tree_first_element" "noalloc"
+external tree_last_child : tree -> [`Tree] node -> [`Tree] node = "caml_xml_tree_last_child" "noalloc"
+external tree_next_sibling : tree -> [`Tree] node -> [`Tree] node = "caml_xml_tree_next_sibling"  "noalloc"
+external tree_next_element : tree -> [`Tree] node -> [`Tree] node = "caml_xml_tree_next_element"  "noalloc"
+external tree_prev_sibling : tree -> [`Tree] node -> [`Tree] node = "caml_xml_tree_prev_sibling" "noalloc"
+external tree_tagged_child : tree -> [`Tree] node -> Tag.t -> [`Tree] node = "caml_xml_tree_tagged_child" "noalloc" 
 
+type unordered_set
+external unordered_set_alloc : int -> unordered_set = "caml_unordered_set_alloc"
+external unordered_set_length : unordered_set -> int = "caml_unordered_set_length"
+external unordered_set_insert : unordered_set -> int -> unit = "caml_unordered_set_set" "noalloc"
 
-    let is_last t n = equal nil (next_sibling t n)
-    
-    external prev_text : t -> [`Tree] node -> [`Text ] node = "caml_xml_tree_prev_text" 
-
-
-    external my_text : t -> [`Tree] node -> [`Text ] node = "caml_xml_tree_my_text"
-    external next_text : t -> [`Tree] node -> [`Text ] node = "caml_xml_tree_next_text"
-
-    external text_xml_id : t -> [`Text ] node -> int = "caml_xml_tree_text_xml_id"
-    external node_xml_id : t -> [`Tree ] node -> int = "caml_xml_tree_node_xml_id"
-    external is_ancestor : t -> [`Tree ] node -> [`Tree ] node -> bool = "caml_xml_tree_is_ancestor"
-    external tagged_desc : t -> [`Tree ] node -> Tag.t -> [`Tree ] node = "caml_xml_tree_tagged_desc"
-    external tagged_foll : t -> [`Tree ] node -> Tag.t -> [`Tree ] node = "caml_xml_tree_tagged_foll"
-    external tagged_next : t -> [`Tree ] node -> Tag.t -> [`Tree ] node = "caml_xml_tree_tagged_next"
-    external subtree_tags : t -> [`Tree ] node -> Tag.t -> int = "caml_xml_tree_subtree_tags"
-
-    let print_skel t =
-      let rec aux id = 
-       if (is_nil id)
-       then Printf.eprintf "#\n"
-       else 
-         begin
-           Printf.eprintf "Node %i has tag '%s' DocOrder=%i, DocID of PrevText,MyText,NextText : (%i = %s,%i = %s,%i = %s) parent_doc(my_text)=%i\n%!" 
-             (int_of_node id)
-             (Tag.to_string (tag_id t id))
-             (node_xml_id t id)
-             (int_of_node (prev_text t id))
-             (Text.get_text t (prev_text t id))
-             (int_of_node (my_text t id))
-             (Text.get_text t (my_text t id))
-             (int_of_node (next_text t id))
-             (Text.get_text t (next_text t id))
-             (int_of_node(parent_doc t (my_text t id)));
-    
-           aux(first_child t id);
-           aux(next_sibling t id);
-         end
-      in
-       aux (root t)
+external tree_select_child : tree -> [`Tree ] node -> unordered_set -> [`Tree] node = "caml_xml_tree_select_child" "noalloc"
+external tree_tagged_following_sibling : tree -> [`Tree] node -> Tag.t -> [`Tree] node = "caml_xml_tree_tagged_following_sibling" "noalloc"
+external tree_select_following_sibling : tree -> [`Tree ] node -> unordered_set -> [`Tree] node = "caml_xml_tree_select_following_sibling" "noalloc"
+external tree_tagged_descendant : tree -> [`Tree ] node -> Tag.t -> [`Tree ] node = "caml_xml_tree_tagged_descendant" "noalloc"
+external tree_select_descendant : tree -> [`Tree ] node -> unordered_set -> [`Tree] node = "caml_xml_tree_select_descendant" "noalloc"
+external tree_tagged_following : tree -> [`Tree ] node -> Tag.t -> [`Tree ] node = "caml_xml_tree_tagged_following" "noalloc"
+external tree_tagged_following_below : tree -> [`Tree ] node -> Tag.t -> [`Tree ] node -> [`Tree ] node = "caml_xml_tree_tagged_following_below" "noalloc"
+external tree_select_following_below : tree -> [`Tree ] node -> unordered_set -> [`Tree] node -> [`Tree] node = "caml_xml_tree_select_following_below" "noalloc"
 
-    let traversal t = 
-       let rec aux id =
-         if not (is_nil id)
-         then
-           begin
-             (* ignore (tag t id);
-             ignore (Text.get_text t (prev_text t id));
-             if (is_leaf t id)
-               then ignore (Text.get_text t (my_text t id));
-             if (is_last t id)
-               then ignore (Text.get_text t (next_text t id)); *)
-             aux (first_child t id);
-             aux (next_sibling t id);
-           end
-       in
-         aux (root t)
-  end
-      
-      
-  module Binary  = struct
 
-    type node_content = 
-       NC of [`Tree ] node 
-      | SC of [`Text ] node * [`Tree ] node 
-    type string_content = [ `Text ] node
-    type descr = 
-      | Nil 
-      | Node of node_content
-      | String of string_content
+external tree_tagged_following_before : tree -> [`Tree ] node -> Tag.t -> [`Tree ] node -> [`Tree ] node = "caml_xml_tree_tagged_following_before" "noalloc"
+external tree_select_following_below : tree -> [`Tree ] node -> unordered_set -> [`Tree] node -> [`Tree] node = "caml_xml_tree_select_following_before" "noalloc"
 
-    type doc = t
+external tree_my_text : tree -> [`Tree ] node -> [`Text] node = "caml_xml_tree_my_text" "noalloc"
+external tree_my_text_unsafe : tree -> [`Tree ] node -> [`Text] node = "caml_xml_tree_my_text_unsafe" "noalloc"
+external tree_text_xml_id : tree -> [`Text ] node -> int = "caml_xml_tree_text_xml_id" "noalloc"
+external tree_node_xml_id : tree -> [`Tree ] node -> int = "caml_xml_tree_node_xml_id" "noalloc"
 
-    type t = { doc : doc;             
-              node : descr }
-       
-    let dump { doc=t } = Tree.print_skel t
-    module DocIdSet = struct
-      include Set.Make (struct type t = string_content
-                              let compare = (-) end)
-                       
-    end
-    let is_node = function { node=Node(_) } -> true | _ -> false
-      
-    let get_string t (i:string_content) = Text.get_text t.doc i
-    open Tree                 
-    let node_of_t t = { doc= t; 
-                       node = Node(NC (root t)) }
+external tree_parent_node : tree -> [`Text ] node -> [`Tree ] node = "caml_xml_tree_parent_node" "noalloc"
 
+(*external tree_prev_doc : tree -> [`Text ] node -> [`Tree ] node = "caml_xml_tree_prev_doc" "noalloc" *)
 
-    let parse_xml_uri str = node_of_t       
-      (MM((parse_xml_uri str 
-            !Options.sample_factor 
-            !Options.index_empty_texts
-            !Options.disable_text_collection),__LOCATION__))
+external tree_closing : tree -> [`Tree] node -> [`Tree] node = "caml_xml_tree_closing" "noalloc"
+external tree_is_open : tree -> [`Tree] node -> bool = "caml_xml_tree_is_open" "noalloc"
 
-    let parse_xml_string str = node_of_t 
-      (MM((parse_xml_string str
-        !Options.sample_factor 
-        !Options.index_empty_texts 
-        !Options.disable_text_collection),__LOCATION__))
 
+external benchmark_jump : tree -> Tag.t -> unit = "caml_benchmark_jump" "noalloc"
 
-    let save t str = save_tree t.doc str
+let benchmark_jump t s = benchmark_jump t.doc s
 
-    let load ?(sample=64) str = node_of_t (load_tree str sample)
+external benchmark_fcns : tree -> int = "caml_benchmark_fcns" "noalloc"
 
+let benchmark_fcns t = benchmark_fcns t.doc
 
-    external pool : doc -> Tag.pool = "%identity"
-    let tag_pool t = pool t.doc
+external benchmark_lcps : tree -> unit = "caml_benchmark_lcps" "noalloc"
 
-    let compare a b = match a.node,b.node  with
-      | Node(NC i),Node(NC j) -> compare i j
-      | _, Node(NC( _ )) -> 1
-      | Node(SC (i,_)),Node(SC (j,_)) -> compare i j
-      | Node(NC( _ )),Node(SC (_,_)) -> -1
-      | _, Node(SC (_,_)) -> 1
-      | String i, String j -> compare i j
-      | Node _ , String _ -> -1
-      | _ , String _ -> 1
-      | Nil, Nil -> 0
-      | _,Nil -> -1
+let benchmark_lcps t = benchmark_lcps t.doc
 
-    let equal a b = (compare a b) == 0
 
-    let string t = match t.node with
-      | String i ->  Text.get_text t.doc i
-      | _ -> assert false
-         
-    let norm (n : [`Tree ] node ) =  if is_nil n then Nil else Node (NC n)
-       
-    let descr t = t.node
-
-    let nts = function
-       Nil -> "Nil"
-      | String i -> Printf.sprintf "String %i" i
-      | Node (NC t) -> Printf.sprintf "Node (NC %i)"  (int_of_node t)
-      | Node (SC (t,i)) -> Printf.sprintf "Node (SC (%i,%i))"  (int_of_node t) (int_of_node i)
-
-
-    let root n = { n with node = norm (Tree.root n.doc) }
-    let is_root n = match n.node with
-      | Node(NC t) when (Tree.root n.doc) == t -> true
-      | _ -> false
-
-    let parent n = 
-      let node' =
-       match n.node with
-         |  Node(NC t) -> 
-              let txt = prev_text n.doc t in
-                if Text.is_empty n.doc txt then
-                  Node(NC (Tree.parent n.doc t))
-                else
-                  Node(SC (txt,t))
-         | Node(SC(t,_)) -> Node (NC(parent_doc n.doc t))
-         | _ -> failwith "parent"
-      in
-       { n with node = node' }
-
-    let first_child n = 
-      let node' = 
-       match n.node with
-         | Node (NC t) when is_leaf n.doc t ->
-             let txt = my_text n.doc t in
-               if Text.is_empty n.doc txt
-               then Nil
-               else Node(SC (txt,Tree.nil))
-         | Node (NC t) -> 
-             let fs = first_child n.doc t in
-             let txt = prev_text n.doc fs in
-               if Text.is_empty n.doc txt
-               then norm fs
-               else Node (SC (txt, fs))                  
-         | Node(SC (i,_)) -> String i
-         | Nil | String _ -> failwith "first_child"
-      in
-       { n with node = node'}
 
-         
-    let next_sibling n = 
-      let node' =
-       match n.node with
-         | Node (SC (_,ns)) -> norm ns
-         | Node(NC t) ->
-             let ns = next_sibling n.doc t in
-             let txt = next_text n.doc t in
-               if Text.is_empty n.doc txt
-               then norm ns
-               else Node (SC (txt, ns))
-         | Nil | String _  -> failwith "next_sibling"
-      in
-       { n with node = node'}
-         
-         
-    let left = first_child 
-    let right = next_sibling
-    
-    let id = 
-      function  { doc=d; node=Node(NC n)}  -> node_xml_id d n
-       | { doc=d;  node=Node(SC (i,_) )} -> text_xml_id d i
-       | _ -> failwith "id"
-           
-    let tag = 
-      function { node=Node(SC _) } -> Tag.pcdata
-       | { doc=d; node=Node(NC n)} -> tag_id d n
-       | _ -> failwith "tag"
-    
-(*    let tag_id = 
-      function  { node=Node(SC _) } -> ()
-       | { doc=d; node=Node(NC n)} -> tag_id d n
-       | _ -> ()
-*)
-    let string_below t id =
-      let strid = parent_doc t.doc id in
-       match t.node with
-         | Node(NC(i)) -> 
-             (Tree.equal i strid) || (is_ancestor t.doc i strid)
-         | Node(SC(i,_)) -> Text.equal i id
-         | _ -> false
-
-
-    let tagged_foll t tag =
-      if tag = Tag.attribute || tag = Tag.pcdata then failwith "tagged_foll"
-      else match t with
-       | { doc=d; node=Node(NC n) } -> { t with node = norm (tagged_foll d n tag) }
-       | { doc=d; node=Node(SC (_,n)) } when is_nil n -> { t with node= Nil } 
-       | { doc=d; node=Node(SC (_,n)) } ->
-           let nnode = 
-             if tag_id d n == tag then n
-             else 
-               let n' = tagged_desc d n tag in
-                 if is_nil n' then tagged_foll d n tag
-                 else n'
-           in {t with node= norm nnode}
-       | _ -> { t with node=Nil }
-           
 
-    let tagged_desc t tag =
-      if tag = Tag.attribute || tag = Tag.pcdata then failwith "tagged_desc"
-      else match t with
-       | { doc=d; node=Node(NC n) } -> { t with node = norm (tagged_desc d n tag) }
-       | _ -> { t with node=Nil }
 
 
-    let tagged_next t tag =
-      if tag = Tag.attribute || tag = Tag.pcdata then failwith "tagged_next"
-      else match t with
-       | { doc=d; node=Node(NC n) } -> { t with node = norm (tagged_next d n tag) }
-       | { doc=d; node=Node(SC (_,n)) } -> { t with node = norm (tagged_next d n tag) }
-       | _ -> { t with node=Nil }
 
-    let subtree_tags t tag =
-      match t with 
-         { doc = d; node = Node(NC n) } -> subtree_tags d n tag
-       | _ -> 0
+let text_size tree = inode (snd ( tree_doc_ids tree root ))
 
+let text_get_text t (x:[`Text] node) =
+  if x == nulldoc then ""
+  else text_get_text t x
 
 
-    let has_tagged_foll t tag = is_node (tagged_foll t tag)
-    let has_tagged_desc t tag = is_node (tagged_desc t tag)
 
-    let contains t s = 
-      Array.fold_left (fun a i -> DocIdSet.add i a) DocIdSet.empty (Text.contains t.doc s)
 
+module HPtset = Hashtbl.Make(Ptset.Int)
 
-    let contains_old t s = 
-      let regexp = Str.regexp_string s in
-      let matching arg = 
-       try
-         let _ = Str.search_forward regexp arg 0;
-         in true
-       with _ -> false
-      in
-      let rec find t acc = match t.node with
-       | Nil -> acc
-       | String i ->
-           if  matching (string t) then DocIdSet.add i acc else acc
-       | Node(_) ->  (find (left t )) ((find (right t))  acc)
-      in
-       find t DocIdSet.empty
+let vector_htbl = HPtset.create MED_H_SIZE
 
+let ptset_to_vector s =
+  try 
+    HPtset.find vector_htbl s
+  with
+      Not_found ->
+       let v = unordered_set_alloc (Ptset.Int.cardinal s) in
+       let _ = Ptset.Int.iter (fun e -> unordered_set_insert v e) s in
+         HPtset.add vector_htbl s v; v
 
-    let contains_iter t s = 
-      let regexp = Str.regexp_string s in
-      let matching arg = 
-       try
-         let _ = Str.search_forward regexp arg 0;
-         in true
-       with _ -> false
-      in
-      let size = Text.size t.doc in
-      let rec find acc n = 
-       if n == size then acc
-       else
-         find 
-           (if matching (Text.get_cached_text t.doc (Obj.magic n)) then 
-            DocIdSet.add (Obj.magic n) acc
-          else acc) (n+1)
-      in
-       find DocIdSet.empty 0
+      
 
+let subtree_size t i = tree_subtree_size t.doc i
+let subtree_elements t i = tree_subtree_elements t.doc i
+let text_size t = text_size t.doc
+
+module MemUnion = Hashtbl.Make (struct 
+      type t = Ptset.Int.t*Ptset.Int.t
+      let equal (x,y) (z,t) = x == z && y == t
+      let equal a b = equal a b || equal b a
+      let hash (x,y) =   (* commutative hash *)
+       let x = Uid.to_int (Ptset.Int.uid x)
+       and y = Uid.to_int (Ptset.Int.uid y)
+       in
+       if x <= y then HASHINT2(x,y) else HASHINT2(y,x)
+    end)
+
+module MemAdd = Hashtbl.Make (
+  struct 
+    type t = Tag.t*Ptset.Int.t
+    let equal (x,y) (z,t) = (x == z)&&(y == t)
+    let hash (x,y) =  HASHINT2(x,Uid.to_int  (Ptset.Int.uid y))
+  end)
+
+module MemUpdate = struct
+include  Hashtbl.Make (
+    struct 
+      type t = Tag.t*Ptset.Int.t*Ptset.Int.t*Ptset.Int.t*Ptset.Int.t
+      let equal (a1,b1,c1,d1,e1)  (a2,b2,c2,d2,e2) = a1==a2 &&
+       b1 == b2 && c1 == c2 && d1 == d2 && e1 == e2
+      let hash (a,b,c,d,e) =  
+       HASHINT4(HASHINT2(a,Uid.to_int (Ptset.Int.uid b)),
+                Uid.to_int (Ptset.Int.uid c),
+                Uid.to_int (Ptset.Int.uid d),
+                Uid.to_int (Ptset.Int.uid e))
+    end)
 
+end
 
+let collect_tags tree =
+  let _ = Printf.eprintf "Collecting Tags\n%!" in
+  let h_union = MemUnion.create BIG_H_SIZE in
+  let pt_cup s1 s2 =
+      try
+       MemUnion.find h_union (s1,s2)
+      with
+       | Not_found -> let s = Ptset.Int.union s1 s2
+         in
+           MemUnion.add h_union (s1,s2) s;s
+  in    
+  let h_add = MemAdd.create BIG_H_SIZE in
+  let pt_add t s =  
+    try MemAdd.find h_add (t,s)
+    with
+      | Not_found -> let r = Ptset.Int.add t s in
+         MemAdd.add h_add (t,s) r;r
+  in 
+  let h = Hashtbl.create BIG_H_SIZE in
+  let update t sc sb ss sa = 
+    let schild,sbelow,ssibling,safter =  
+      try
+       Hashtbl.find h t 
+      with
+       | Not_found -> 
+           (Ptset.Int.empty,Ptset.Int.empty,Ptset.Int.empty,Ptset.Int.empty)
+    in
+      Hashtbl.replace h t 
+       (pt_cup sc schild,pt_cup sbelow sb, pt_cup ssibling ss, pt_cup safter sa) 
+  in
+  let rec loop right id acc_after = 
+    if  id == nil
+    then Ptset.Int.empty,Ptset.Int.empty,acc_after else
+    let sibling2,desc2,after2 = loop true (tree_next_sibling tree id) acc_after in
+    let child1,desc1,after1   = loop false (tree_first_child tree id) after2  in
+    let tag = tree_tag tree id in
+    update tag child1 desc1 sibling2 after2;
+    ( pt_add tag sibling2, 
+      pt_add tag (pt_cup desc1 desc2),
+      if right then pt_cup after1 (pt_cup desc1 desc2) else acc_after )
+  in
+  let _ = loop false (tree_root tree) Ptset.Int.empty in 
+  let _ = Printf.eprintf "Finished\n%!" in
+    h
+
+
+
+
+let contains_array = ref [| |]
+let contains_index = Hashtbl.create 4096 
+let in_array _ i =
+  try
+    Hashtbl.find contains_index i
+  with
+      Not_found -> false
+
+let init_textfun f t s = 
+  let a = match f with 
+    | `CONTAINS -> text_contains t.doc s 
+    | `STARTSWITH -> text_prefix t.doc s 
+    | `ENDSWITH -> text_suffix t.doc s 
+    | `EQUALS -> text_equals t.doc s 
+  in
+    (*Array.fast_sort (compare) a; *)
+    contains_array := a;
+    Array.iter (fun x -> Hashtbl.add contains_index x true) !contains_array
+      
+let count_contains t s = text_count_contains t.doc s
+
+let init_naive_contains t s =
+  let i,j = tree_doc_ids t.doc (tree_root t.doc)
+  in
+  let regexp = Str.regexp_string s in
+  let matching arg = 
+    try
+      let _ = Str.search_forward regexp arg 0;
+      in true
+    with _ -> false
+  in
+  let rec loop n acc l = 
+    if n >= j then acc,l
+    else
+      let s = text_get_text t.doc n
+      in
+       if matching s 
+       then loop (nodei ((inode n)+1)) (n::acc) (l+1) 
+       else loop (nodei ((inode n)+1)) acc l
+  in
+  let acc,l = loop i [] 0 in
+  let a = Array.create l nulldoc in
+  let _ = List.fold_left (fun cpt e -> a.(cpt) <- e; (cpt-1)) (l-1) acc
+  in
+    contains_array := a
+
+let last_idx = ref 0
+
+let array_find a i j =
+  let l = Array.length a in
+  let rec loop idx x y =
+    if x > y || idx >= l then nulldoc
+       else
+         if a.(idx) >= x then if a.(idx) > y then nulldoc else (last_idx := idx;a.(idx))
+         else loop (idx+1) x y
+  in
+    if a.(0) > j || a.(l-1) < i then nulldoc
+    else loop !last_idx i j 
+         
+let text_below tree t = 
+  let l = Array.length !contains_array in
+  let i,j = tree_doc_ids tree.doc t in
+  let id = if l == 0 then i else (array_find !contains_array i j) in
+  tree_parent_node tree.doc id
+    
+let text_next tree t root =
+  let l = Array.length !contains_array in
+  let inf = nodei((inode(snd(tree_doc_ids tree.doc t)))+1) in    
+  let _,j = tree_doc_ids tree.doc root in      
+  let id = if l == 0 then if inf > j then nulldoc else  inf
+  else array_find !contains_array inf j
+  in 
+  tree_parent_node tree.doc id
 
-    let count_contains t s =   Text.count_contains t.doc s
-    let count t s =   Text.count t.doc s
 
-    let is_left t =
-      let u = left (parent t) in
-       (id t) == (id u)
 
-    let print_xml_fast outc t =
-      let rec loop ?(print_right=true) t = match t.node with 
-       | Nil -> ()
-       | String (s) -> output_string outc (string t)
-       | Node _ when Tag.equal (tag t) Tag.pcdata -> 
-           loop (left t); 
-           if print_right then loop (right t)
-           
-       | Node (_) -> 
-           let tg = Tag.to_string (tag t) in
-           let l = left t 
-           and r = right t 
-           in
-             output_char outc  '<';
-             output_string outc  tg;
-             ( match l.node with
-                   Nil -> output_string outc  "/>"
-                 | String _ -> assert false
-                 | Node(_) when Tag.equal (tag l) Tag.attribute -> 
-                     (loop_attributes (left l);
-                      match (right l).node with
-                        | Nil -> output_string outc  "/>"
-                        | _ -> 
-                            output_char outc  '>'; 
-                            loop (right l);
-                            output_string outc  "</";
-                            output_string outc  tg;
-                            output_char outc '>' )
-                 | _ ->
-                     output_char outc  '>'; 
-                     loop l;
-                     output_string outc "</";
-                     output_string outc tg;
-                     output_char outc '>'
-             );if print_right then loop r
-      and loop_attributes a =
-
-       match a.node with 
-         | Node(_) ->
-             let value =
-               match (left a).node with
-                 | Nil -> ""
-                 | _ -> string (left(left a)) 
-             in
-               output_char outc ' ';
-               output_string outc (Tag.to_string (tag a));
-               output_string outc "=\"";
-               output_string outc value;
-               output_char outc '"';
-               loop_attributes (right a)
-       | _ -> ()
-      in
-       loop ~print_right:false t
+module DocIdSet = struct
+  include Set.Make (struct type t = [`Text] node
+                          let compare = compare_node end)
+    
+end
+let is_nil t = t == nil
+
+let is_node t = t != nil
+let is_root t = t == root
+
+let node_of_t t  =
+  let _ = Tag.init (Obj.magic t) in
+  let table = collect_tags t 
+  in (*
+  let _ = Hashtbl.iter (fun t (c,d,ns,f) ->
+                         Printf.eprintf "Tag %s has:\n" (Tag.to_string t);
+                         Printf.eprintf "Child tags: ";
+                         Ptset.Int.iter (fun t -> Printf.eprintf "%s "(Tag.to_string t)) c;
+                         Printf.eprintf "\nDescendant tags: ";
+                         Ptset.Int.iter (fun t -> Printf.eprintf "%s "(Tag.to_string t)) d;
+                         Printf.eprintf "\nNextSibling tags: ";
+                         Ptset.Int.iter (fun t -> Printf.eprintf "%s "(Tag.to_string t)) ns;
+                         Printf.eprintf "\nFollowing tags: ";
+                         Ptset.Int.iter (fun t -> Printf.eprintf "%s "(Tag.to_string t)) f;
+                         Printf.eprintf "\n\n%!";) table
+  in
+                         
+     *)                          
+    { doc= t; 
+      ttable = table;
+    }
+
+let finalize _ = Printf.eprintf "Release the string list !\n%!"
+;;
+
+let parse f str =
+  node_of_t
+    (f str 
+       !Options.sample_factor 
+       !Options.index_empty_texts
+       !Options.disable_text_collection)
+    
+let parse_xml_uri str = parse parse_xml_uri str
+let parse_xml_string str =  parse parse_xml_string str
+
+let size t = tree_size t.doc;;
+     
+external pool : tree -> Tag.pool = "%identity"
+
+let magic_string = "SXSI_INDEX"
+let version_string = "2"
+
+let pos fd =
+  Unix.lseek fd 0  Unix.SEEK_CUR
+
+let pr_pos fd = Printf.eprintf "At position %i\n%!" (pos fd)
+
+let write fd s = 
+  let sl = String.length s in
+  let ssl = Printf.sprintf "%020i" sl in
+    ignore (Unix.write fd ssl 0 20);
+    ignore (Unix.write fd s 0 (String.length s))
+
+let rec really_read fd buffer start length =
+  if length <= 0 then () else
+    match Unix.read fd buffer start length with
+       0 -> raise End_of_file
+      | r -> really_read fd buffer (start + r) (length - r);;
+
+let read fd =
+  let buffer = String.create 20 in
+  let _ =  really_read fd buffer 0 20 in
+  let size = int_of_string buffer in
+  let buffer = String.create size in
+  let _ =  really_read fd buffer 0 size in
+    buffer
+    
 
+let save t str =
+  let fd = Unix.openfile str [ Unix.O_WRONLY;Unix.O_TRUNC;Unix.O_CREAT] 0o644 in
+  let out_c = Unix.out_channel_of_descr fd in
+  let _ = set_binary_mode_out out_c true in
+    output_string out_c magic_string;
+    output_char out_c '\n';
+    output_string out_c version_string;
+    output_char out_c '\n';
+    Marshal.to_channel out_c t.ttable [ ];
+    (* we need to move the fd to the correct position *)
+    flush out_c;
+    ignore (Unix.lseek fd (pos_out out_c) Unix.SEEK_SET);
+    tree_save t.doc fd str;
+    close_out out_c
+;;
+
+let load ?(sample=64) ?(load_text=true) str = 
+  let fd = Unix.openfile str [ Unix.O_RDONLY ] 0o644 in
+  let in_c = Unix.in_channel_of_descr fd in
+  let _ = set_binary_mode_in in_c true in
+  let load_table () = 
+    (let ms = input_line in_c in if ms <> magic_string then failwith "Invalid index file");
+    (let vs = input_line in_c in if vs <> version_string then failwith "Invalid version file");
+    let table : (Tag.t,(Ptset.Int.t*Ptset.Int.t*Ptset.Int.t*Ptset.Int.t)) Hashtbl.t =
+      Marshal.from_channel in_c 
+    in
+    let ntable = Hashtbl.create (Hashtbl.length table) in
+      Hashtbl.iter (fun k (s1,s2,s3,s4) -> 
+                     let ss1 = Ptset.Int.fold (Ptset.Int.add) s1 Ptset.Int.empty
+                     and ss2 = Ptset.Int.fold (Ptset.Int.add) s2 Ptset.Int.empty
+                     and ss3 = Ptset.Int.fold (Ptset.Int.add) s3 Ptset.Int.empty
+                     and ss4 = Ptset.Int.fold (Ptset.Int.add) s4 Ptset.Int.empty
+                     in Hashtbl.add ntable k (ss1,ss2,ss3,ss4)
+                  ) table;
+      Hashtbl.clear table;
+      (* The in_channel read a chunk of fd, so we might be after
+        the start of the XMLTree save file. Reset to the correct
+        position *)
+      ntable
+  in
+  let _ = Printf.eprintf "\nLoading tag table : " in
+  let ntable = time (load_table) () in
+  ignore(Unix.lseek fd (pos_in in_c) Unix.SEEK_SET);
+  let tree = { doc = tree_load fd str load_text sample;
+              ttable = ntable;}
+  in close_in in_c;
+  tree
+  
+
+
+
+let tag_pool t = pool t.doc
+  
+let compare = compare_node
+
+let equal a b = a == b
+   
+let nts = function
+    -1 -> "Nil"
+  | i -> Printf.sprintf "Node (%i)"  i
+      
+let dump_node t = nts (inode t)
 
-    let print_xml_fast outc t = 
-      if Tag.to_string (tag t) = "" then
-       print_xml_fast outc (first_child t)
-      else print_xml_fast outc t
-       
-    let traversal t = Tree.traversal t.doc
-    let full_traversal t = 
-      let rec aux n =
-       match n.node with
-       | Nil -> ()
-       | String i -> () (*ignore(Text.get_text t.doc i)  *)
-       | Node(_) -> 
-           (* tag_id n; *)
-           aux (first_child n);
-           aux (next_sibling n)
-      in aux t
-
-    let print_stats _ = ()
-  end
+let is_left t n = tree_is_first_child t.doc n
 
-end
 
 
+let is_below_right t n1 n2 = 
+  tree_is_ancestor t.doc (tree_parent t.doc n1) n2 
+  && not (tree_is_ancestor t.doc n1 n2)
 
-IFDEF DEBUG
-THEN
-module DEBUGTREE 
-  = struct
-    
-    let _timings = Hashtbl.create 107
+let is_binary_ancestor t n1 n2 =
+  let p = tree_parent t.doc n1 in
+  let fin = tree_closing t.doc p in
+  n2 > n1 && n2 < fin
+(*  (is_below_right t n1 n2) ||
+    (tree_is_ancestor t.doc n1 n2) *)
     
+let parent t n = tree_parent t.doc n
 
-    let time _ref f arg = 
-      let t1 = Unix.gettimeofday () in
-      let r = f arg in
-      let t2 = Unix.gettimeofday () in 
-      let t = (1000. *.(t2 -. t1)) in
+let first_child t = let doc = t.doc in ();fun n -> tree_first_child doc n
+let first_element t = let doc = t.doc in (); fun n -> tree_first_element doc n
 
-      let (time,count) = try 
-       Hashtbl.find _timings _ref
-      with
-       | Not_found -> 0.,0
-      in
-      let time = time+. t 
-      and count = count + 1
-      in
-       Hashtbl.replace _timings _ref (time,count);r
+(* these function will be called in two times: first partial application
+   on the tag, then application of the tag and the tree, then application of
+   the other arguments. We use the trick to let the compiler optimize application
+*)
 
-    include XML.Binary
+let tagged_child t tag = () ; fun n -> tree_tagged_child t.doc n tag
 
+let select_child t = fun ts ->
+  let v = ptset_to_vector ts in ();
+    fun n -> tree_select_child t.doc n v
 
-    let first_child_ doc node = 
-     time ("XMLTree.FirstChild()") (XML.Tree.first_child doc)  node
-    let next_sibling_ doc node = 
-      time ("XMLTree.NextSibling()") (XML.Tree.next_sibling doc) node
+let next_sibling t = let doc = t.doc in (); fun n ->  tree_next_sibling doc n
+let next_element t = let doc = t.doc in (); fun n ->  tree_next_element doc n
 
-    let is_empty_ text node = 
-      time ("TextCollection.IsEmpty()") (XML.Text.is_empty text) node
+let tagged_following_sibling t tag = (); fun n -> tree_tagged_following_sibling t.doc n tag
 
-    let prev_text_ doc node = 
-      time ("XMLTree.PrevText()") (XML.Tree.prev_text doc) node
+let select_following_sibling t = fun ts ->
+  let v = (ptset_to_vector ts) in ();
+    fun n -> tree_select_following_sibling t.doc n v
 
-    let my_text_ doc node = 
-      time ("XMLTree.MyText()") (XML.Tree.my_text doc) node
-       
-    let next_text_ doc node = 
-      time ("XMLTree.NextText()") (XML.Tree.next_text doc) node
+let next_sibling_below t = (); fun n _ -> tree_next_sibling t.doc n
+let next_element_below t = (); fun n _ -> tree_next_element t.doc n
 
-    let is_leaf_ doc node =  
-      time ("XMLTree.IsLeaf()") (XML.Tree.is_leaf doc ) node
-       
-    let node_xml_id_ doc node =  
-      time ("XMLTree.NodeXMLId()") (XML.Tree.node_xml_id doc ) node
+let tagged_following_sibling_below t tag = (); fun n  _ -> tree_tagged_following_sibling t.doc n tag
+
+let select_following_sibling_below t = fun ts -> 
+  let v = (ptset_to_vector ts) in ();
+     fun n  _ -> tree_select_following_sibling t.doc n v
+
+let id t n = tree_node_xml_id t.doc n
        
-    let text_xml_id_ doc node =  
-      time ("XMLTree.TextXMLId()") (XML.Tree.text_xml_id doc ) node
-
-
-    let first_child n =
-      let node' =
-       match n.node with
-         | Node (NC t) when is_leaf_ n.doc t ->
-             let txt = my_text_ n.doc t in
-               if is_empty_ n.doc txt
-               then Nil
-               else Node(SC (txt,XML.Tree.nil))
-         | Node (NC t) ->
-             let fs = first_child_ n.doc t in
-             let txt = prev_text_ n.doc fs in
-               if is_empty_ n.doc txt
-               then norm fs
-               else Node (SC (txt, fs))
-         | Node(SC (i,_)) -> String i
-         | Nil | String _ -> failwith "first_child"
-      in
-       { n with node = node'}
+let tag t n = if n == nil then Tag.nullt else tree_tag t.doc n
 
-         
-    let next_sibling n =
-      let node' =
-       match n.node with
-         | Node (SC (_,ns)) -> norm ns
-         | Node(NC t) ->
-             let ns = next_sibling_ n.doc t in
-             let txt = 
-               if XML.Tree.is_nil ns then
-                 next_text_ n.doc t 
-               else prev_text_ n.doc ns
-             in
-               if is_empty_ n.doc txt
-               then norm ns
-               else Node (SC (txt, ns))
-         | Nil | String _  -> failwith "next_sibling"
-      in
-       { n with node = node'}
-
-    let id = 
-      function  { doc=d; node=Node(NC n)}  -> node_xml_id_ d n
-       | { doc=d;  node=Node(SC (i,_) )} -> text_xml_id_ d i
-       | _ -> failwith "id"
-           
-    (* Wrapper around critical function *)
-    let string t = time ("TextCollection.GetText()") (string) t
-    let left = first_child
-    let right = next_sibling
-    let tag t =  time ("XMLTree.GetTag()") (tag) t
-      
-    let print_stats ppf = 
-      let total_time,total_calls =
-       Hashtbl.fold  (fun _ (t,c) (tacc,cacc) ->
-                        tacc+. t, cacc + c)  _timings (0.,0)
+let tagged_descendant t tag = 
+  let doc = t.doc in (); fun n -> tree_tagged_descendant doc n tag 
 
-      in
-       Format.fprintf ppf
-         "Timing : Function Name, number of calls,%% of total calls, mean time, total time, %% of total time\n%!";
-       Hashtbl.iter (fun name (time,count) ->
-                       Format.fprintf ppf  "%-27s% 8d\t% 4.2f%%\t% 4.6f ms\t% 4.6f ms\t%04.2f%%\n%!"
-                         name 
-                         count 
-                         (100. *. (float_of_int count)/.(float_of_int total_calls))
-                         (time /. (float_of_int count))
-                         time
-                         (100. *. time /.  total_time)) _timings;
-       Format.fprintf ppf  "-------------------------------------------------------------------\n";
-       Format.fprintf ppf "%-27s% 8d\t% 4.0f%%\t########## ms\t% 4.6f ms\t% 4.0f%%\n%!"
-         "Total" total_calls 100. total_time 100.
-                         
+let select_descendant t = fun ts -> 
+  let v = (ptset_to_vector ts) in ();
+    fun n -> tree_select_descendant t.doc n v
+
+let tagged_following_below  t tag =
+  let doc = t.doc in
+  (); fun n ctx -> tree_tagged_following_below doc n tag ctx
+
+let select_following_below t = fun ts ->
+  let v = (ptset_to_vector ts) in ();
+    fun n ctx -> tree_select_following_below t.doc n v ctx
 
-    let print_xml_fast outc t =
-      let rec loop ?(print_right=true) t = match t.node with 
-       | Nil -> ()
-       | String (s) -> output_string outc (string t)
-       | Node _ when Tag.equal (tag t) Tag.pcdata -> loop (left t); loop (right t)
-           
-       | Node (_) -> 
-           let tg = Tag.to_string (tag t) in
-           let l = left t 
-           and r = right t 
+let closing t n = tree_closing t.doc n
+let is_open t n = tree_is_open t.doc n
+let get_text_id t n = tree_my_text t.doc n
+
+let last_idx = ref 0
+let array_find a i j =
+  let l = Array.length a in
+  let rec loop idx x y =
+    if x > y || idx >= l then nil
+       else
+         if a.(idx) >= x then if a.(idx) > y then nil else (last_idx := idx;a.(idx))
+         else loop (idx+1) x y
+  in
+    if a.(0) > j || a.(l-1) < i then nil
+    else loop !last_idx i j 
+
+
+
+  let count t s = text_count t.doc s
+  let stack = ref []
+  let init_stack () = stack := []
+  let push x = stack:= x::!stack
+  let peek () = match !stack with 
+     p::_ -> p
+    | _ -> failwith "peek"
+  let pop () = match !stack with
+     p::r -> stack:=r; p
+    | _ -> failwith "pop"
+
+  let next t = nodei ( (inode t) + 1 ) 
+  let next2 t = nodei ( (inode t) + 2 ) 
+  let next3 t = nodei ( (inode t) + 3 ) 
+    
+  let print_xml_fast2  =
+    let _ = init_stack () in
+    let h = Hashtbl.create MED_H_SIZE in    
+    let tag_str t = try Hashtbl.find h t with
+       Not_found -> let s = Tag.to_string t in
+       Hashtbl.add h t s;s
+    in
+    let h_att = Hashtbl.create MED_H_SIZE in    
+    let att_str t = try Hashtbl.find h_att t with
+       Not_found -> let s = Tag.to_string t in
+      let attname = String.sub s 3 ((String.length s) -3) in
+      Hashtbl.add h_att t attname;attname
+    in fun outc tree t ->
+      let tree = tree.doc in
+      let fin = tree_closing tree t in
+      let rec loop_tag t tag =
+       if t <= fin then
+       if tree_is_open tree t then
+       (* opening tag *)
+       if tag == Tag.pcdata then 
+       begin
+         output_string outc (text_get_text tree (tree_my_text_unsafe tree t));
+         loop (next2 t) (* skip closing $ *)
+       end
+       else
+       let tagstr = tag_str tag in
+       let _ = output_char outc '<';    
+       output_string outc tagstr in
+       let t' = next t in
+       if tree_is_open tree t' then
+       let _ = push tagstr in
+       let tag' = tree_tag tree t' in
+       if tag' == Tag.attribute then let t'' = loop_attr (next t') 0 in 
+       output_string outc ">"; loop t'' else (output_string outc ">";loop_tag t' tag')
+       else (* closing with no content *)
+       let _ = output_string outc "/>" in
+       loop (next t')
+       else
+       begin
+       (* closing tag *)
+         output_string outc "</";
+         output_string outc (pop());
+         output_char outc '>';
+         loop (next t);
+       end
+      and loop t = loop_tag t (tree_tag tree t)
+      and loop_attr t n = 
+       if tree_is_open tree t then 
+       let attname = att_str (tree_tag tree t) in
+       output_char outc ' ';
+       output_string outc attname;
+       output_string outc "=\"";
+       let t = next t in (* open $@ *)
+       output_string outc (text_get_text tree (tree_my_text_unsafe tree t));
+       output_char outc '"';
+       loop_attr (next3 t) (n+1)
+       else
+       next t (* close @ *)
+      in loop t
+
+  let print_xml_fast  =
+    let h = Hashtbl.create MED_H_SIZE in    
+    let tag_str t = try Hashtbl.find h t with
+       Not_found -> let s = Tag.to_string t in
+       Hashtbl.add h t s;s
+    in
+    let h_att = Hashtbl.create MED_H_SIZE in    
+    let att_str t = try Hashtbl.find h_att t with
+       Not_found -> let s = Tag.to_string t in
+      let attname = String.sub s 3 ((String.length s) -3) in
+      Hashtbl.add h_att t attname;attname
+    in fun outc tree t ->
+    let rec loop ?(print_right=true) t = 
+      if t != nil 
+      then 
+       let tagid = tree_tag tree.doc t in
+         if tagid==Tag.pcdata
+         then 
+           begin
+             let tid =  tree_my_text_unsafe tree.doc t in
+             output_string outc (text_get_text tree.doc tid);
+             if print_right
+             then loop (next_sibling tree t);
+           end
+         else
+           let tagstr = tag_str tagid in
+           let l = first_child tree t 
+           and r = next_sibling tree t 
            in
              output_char outc  '<';
-             output_string outc  tg;
-             ( match l.node with
-                   Nil -> output_string outc  "/>"
-                 | String _ -> assert false
-                 | Node(_) when Tag.equal (tag l) Tag.attribute -> 
-                     (loop_attributes (left l);
-                      match (right l).node with
-                        | Nil -> output_string outc  "/>"
-                        | _ -> 
-                            output_char outc  '>'; 
-                            loop (right l);
-                            output_string outc  "</";
-                            output_string outc  tg;
-                            output_char outc '>' )
-                 | _ ->
-                     output_char outc  '>'; 
-                     loop l;
-                     output_string outc "</";
-                     output_string outc tg;
-                     output_char outc '>'
-             );if print_right then loop r
-      and loop_attributes a =
-
-       match a.node with 
-         | Node(_) ->
-             let value =
-               match (left a).node with
-                 | Nil -> ""
-                 | _ -> string (left(left a)) 
-             in
-               output_char outc ' ';
-               output_string outc (Tag.to_string (tag a));
-               output_string outc "=\"";
-               output_string outc value;
-               output_char outc '"';
-               loop_attributes (right a)
-       | _ -> ()
-      in
+             output_string outc tagstr;
+             if l == nil then output_string outc  "/>"
+             else 
+               if (tag tree l) == Tag.attribute then
+                 begin
+                   loop_attributes (first_child tree l);
+                   if (next_sibling tree l) == nil then output_string outc  "/>"
+                   else  
+                     begin 
+                       output_char outc  '>'; 
+                       loop (next_sibling tree l);
+                       output_string outc  "</";
+                       output_string outc  tagstr;
+                       output_char outc '>';
+                     end;
+                 end
+               else
+                 begin
+                   output_char outc  '>'; 
+                   loop l;
+                   output_string outc "</";
+                   output_string outc tagstr;
+                   output_char outc '>';
+                 end;
+             if print_right then loop r
+    and loop_attributes a = 
+      if a != nil
+      then
+      let attname = att_str (tag tree a) in
+      let fsa = first_child tree a in
+      let tid =  tree_my_text_unsafe tree.doc fsa in
+       output_char outc ' ';
+       output_string outc attname;
+       output_string outc "=\"";
+       output_string outc (text_get_text tree.doc tid);
+       output_char outc '"';
+       loop_attributes (next_sibling tree a)
+    in
        loop ~print_right:false t
+         
+         
+    let print_xml_fast outc tree t = 
+      if (tag tree t) = Tag.document_node then
+       print_xml_fast outc tree (first_child tree t)
+      else print_xml_fast outc tree t 
+       
+let tags_children t tag = 
+  let a,_,_,_ = Hashtbl.find t.ttable tag in a
+let tags_below t tag = 
+  let _,a,_,_ = Hashtbl.find t.ttable tag in a
+let tags_siblings t tag = 
+  let _,_,a,_ = Hashtbl.find t.ttable tag in a
+let tags_after t tag = 
+  let _,_,_,a = Hashtbl.find t.ttable tag in a
+
+
+let tags t tag = Hashtbl.find t.ttable tag
+
+
+let rec binary_parent t n = 
+  let r = 
+  if tree_is_first_child t.doc n
+  then tree_parent t.doc n
+  else tree_prev_sibling t.doc n
+  in if tree_tag t.doc r = Tag.pcdata then
+  binary_parent t r
+  else r
+
+let doc_ids t n = tree_doc_ids t.doc n
+
+let subtree_tags t tag = ();
+  fun n -> if n == nil then 0 else
+    tree_subtree_tags t.doc n tag
+
+let get_text t n =
+  let tid = tree_my_text t.doc n in
+    if tid == nulldoc then "" else 
+      text_get_text t.doc tid
+
+
+let dump_tree fmt tree = 
+  let rec loop t n =
+    if t != nil then
+      let tag = (tree_tag tree.doc t ) in
+      let tagstr = Tag.to_string tag in
+       let tab = String.make n ' ' in
+
+         if tag == Tag.pcdata || tag == Tag.attribute_data 
+         then 
+           Format.fprintf fmt "%s<%s>%s</%s>\n" 
+             tab tagstr (text_get_text tree.doc (tree_my_text tree.doc t)) tagstr
+         else begin
+           Format.fprintf fmt "%s<%s>\n" tab tagstr;
+           loop (tree_first_child tree.doc t) (n+2);
+           Format.fprintf fmt "%s</%s>\n%!" tab tagstr;
+         end;
+         loop (tree_next_sibling tree.doc t) n
+  in
+    loop root 0
+;;
+
+       
+let print_xml_fast3 t = tree_print_xml_fast3 t.doc
+
+
+
+
+let stats t = 
+  let tree = t.doc in
+  let rec loop left node acc_d total_d num_leaves = 
+    if node == nil then
+    (acc_d+total_d,if left then num_leaves+1 else num_leaves)
+    else
+    let d,td = loop true (tree_first_child tree node) (acc_d+1) total_d num_leaves in
+    loop false (tree_next_sibling tree  node) (acc_d)  d td
+  in
+  let a,b = loop true root 0 0 0
+  in
+  Printf.eprintf "Average depth: %f, number of leaves %i\n%!" ((float_of_int a)/. (float_of_int b)) b
+;;
 
 
-    let print_xml_fast outc t = 
-      if Tag.to_string (tag t) = "" then
-       print_xml_fast outc (first_child t)
-      else print_xml_fast outc t
 
-       
 
 
-end
 
-module Binary = DEBUGTREE
-ELSE
-module Binary = XML.Binary
-END (* IFDEF DEBUG *)
+let test_prefix t s = Array.length (text_prefix t.doc s)
+let test_suffix t s = Array.length (text_suffix t.doc s)
+let test_contains t s = Array.length (text_contains t.doc s) 
+let test_equals t s = Array.length (text_equals t.doc s)