Random fixes
[SXSI/xpathcomp.git] / tree.ml
diff --git a/tree.ml b/tree.ml
index 20f0505..7ea6f03 100644 (file)
--- a/tree.ml
+++ b/tree.ml
 (******************************************************************************)
 INCLUDE "utils.ml"
 
+
+external init_lib : unit -> unit = "caml_init_lib"
+
+exception CPlusPlusError of string
+
+let () = Callback.register_exception "CPlusPlusError" (CPlusPlusError "")
+
+let () =  init_lib ()
+
+
 type tree
-type 'a node = int
+type 'a node = private int
 type node_kind = [`Text | `Tree ]
-    
-let compare_node : 'a node -> 'a node -> int = (-)
+
+type t = { 
+  doc : tree;            
+  ttable : (Tag.t,(Ptset.Int.t*Ptset.Int.t*Ptset.Int.t*Ptset.Int.t)) Hashtbl.t;
+}
+
+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 = (==)
-  
-(* abstract type, values are pointers to a XMLTree C++ object *)
 
-external int_of_node : 'a node -> int = "%identity"
   
 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 save_tree : tree -> string -> unit = "caml_xml_tree_save"
-external load_tree : string ->  int -> tree = "caml_xml_tree_load"
+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"
 
-let nil : 'a node = Obj.magic (-1)
+let nil : [`Tree ] node = nodei ~-1
+let nulldoc : [`Text ] node = nodei ~-1
+let root : [`Tree ] node = nodei 0
 
-external text_get_tc_text : tree -> [`Text] node -> string = "caml_text_collection_get_text" 
-               
+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" 
 
-let text_is_empty t n =
-  (equal_node nil n) || text_is_empty t n
-    
-
+let text_is_empty t n = (equal_node nulldoc n) || text_is_empty t n
 
+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_count_contains : tree -> string -> int = "caml_text_collection_count_contains" 
-external text_count : tree -> string -> int = "caml_text_collection_count" 
-external text_contains : tree -> string -> [`Text ] node array = "caml_text_collection_contains" 
-external text_unsorted_contains : tree -> string -> unit = "caml_text_collection_unsorted_contains"
-external get_cached_text : tree -> [`Text] node -> string = "caml_text_collection_get_cached_text"
+external text_is_lessthan : tree -> string -> bool = "caml_text_collection_is_lessthan" 
 
