Blame src/extHashtbl.ml

rpm-build 0f2925
(* 
rpm-build 0f2925
 * ExtHashtbl, extra functions over hashtables.
rpm-build 0f2925
 * Copyright (C) 2003 Nicolas Cannasse
rpm-build 0f2925
 * 
rpm-build 0f2925
 * This library is free software; you can redistribute it and/or
rpm-build 0f2925
 * modify it under the terms of the GNU Lesser General Public
rpm-build 0f2925
 * License as published by the Free Software Foundation; either
rpm-build 0f2925
 * version 2.1 of the License, or (at your option) any later version,
rpm-build 0f2925
 * with the special exception on linking described in file LICENSE.
rpm-build 0f2925
 *
rpm-build 0f2925
 * This library is distributed in the hope that it will be useful,
rpm-build 0f2925
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
rpm-build 0f2925
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
rpm-build 0f2925
 * Lesser General Public License for more details.
rpm-build 0f2925
 *
rpm-build 0f2925
 * You should have received a copy of the GNU Lesser General Public
rpm-build 0f2925
 * License along with this library; if not, write to the Free Software
rpm-build 0f2925
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
rpm-build 0f2925
 *)
rpm-build 0f2925
 
rpm-build 0f2925
rpm-build 0f2925
module Hashtbl =
rpm-build 0f2925
  struct
rpm-build 0f2925
rpm-build 0f2925
#if OCAML >= 400
rpm-build 0f2925
  external old_hash_param :
rpm-build 0f2925
    int -> int -> 'a -> int = "caml_hash_univ_param" "noalloc"
rpm-build 0f2925
#endif
rpm-build 0f2925
rpm-build 0f2925
  type ('a, 'b) h_bucketlist =
rpm-build 0f2925
    | Empty
rpm-build 0f2925
    | Cons of 'a * 'b * ('a, 'b) h_bucketlist
rpm-build 0f2925
rpm-build 0f2925
#if OCAML >= 400
rpm-build 0f2925
  type ('a, 'b) h_t = {
rpm-build 0f2925
    mutable size: int;
rpm-build 0f2925
    mutable data: ('a, 'b) h_bucketlist array;
rpm-build 0f2925
    mutable seed: int;
rpm-build 0f2925
    initial_size: int;
rpm-build 0f2925
  }
rpm-build 0f2925
#else
rpm-build 0f2925
  type ('a, 'b) h_t = {
rpm-build 0f2925
    mutable size: int;
rpm-build 0f2925
    mutable data: ('a, 'b) h_bucketlist array
rpm-build 0f2925
  }
rpm-build 0f2925
#endif
rpm-build 0f2925
rpm-build 0f2925
  include Hashtbl
rpm-build 0f2925
rpm-build 0f2925
#if OCAML < 400
rpm-build 0f2925
  let create ?random:_ n = Hashtbl.create (* no seed *) n
rpm-build 0f2925
#endif
rpm-build 0f2925
rpm-build 0f2925
  external h_conv : ('a, 'b) t -> ('a, 'b) h_t = "%identity"
rpm-build 0f2925
  external h_make : ('a, 'b) h_t -> ('a, 'b) t = "%identity"
rpm-build 0f2925
rpm-build 0f2925
  let exists = mem
rpm-build 0f2925
rpm-build 0f2925
  let enum h =
rpm-build 0f2925
    let rec make ipos ibuck idata icount =
rpm-build 0f2925
      let pos = ref ipos in
rpm-build 0f2925
      let buck = ref ibuck in
rpm-build 0f2925
      let hdata = ref idata in
rpm-build 0f2925
      let hcount = ref icount in
rpm-build 0f2925
      let force() =
rpm-build 0f2925
        (** this is a hack in order to keep an O(1) enum constructor **)
rpm-build 0f2925
        if !hcount = -1 then begin
rpm-build 0f2925
          hcount := (h_conv h).size;
rpm-build 0f2925
          hdata := Array.copy (h_conv h).data;
rpm-build 0f2925
        end;
rpm-build 0f2925
      in
rpm-build 0f2925
      let rec next() =
rpm-build 0f2925
        force();
rpm-build 0f2925
        match !buck with
rpm-build 0f2925
        | Empty ->
rpm-build 0f2925
          if !hcount = 0 then raise Enum.No_more_elements;
rpm-build 0f2925
          incr pos;
rpm-build 0f2925
          buck := Array.unsafe_get !hdata !pos;
rpm-build 0f2925
          next()
rpm-build 0f2925
        | Cons (k,i,next_buck) ->
rpm-build 0f2925
          buck := next_buck;
rpm-build 0f2925
          decr hcount;
