(* $Id: netmcore_hashtbl.ml 1998 2014-08-24 20:41:09Z gerd $ *) (* Parts of the implementation are taken over from hashtbl.ml of the O'Caml distribution *) module H = Netmcore_heap type ('a, 'b, 'h) tbl = { mutable size: int; (* number of elements *) mutable data: ('a, 'b) bucketlist array; (* the buckets *) header : 'h; } and ('a, 'b) bucketlist = Empty | Cons of ('a, 'b) bucketcell and ('a, 'b) bucketcell = { mutable key : 'a; mutable value : 'b; mutable tail : ('a, 'b) bucketlist } type ('a, 'b, 'h) t = ('a, 'b, 'h) tbl H.heap type ('a, 'b, 'h) t_descr = ('a, 'b, 'h) tbl H.descr let descr_of_hashtbl = H.descr_of_heap let hashtbl_of_descr = H.heap_of_descr let create pool h = let tbl = { size = 0; data = Array.make 391 Empty; header = h } in H.create_heap pool (H.minimum_size tbl) tbl let clear t = H.modify t (fun mut -> let tbl = H.root t in tbl.size <- 0; Array.fill tbl.data 0 (Array.length tbl.data) Empty ) let length t = (H.root t).size let resize mut tbl = let odata = tbl.data in let osize = Array.length odata in let nsize = min (2 * osize + 1) Sys.max_array_length in if nsize <> osize then ( let ndata = H.add mut (Array.make nsize Empty) in H.pin mut ndata; let rec insert_bucket bucket = match bucket with | Empty -> () | Cons cell -> insert_bucket cell.tail; (* preserve original order of elements *) let nidx = (Hashtbl.hash cell.key) mod nsize in let prev = ndata.(nidx) in ndata.(nidx) <- bucket; cell.tail <- prev; in for i = 0 to osize - 1 do insert_bucket odata.(i) done; tbl.data <- ndata; ) let add_1 tbl mut key value = let i = (Hashtbl.hash key) mod (Array.length tbl.data) in let cell_orig = { key = key; value = value; tail = Empty } in let elem = H.add mut (Cons cell_orig) in let cell = match elem with Cons c -> c | _ -> assert false in cell.tail <- tbl.data.(i); tbl.data.(i) <- elem; tbl.size <- succ tbl.size; if tbl.size > Array.length tbl.data lsl 1 then resize mut tbl let add t key value = H.modify t (fun mut -> let tbl = H.root t in add_1 tbl mut key value ) let remove t key = H.modify t (fun mut -> let tbl = H.root t in let i = (Hashtbl.hash key) mod (Array.length tbl.data) in let prev = ref None in let cur = ref tbl.data.(i) in while !cur <> Empty do match !cur with | Cons cell -> if compare cell.key key = 0 then ( ( match !prev with | None -> tbl.data.(i) <- cell.tail | Some pcell -> pcell.tail <- cell.tail ); tbl.size <- pred tbl.size; cur := Empty ) else ( prev := Some cell; cur := cell.tail; ) | Empty -> assert false done; ) let rec find_rec key = function | Empty -> raise Not_found | Cons cell -> if compare cell.key key = 0 then cell.value else find_rec key cell.tail let find_quickly tbl key = match tbl.data.((Hashtbl.hash key) mod (Array.length tbl.data)) with Empty -> raise Not_found | Cons cell1 -> if compare key cell1.key = 0 then cell1.value else match cell1.tail with Empty -> raise Not_found | Cons cell2 -> if compare key cell2.key = 0 then cell2.value else match cell2.tail with Empty -> raise Not_found | Cons cell3 -> if compare key cell3.key = 0 then cell3.value else find_rec key cell3.tail let find_ro t key = (* unprotected version! *) find_quickly (H.root t) key let find_p t key f = H.with_value t (fun () -> find_quickly (H.root t) key ) f let find_c t key = find_p t key H.copy let rec find_in_bucket key = function | Empty -> [] | Cons cell -> if compare cell.key key = 0 then cell.value :: find_in_bucket key cell.tail else find_in_bucket key cell.tail let find_all_ro t key = let tbl = H.root t in find_in_bucket key tbl.data.((Hashtbl.hash key) mod (Array.length tbl.data)) let find_all_p t key f = let tbl = H.root t in H.with_value_n t (fun () -> find_in_bucket key tbl.data.((Hashtbl.hash key) mod (Array.length tbl.data)) ) f let find_all_c t key = find_all_p t key H.copy let replace t key value = H.modify t (fun mut -> let tbl = H.root t in let rec replace_bucket = function | Empty -> raise Not_found | Cons cell -> if compare cell.key key = 0 then cell.value <- H.add mut value else replace_bucket cell.tail in let i = (Hashtbl.hash key) mod (Array.length tbl.data) in try replace_bucket tbl.data.(i) with | Not_found -> add_1 tbl mut key value ) let mem_ro t key = try ignore(find_ro t key); true with Not_found -> false let mem t key = H.with_value t (fun () -> mem_ro t key ) (fun r -> r) let iter f t = H.with_value t (fun () -> let rec do_bucket = function | Empty -> () | Cons cell -> f cell.key cell.value; do_bucket cell.tail in let tbl = H.root t in let d = tbl.data in for i = 0 to Array.length d - 1 do do_bucket d.(i) done ) (fun () -> ()) let header t = (H.root t).header let heap t = Obj.magic t