+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 tree_serialize : tree -> string -> unit = "caml_xml_tree_serialize"
+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 tree_unserialize : string -> tree = "caml_xml_tree_unserialize"
-      
-external tree_root : tree -> [`Tree] node = "caml_xml_tree_root" 
+    
+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 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"
 
-external tree_parent : tree -> [`Tree] node -> [`Tree] node = "caml_xml_tree_parent" 
-external tree_parent_doc : tree -> [`Text ] node -> [`Tree ] node = "caml_xml_tree_parent_doc" 
-external tree_prev_doc : tree -> [`Text ] node -> [`Tree ] node = "caml_xml_tree_prev_doc" 
-external tree_first_child : tree -> [`Tree] node -> [`Tree] node = "caml_xml_tree_first_child" 
-external tree_next_sibling : tree -> [`Tree] node -> [`Tree] node = "caml_xml_tree_next_sibling" 
-external tree_prev_sibling : tree -> [`Tree] node -> [`Tree] node = "caml_xml_tree_prev_sibling" 
-external tree_is_leaf : tree -> [`Tree] node -> bool = "caml_xml_tree_is_leaf" 
-external tree_last_child : tree -> [`Tree] node -> [`Tree] node = "caml_xml_tree_last_child"
-external tree_is_first_child : tree -> [`Tree] node -> bool = "caml_xml_tree_is_first_child"
-
-(*    external tag : tree -> [`Tree ] node -> T = "caml_xml_tree_tag"*)
-external tree_tag_id : tree -> [`Tree ] node -> Tag.t = "caml_xml_tree_tag_id" 
-    
+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"
+
+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"
+
+
+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"
+
+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"
+
+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" *)
+
+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"
+
+
+external benchmark_jump : tree -> Tag.t -> unit = "caml_benchmark_jump" "noalloc"
+
+let benchmark_jump t s = benchmark_jump t.doc s
+
+external benchmark_fcns : tree -> int = "caml_benchmark_fcns" "noalloc"
+
+let benchmark_fcns t = benchmark_fcns t.doc
+
+external benchmark_lcps : tree -> unit = "caml_benchmark_lcps" "noalloc"
+
+let benchmark_lcps t = benchmark_lcps t.doc
+
+
+
+
+
+
+
+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
+
+
+
+
+module HPtset = Hashtbl.Make(Ptset.Int)
+
+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 tree_is_last t n = equal_node nil (tree_next_sibling t n)
-    
-external tree_prev_text : tree -> [`Tree] node -> [`Text ] node = "caml_xml_tree_prev_text" 
-
-external tree_my_text : tree -> [`Tree] node -> [`Text ] node = "caml_xml_tree_my_text" 
-external tree_next_text : tree -> [`Tree] node -> [`Text ] node = "caml_xml_tree_next_text" 
-external tree_doc_ids : tree -> [`Tree ] node -> [`Text ] node * [`Text ] node = "caml_xml_tree_doc_ids" 
-
-let text_size tree = int_of_node (snd ( tree_doc_ids tree (Obj.magic 0) ))
-
-let get_cached_text t x =
-  if x == -1 then ""
-  else 
-     get_cached_text t x
-
-
-external tree_text_xml_id : tree -> [`Text ] node -> int = "caml_xml_tree_text_xml_id" 
-external tree_node_xml_id : tree -> [`Tree ] node -> int = "caml_xml_tree_node_xml_id" 
-external tree_is_ancestor : tree -> [`Tree ] node -> [`Tree ] node -> bool = "caml_xml_tree_is_ancestor" 
-external tree_tagged_desc : tree -> [`Tree ] node -> Tag.t -> [`Tree ] node = "caml_xml_tree_tagged_desc" 
-external tree_tagged_foll_below : tree -> [`Tree ] node -> Tag.t -> [`Tree ] node -> [`Tree ] node = "caml_xml_tree_tagged_foll_below" 
-external tree_subtree_tags : tree -> [`Tree ] node -> Tag.t -> int = "caml_xml_tree_subtree_tags" 
-(*
-external tree_select_below : tree -> [`Tree ] node -> Ptset.int_vector -> Ptset.int_vector -> [`Tree ] node = "caml_xml_tree_select_below" 
-external tree_select_desc_only : tree -> [`Tree ] node -> Ptset.int_vector -> [`Tree ] node = "caml_xml_tree_select_desc_only" 
-external tree_select_next : tree -> [`Tree ] node -> Ptset.int_vector -> Ptset.int_vector -> [`Tree ] node -> [`Tree ] node = "caml_xml_tree_select_next" 
-external tree_select_foll_only : tree -> [`Tree ] node -> Ptset.int_vector -> [`Tree ] node -> [`Tree ] node = "caml_xml_tree_select_foll_only" 
-external tree_select_desc_or_foll_only : tree -> [`Tree ] node -> Ptset.int_vector -> [`Tree ] node -> [`Tree ] node = "caml_xml_tree_select_foll_only" *)
-  
-type descr = 
-  | Nil 
-  | Node of [`Tree] node
-  | Text of [`Text] node * [`Tree] node
       
-type t = { doc : tree;           
-          node : descr;
-          ttable : (Tag.t,(Ptset.Int.t*Ptset.Int.t)) Hashtbl.t;
-        }
 
+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 h_union = Hashtbl.create 511 in
+  let _ = Printf.eprintf "Collecting Tags\n%!" in
+  let h_union = MemUnion.create BIG_H_SIZE in
   let pt_cup s1 s2 =
-    (* special case, since this is a union we want hash(s1,s2) = hash(s2,s1) *)
-    let x = Ptset.Int.hash s1 
-    and y = Ptset.Int.hash s2 in
-    let h = if x < y then HASHINT2(x,y) else HASHINT2(y,x)in
       try
-       Hashtbl.find h_union h
+       MemUnion.find h_union (s1,s2)
       with
        | Not_found -> let s = Ptset.Int.union s1 s2
          in
-           Hashtbl.add h_union h s;s
+           MemUnion.add h_union (s1,s2) s;s
   in    
-  let h_add = Hashtbl.create 511 in
-  let pt_add t s = 
-    let k = HASHINT2(Tag.hash t,Ptset.Int.hash s) in
-      try
-       Hashtbl.find h_add k
-      with
+  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
-         Hashtbl.add h_add k r;r
-  in
-  let h = Hashtbl.create 511 in
-  let sing = Ptset.Int.singleton Tag.pcdata in    
-  let update t sb sa =
-    let sbelow,safter = 
+         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 -> 
-           (sing,sing)
+           (Ptset.Int.empty,Ptset.Int.empty,Ptset.Int.empty,Ptset.Int.empty)
     in
-      Hashtbl.replace h t (pt_cup sbelow sb, pt_cup safter sa)
+      Hashtbl.replace h t 
+       (pt_cup sc schild,pt_cup sbelow sb, pt_cup ssibling ss, pt_cup safter sa) 
   in
-  let rec loop id acc = 
-    if equal_node id nil
-    then (Ptset.Int.empty,acc)
-    else
-      let below2,after2 = loop (tree_next_sibling tree id) acc in
-      let below1,after1 = loop (tree_first_child tree id) after2 in
-      let tag = tree_tag_id tree id in
-       update tag below1 after2;
-       pt_add tag (pt_cup below1 below2), (pt_add tag after1)
+  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 b,a = loop (tree_root tree) Ptset.Int.empty in
-    update Tag.pcdata b a;
+  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 =
@@ -168,15 +263,18 @@ let in_array _ i =
   with
       Not_found -> false
 
-let init_contains t s = 
-  let a = text_contains t.doc s 
+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;
+    (*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 unsorted_contains t s = text_unsorted_contains t.doc s
 
 let init_naive_contains t s =
   let i,j = tree_doc_ids t.doc (tree_root t.doc)
@@ -191,18 +289,46 @@ let init_naive_contains t s =
   let rec loop n acc l = 
     if n >= j then acc,l
     else
-      let s = get_cached_text t.doc n
+      let s = text_get_text t.doc n
       in
        if matching s 
-       then loop (n+1) (n::acc) (l+1) 
-       else loop (n+1) acc l
+       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 nil 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
+
 
 
 module DocIdSet = struct
@@ -210,29 +336,33 @@ module DocIdSet = struct
                           let compare = compare_node end)
     
 end
-let is_nil t = t.node == Nil
+let is_nil t = t == nil
 
-let is_node t = t.node != 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
-(*
-  let _ = Hashtbl.iter (fun t (sb,sa) ->
-                         Printf.eprintf "'%s' -> { " (Tag.to_string t);
-                         Ptset.iter (fun i ->  Printf.eprintf "'%s' " (Tag.to_string i)) sb;
-                         Printf.eprintf "}\n { ";
-                         Ptset.iter (fun i ->  Printf.eprintf "'%s' " (Tag.to_string i)) sa;
-                         Printf.eprintf "} \n----------------------------------\n";
-                      ) table in
-  let i,j = tree_doc_ids t (tree_root t) in
-    Printf.eprintf "%i docs, range from %i to %i\n%!" (Array.length s) i j;
-    Array.iter (fun i -> print_endline (">>>" ^ i ^ "<<<")) s; *)
+                         
+     *)                          
     { doc= t; 
-      node = Node(tree_root t);
       ttable = table;
     }
