+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_is_ancestor : tree -> [`Tree ] node -> [`Tree ] node -> bool = "caml_xml_tree_is_ancestor" "noalloc"
+external tree_tagged_desc : tree -> [`Tree ] node -> Tag.t -> [`Tree ] node = "caml_xml_tree_tagged_desc" "noalloc"
+external tree_tagged_foll_below : tree -> [`Tree ] node -> Tag.t -> [`Tree ] node -> [`Tree ] node = "caml_xml_tree_tagged_foll_below" "noalloc"
+external tree_subtree_tags : tree -> [`Tree ] node -> Tag.t -> int = "caml_xml_tree_subtree_tags" "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_select_foll_sibling : tree -> [`Tree ] node -> unordered_set -> [`Tree] node = "caml_xml_tree_select_foll_sibling" "noalloc"
+external tree_select_desc : tree -> [`Tree ] node -> unordered_set -> [`Tree] node = "caml_xml_tree_select_desc" "noalloc"
+external tree_select_foll_below : tree -> [`Tree ] node -> unordered_set -> [`Tree] node -> [`Tree] node = "caml_xml_tree_select_foll_below" "noalloc"
+
+
+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
+
+
+type t = {
+ doc : tree;
+ ttable : (Tag.t,(Ptset.Int.t*Ptset.Int.t*Ptset.Int.t*Ptset.Int.t)) Hashtbl.t;
+}
+
+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) = (Ptset.Int.equal x z)&&(Ptset.Int.equal y t)
+ let equal a b = equal a b || equal b a
+ let hash (x,y) = (* commutative hash *)
+ let x = Ptset.Int.hash x
+ and y = Ptset.Int.hash 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)&&(Ptset.Int.equal y t)
+ let hash (x,y) = HASHINT2(x,Ptset.Int.hash y)
+ end)
+
+let collect_tags tree =
+ 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_sibling acc_after=
+ if id == nil
+ then (acc_sibling,acc_after)
+ else
+ let sibling2,after2 = loop_right (tree_next_sibling tree id) acc_sibling acc_after in
+ let child1,below1 = loop_left (tree_first_child tree id) after2 in
+ let tag = tree_tag_id tree id in
+ update tag child1 below1 sibling2 after2;
+ (pt_add tag sibling2, (pt_add tag (pt_cup after2 below1)))
+ and loop_left id acc_after =
+ if id == nil
+ then (Ptset.Int.empty,Ptset.Int.empty)
+ else
+ let sibling2,after2 = loop_right (tree_next_sibling tree id) Ptset.Int.empty acc_after in
+ let child1,below1 = loop_left (tree_first_child tree id) after2 in
+ let tag = tree_tag_id tree id in
+ update tag child1 below1 sibling2 after2;
+ (pt_add tag sibling2,(pt_add tag (pt_cup after2 below1)))
+ in
+ let _ = loop_left (tree_root tree) Ptset.Int.empty 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_contains t s =
+ let a = text_contains 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 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)
+ 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_cached_text t.doc n