rpm-build 0f2925
          (k,i)
rpm-build 0f2925
      in
rpm-build 0f2925
      let count() =
rpm-build 0f2925
        if !hcount = -1 then (h_conv h).size else !hcount
rpm-build 0f2925
      in
rpm-build 0f2925
      let clone() =
rpm-build 0f2925
        force();
rpm-build 0f2925
        make !pos !buck !hdata !hcount
rpm-build 0f2925
      in
rpm-build 0f2925
      Enum.make ~next ~count ~clone
rpm-build 0f2925
    in
rpm-build 0f2925
    make (-1) Empty (Obj.magic()) (-1)
rpm-build 0f2925
rpm-build 0f2925
  let keys h =
rpm-build 0f2925
    Enum.map (fun (k,_) -> k) (enum h)
rpm-build 0f2925
rpm-build 0f2925
  let values h =
rpm-build 0f2925
    Enum.map (fun (_,v) -> v) (enum h)
rpm-build 0f2925
rpm-build 0f2925
  let map f h =
rpm-build 0f2925
    let rec loop = function
rpm-build 0f2925
      | Empty -> Empty
rpm-build 0f2925
      | Cons (k,v,next) -> Cons (k,f v,loop next)
rpm-build 0f2925
    in
rpm-build 0f2925
    h_make { (h_conv h) with
rpm-build 0f2925
      data = Array.map loop (h_conv h).data; 
rpm-build 0f2925
    }
rpm-build 0f2925
rpm-build 0f2925
#if OCAML >= 400
rpm-build 0f2925
  (* copied from stdlib :( *)
rpm-build 0f2925
  let key_index h key =
rpm-build 0f2925
    (* compatibility with old hash tables *)
rpm-build 0f2925
    if Obj.size (Obj.repr h) >= 3
rpm-build 0f2925
    then (seeded_hash_param 10 100 (h_conv h).seed key) land (Array.length (h_conv h).data - 1)
rpm-build 0f2925
    else (old_hash_param 10 100 key) mod (Array.length (h_conv h).data)
rpm-build 0f2925
#else
rpm-build 0f2925
  let key_index h key = (hash key) mod (Array.length (h_conv h).data)
rpm-build 0f2925
#endif
rpm-build 0f2925
rpm-build 0f2925
  let remove_all h key =
rpm-build 0f2925
    let hc = h_conv h in
rpm-build 0f2925
    let rec loop = function
rpm-build 0f2925
      | Empty -> Empty
rpm-build 0f2925
      | Cons(k,v,next) ->
rpm-build 0f2925
        if k = key then begin
rpm-build 0f2925
          hc.size <- pred hc.size;
rpm-build 0f2925
          loop next
rpm-build 0f2925
        end else
rpm-build 0f2925
          Cons(k,v,loop next)
rpm-build 0f2925
    in
rpm-build 0f2925
    let pos = key_index h key in
rpm-build 0f2925
    Array.unsafe_set hc.data pos (loop (Array.unsafe_get hc.data pos))
rpm-build 0f2925
rpm-build 0f2925
  let find_default h key defval =
rpm-build 0f2925
    let rec loop = function
rpm-build 0f2925
      | Empty -> defval
rpm-build 0f2925
      | Cons (k,v,next) ->
rpm-build 0f2925
        if k = key then v else loop next
rpm-build 0f2925
    in
rpm-build 0f2925
    let pos = key_index h key in
rpm-build 0f2925
    loop (Array.unsafe_get (h_conv h).data pos)
rpm-build 0f2925
rpm-build 0f2925
#if OCAML < 405
rpm-build 0f2925
  let find_opt h key =
rpm-build 0f2925
    let rec loop = function
rpm-build 0f2925
      | Empty -> None
rpm-build 0f2925
      | Cons (k,v,next) ->
rpm-build 0f2925
        if k = key then Some v else loop next
rpm-build 0f2925
    in
rpm-build 0f2925
    let pos = key_index h key in
rpm-build 0f2925
    loop (Array.unsafe_get (h_conv h).data pos)
rpm-build 0f2925
#endif
rpm-build 0f2925
rpm-build 0f2925
  let find_option = find_opt
rpm-build 0f2925
rpm-build 0f2925
  let of_enum e =
rpm-build 0f2925
    let h = create (if Enum.fast_count e then Enum.count e else 0) in
rpm-build 0f2925
    Enum.iter (fun (k,v) -> add h k v) e;
rpm-build 0f2925
    h
rpm-build 0f2925
rpm-build 0f2925
  let length h =
rpm-build 0f2925
    (h_conv h).size
rpm-build 0f2925
rpm-build 0f2925
  end