+
 let finalize _ = Printf.eprintf "Release the string list !\n%!"
 ;;
 
@@ -246,271 +376,173 @@ let parse f str =
 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 save t str = (save_tree t.doc str)
+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) str = 
-  node_of_t (load_tree str sample)
-    
+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 a b = match a.node,b.node  with
-  | Nil, Nil -> 0
-  | Nil,_ -> 1
-  | _ , Nil -> -1
-  | Node(i),Node(j) -> compare_node i j
-  | Text(i,_), Text(j,_) -> compare_node i j
-  | Node(i), Text(_,j) -> compare_node i j
-  | Text(_,i), Node(j) -> compare_node i j 
-
-let equal a b = (compare a b) == 0
-  
-  
-let norm (n : [`Tree ] node ) =  if n == -1 then Nil else Node (n)
-  
+let compare = compare_node
+
+let equal a b = a == b
+   
 let nts = function
-    Nil -> "Nil"
-  | Text (i,j) -> Printf.sprintf "Text (%i, %i)" i j
-  | Node (i) -> Printf.sprintf "Node (%i)"  i
+    -1 -> "Nil"
+  | i -> Printf.sprintf "Node (%i)"  i
       
-let dump_node t = nts t.node
+let dump_node t = nts (inode t)
 
-let mk_nil t = { t with node = Nil }             
-let root n = { n with node = norm (tree_root n.doc) }
+let is_left t n = tree_is_first_child t.doc n
 
-let is_root n = match n.node with
-  | Node(t) -> (int_of_node t) == 0 
-  | _ -> false
-      
-let is_left n = match n.node with
-  | Node(t) -> (tree_is_first_child n.doc t) && (equal_node nil (tree_prev_text n.doc t))
-  | Text(_,t) -> tree_is_nil t || tree_is_first_child n.doc t
-  | _ -> false
-
-let is_below_right t1 t2 =
-  match (t1.node,t2.node) with
-    | Nil,_ | _,Nil -> false
-    | Node(i1), Node(i2)   -> 
-       tree_is_ancestor t1.doc (tree_parent t1.doc i1) i2
-       && not (tree_is_ancestor t1.doc i1 i2)
-    | Text(_,i1),Node(i2) -> i1 == i2 ||
-       (tree_is_ancestor t1.doc (tree_parent t1.doc i1) i2 && i1 < i2)
-    | Text(_,i1),Text(i,_) ->  
-       let x,y = tree_doc_ids t1.doc i1 in
-         i >= x && i <= y          
-    | Node(i1), Text(i,_) -> 
-       let i2 = tree_next_sibling t1.doc i1 in
-       let x,y = tree_doc_ids t1.doc i2 in
-         i >= x && i <= y
-
-let parent n =  
-  let node' = 
-    match n.node with (* inlined parent *)
-      | Node(t) when (int_of_node t)== 0 -> Nil
-      | Node(t) -> 
-         let txt = tree_prev_text n.doc t in
-           if text_is_empty n.doc txt then
-             let ps = tree_prev_sibling n.doc t in
-               if tree_is_nil ps
-               then
-                 Node(tree_parent n.doc t)
-               else Node(ps)
-           else
-             Text(txt,t)
-      | Text(i,t) ->
-         let ps = tree_prev_doc n.doc i in
-           if tree_is_nil ps
-           then Node (tree_parent_doc n.doc i)
-           else Node(ps)
-      | _ -> failwith "parent"
-  in
-    { n with node = node' }
-
-let node_child n =
-  match n.node with
-    | Node i ->  { n with node= norm(tree_first_child n.doc i) }
-    | _ -> { n with node = Nil }
-
-let node_sibling n =
-  match n.node with
-    | Node i ->  { n with node= norm(tree_next_sibling n.doc i) }
-    | _ -> { n with node = Nil }
-
-let node_sibling_ctx  n _ = 
-  match n.node with
-    | Node i ->  { n with node= norm(tree_next_sibling n.doc i) }
-    | _ -> { n with node = Nil }
-
-
-let first_child n = 
-  let node' = 
-    match n.node with
-      | Node (t) -> 
-         let fs = tree_first_child n.doc t in
-           if equal_node nil fs
-           then 
-             let txt = tree_my_text n.doc t in
-               if equal_node nil txt
-               then Nil
-               else Text(txt,nil)
-           else
-             let txt = tree_prev_text n.doc fs in
-               if equal_node nil txt
-               then Node(fs)
-               else Text(txt, fs) 
-      | Text(_,_) -> Nil
-      | Nil -> failwith "first_child"
-  in
-    { n with node = node'}
-      
-let next_sibling n = 
-  let node' =
-    match n.node with
-      | Text (_,ns) -> norm ns
-      | Node(t) ->
-         let ns = tree_next_sibling n.doc t in
-         let txt = tree_next_text n.doc t in
-           if equal_node nil txt
-           then norm ns
-           else Text(txt, ns)
-      | Nil -> failwith "next_sibling"
-  in
-    { n with node = node'}
-         
-let next_sibling_ctx n _ = next_sibling n
-         
-let left = first_child 
-let right = next_sibling
+
+
+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)
+
+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 id t = 
-  match t.node with
-    | Node(n)  -> tree_node_xml_id t.doc n
-    | Text(i,_)  -> tree_text_xml_id t.doc i
-    | _ ->  -1 
-       
-let tag t =
-  match t.node with 
-  | Text(_) -> Tag.pcdata
-  | Node(n) -> tree_tag_id t.doc n
-  | Nil -> Tag.nullt
-
-(*
-let select_next tb tf t s = 
-  match s.node  with
-    | Node (below) -> begin
-       match t.node with
-         | Node( n)  ->
-             { t with node = norm (tree_select_next t.doc n (Ptset.Int.to_int_vector tb) (Ptset.Int.to_int_vector tf) below) }
-         | Text (i,n)  when equal_node nil n ->
-             let p = tree_parent_doc t.doc i in
-               { t with node = norm (tree_select_next t.doc p (Ptset.Int.to_int_vector tb) (Ptset.Int.to_int_vector tf) below) }
-         | Text(_,n)  ->
-             if Ptset.mem (tree_tag_id t.doc n) (Ptset.Int.union tb tf)
-             then { t with node=Node(n) }
-             else
-               let vb = Ptset.Int.to_int_vector tb in
-               let vf = Ptset.Int.to_int_vector tf in
-               let node = 
-                 let dsc = tree_select_below t.doc n vb vf in
-                   if equal_node nil dsc
-                   then tree_select_next t.doc n vb vf below
-                   else dsc
-               in
-                 { t with node = norm node }
-         | _ -> {t with node = Nil }
-      end
-       
-    | _ -> { t with node = Nil }
+let parent t n = tree_parent t.doc n
 
-  
+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
 
+(* 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
+*)
 
-  let select_foll_only  tf t s = 
-    match s.node  with
-      | Node (below)  -> 
-         begin
-           match t.node with
-           | Node(n) ->
-               { t with node= norm (tree_select_foll_only t.doc n (Ptset.Int.to_int_vector tf) below) }
-           | Text(i,n)  when equal_node nil n ->
-               let p = tree_parent_doc t.doc i in
-                 { t with node= norm (tree_select_foll_only t.doc p (Ptset.Int.to_int_vector tf) below) }
-           |  Text(_,n) ->
-                if Ptset.mem (tree_tag_id t.doc n) tf
-                then { t with node=Node(n) }
-                else
-                  let vf = Ptset.Int.to_int_vector tf in
-                  let node = 
-                    let dsc = tree_select_desc_only t.doc n vf in
-                      if tree_is_nil dsc
-                      then tree_select_foll_only t.doc n vf below
-                      else dsc
-                  in
-                    { t with node = norm node }
-           | _ -> { t with node = Nil }
-       end         
-      | _ -> {t with node=Nil }          
-
-let select_below  tc td t=
-  match t.node with
-    | Node( n) -> 
-       let vc = Ptset.Int.to_int_vector tc
-       in
-       let vd = Ptset.Int.to_int_vector td
-       in
-         { t with node= norm(tree_select_below t.doc n vc vd) }
-    | _ -> { t with node=Nil }
-       
+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 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 tagged_following_sibling t tag = (); fun n -> tree_tagged_following_sibling t.doc n tag
+
+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 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 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 select_desc_only  td t =
-  match t.node with
-    | Node(n) -> 
-       let vd = Ptset.Int.to_int_vector td
-       in
-         { t with node = norm(tree_select_desc_only t.doc n vd) }
-    | _ -> { t with node = Nil }
+let tag t n = if n == nil then Tag.nullt else tree_tag t.doc n
 
-*)
-let tagged_desc tag t =
-  match t.node with
-    | Node(n) ->       
-         { t with node = norm(tree_tagged_desc t.doc n tag) }
-    | _ -> { t with node = Nil }
-
-
-let tagged_foll_ctx tag t s =
-    match s.node  with
-      | Node (below)  -> 
-         begin
-           match t.node with
-           | Node(n) ->
-               { t with node= norm (tree_tagged_foll_below t.doc n tag below) }
-           | Text(i,n)  when equal_node nil n ->
-               let p = tree_prev_doc t.doc i in
-                 { t with node= norm (tree_tagged_foll_below t.doc p tag below) }
-           |  Text(_,n) ->
-                if (tree_tag_id t.doc n) == tag
-                then { t with node=Node(n) }
-                else
-                  let node = 
-                    let dsc = tree_tagged_desc t.doc n tag in
-                      if tree_is_nil dsc
-                      then tree_tagged_foll_below t.doc n tag below
-                      else dsc
-                  in
-                    { t with node = norm node }
-           | _ -> { t with node = Nil }
-         end       
-      | _ -> {t with node=Nil }          
+let tagged_descendant t tag = 
+  let doc = t.doc in (); fun n -> tree_tagged_descendant doc n tag 
 
+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 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 =
@@ -525,310 +557,239 @@ let array_find a i j =
     else loop !last_idx i j 
 
 
-       
-let text_below t = 
-  let l = Array.length !contains_array in
-      match t.node with
-       | Node(n)  -> 
-           let i,j = tree_doc_ids t.doc n in
-           let id = if l == 0 then i else (array_find !contains_array 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
-(*           Printf.printf "Looking for text below node %i with tag %s in range %i %i, in array : [|\n%!"
-               n (Tag.to_string (tree_tag_id t.doc n)) i j;
-             Array.iter (fun i -> Printf.printf "%i " (int_of_node i )) !contains_array;
-             Printf.printf "|]\nResult is %i\n%!" id;        *)
-             if id == nil then  
-               { t with  node=Nil }
-             else
-               { t with  node = Text(id, tree_next_sibling t.doc (tree_prev_doc t.doc id)) }
-       | _ -> (*Printf.printf "Here\n%!"; *)
-           { t with node = Nil }
-           
-let text_next t root =
-  let l = Array.length !contains_array in
-      let inf = match t.node with
-       | Node(n)  -> snd(tree_doc_ids t.doc n)+1
-       | Text(i,_)  -> i+1
-       | _ -> assert false
-      in
-       match root.node with
-         | Node (n)  ->
-             let _,j = tree_doc_ids t.doc n in      
-             let id = if l == 0 then if inf > j then nil else inf
-             else array_find !contains_array inf j
-             in
-               if id == nil then  { t with node= Nil }
+             output_char outc  '<';
+             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
-                 { t with node = Text(id,tree_next_sibling t.doc (tree_prev_doc t.doc id)) }
-         | _ -> { 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 select_desc_array = ref [| |]
-    let idx = ref 0
-
-    let init_tagged_next t tagid =
-      let l = subtree_tags (root t) tagid
-      in
-       tagged_desc_array := Array.create l { t with node= Nil };
-       let i = ref 0 in
-         let rec collect t =
-           if is_node t then begin
-             if tag t == tagid then
-               begin
-                 !tagged_desc_array.(!i) <- t;
-                 incr i;
-               end;
-             collect (first_child t);
-             collect (next_sibling t)
-           end;
-         in
-           collect t;
-           idx := 0
-
-    let print_id ppf v = 
-      let pr x= Format.fprintf ppf x in
-       match v with
-           { node=Nil } -> pr "NULLT: -1"
-         | { node=String(i) } | { node=Node(SC(i,_)) } -> pr "DocID: %i" (int_of_node i)
-         | { node=Node(NC(i)) } -> pr "Node: %i" (int_of_node i)
-             
-             
+                 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 tagged_next t tag = 
-      if !idx >= Array.length !tagged_desc_array 
-      then {t with node=Nil}
-      else
-       let r = !tagged_desc_array.(!idx) 
-       in
-         incr idx; r
-*)               
-
+         
+    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 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)
+let tags t tag = Hashtbl.find t.ttable tag
 
 
-    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 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 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 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 count_contains t s =   Text.count_contains t.doc s
-*)
 
-  let count t s = text_count t.doc s
-(*
-    let is_left t =
-      if is_root t then false
-      else
-      if tag (parent t) == Tag.pcdata then false
-      else
-       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 -> ()    
-      | Text(i,n) -> output_string outc (get_cached_text t.doc i);
-         if print_right
-         then loop (right t)
-      | Node (n) -> 
-         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  "/>"
-               | 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
-                 | Text(i,_) -> (get_cached_text a.doc i)
-                 | _ -> assert false
-             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
-         
-         
-    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 tags_below t tag = 
-  fst(Hashtbl.find t.ttable tag)
 
-let tags_after t tag = 
-  snd(Hashtbl.find t.ttable tag)
 
-let tags t tag = Hashtbl.find t.ttable tag
 
-let  tagged_lowest t tag = 
-  let rec loop_lowest i = 
-    let j = tree_tagged_desc t.doc i tag in
-    if tree_is_nil j then i else loop_lowest j
-  in
-    match t.node with
-      | Node i ->
-         let j = loop_lowest i in 
-           { t with 
-               node = norm(
-                 if tree_is_nil j then
-                   if (tree_tag_id t.doc i) == tag
-                   then i
-                   else j
-                 else j) }
-      | Nil -> t
-      | _ -> assert false
-         
-         
-let tagged_next t tag = 
-  match t.node with
-    | Node(i) -> 
-       let n = tree_tagged_foll_below t.doc i tag (Obj.magic 0)
-       in
-         if tree_is_nil  n then mk_nil t
-         else 
-           tagged_lowest { t with node = Node n } tag
-    | Nil -> t
-    | _ -> assert false
-
-let rec binary_parent t = 
-  let res = 
-  match t.node with
-  | Node(0) -> { t with node = Nil }
-  | Node(i) ->
-      let j = tree_prev_sibling t.doc i in
-       if tree_is_nil j then
-         let idoc = tree_prev_text t.doc i in
-           if equal_node nil idoc then
-             { t with node = Node (tree_parent t.doc i) }
-           else 
-             { t with node = Text(idoc,i) }
-       else
-         let idoc = tree_prev_text t.doc i in
-           if equal_node nil idoc then
-             { t with node = Node (j) }
-           else { t with node = Text(idoc,i) }
-  | Text(d,i) ->       
-      if tree_is_nil i then
-       let n = tree_parent_doc t.doc d in
-       let lc = tree_last_child t.doc n in
-         if tree_is_nil lc then {t with node = Node n }
-         else { t with node = Node lc }
-      else
-       let j = tree_prev_sibling t.doc i in
-         if tree_is_nil j then
-           { t with node = Node (tree_parent t.doc i) }
-         else { t with node = Node j }
-  | Nil -> t
-  in match res.node with
-    | Text(idoc,t) -> 
-       if (Array.length !contains_array) != 0
-       then if in_array !contains_array idoc then res
-       else binary_parent res
-       else res
-    | _ -> res
-
-let benchmark_text t =
-  let doc = t.doc in
-    match (root t).node with
-      | Node i -> let _,size = tree_doc_ids doc i in
-         Printf.eprintf "%i will take ~ %i seconds\n%!"
-           size (size/10000) ;
-       let a = Array.create size "" in
-         for i = 0 to size 
-         do
-           a.(i) <- text_get_tc_text t.doc (i+1)
-         done; a
-      | _ -> assert false
-
-let doc_ids (t:t) : (int*int) = 
-  (Obj.magic (
-    match t.node with
-      | Node i -> tree_doc_ids t.doc i
-      | Text (i,_) -> (i,i)
-      | Nil -> (nil,nil)
-   ))
-
-let subtree_tags t tag = match t.node with
-  | Nil -> 0
-  | Node(i) -> tree_subtree_tags t.doc i tag
-  | Text(_,i) -> tree_subtree_tags t.doc i tag
-
-let get_text t = match t.node with
-  | Text(i,_) -> get_cached_text t.doc i
-  | _ -> ""
+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)