diff --git a/pHashtbl.ml b/pHashtbl.ml index 02dc55f2..515ea44f 100644 --- a/pHashtbl.ml +++ b/pHashtbl.ml @@ -51,6 +51,17 @@ let create ?(max_load=0.8) ?(eq=fun x y -> x = y) eq; hash; } +module type Hashable = sig + type t + val equal : t -> t -> bool + val hash : t -> int +end + +(** Create a hashtable from the given 'typeclass' *) +let create_tc (type key) (h : (module Hashable with type t = key)) size = + let module H = (val h) in + create ~eq:H.equal ~hash:H.hash size + (** Copy of the hashtable *) let copy t = { eq = t.eq; @@ -179,6 +190,17 @@ let fold f acc t = done; !acc +(** Map, replaces values by other values *) +let map f t = + let t' = create ~eq:t.eq ~hash:t.hash (Array.length t.buckets) in + for i = 0 to Array.length t.buckets - 1 do + match t.buckets.(i) with + | (_, _, Empty) -> () + | (k, _, Deleted) -> t'.buckets.(i) <- my_deleted k + | (k, v, Used) -> t'.buckets.(i) <- (k, f k v, Used) + done; + t' + (** Destructive filter (remove bindings that do not satisfiy predicate) *) let filter pred t = for i = 0 to Array.length t.buckets - 1 do @@ -201,3 +223,7 @@ let to_seq t = (** Statistics on the table *) let stats t = (Array.length t.buckets, t.size, t.size, 0, 0, 1) + +let get_eq t = t.eq + +let get_hash t = t.hash diff --git a/pHashtbl.mli b/pHashtbl.mli index 3151267f..c92084a2 100644 --- a/pHashtbl.mli +++ b/pHashtbl.mli @@ -25,8 +25,16 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. (** {1 Open addressing hashtable, with linear probing} *) -type ('a, 'b) t - (** Polymorphic hashtable *) +type ('a, 'b) t = private { + mutable buckets : ('a * 'b * state) array; + mutable size : int; + eq : 'a -> 'a -> bool; + hash : 'a -> int; + max_load : float; +} (** A hashtable is an array of (key, value) buckets that have a state, + plus the size of the table and equality/hash functions *) +and state = Used | Empty | Deleted + (** state of a bucket *) val create : ?max_load:float -> ?eq:('a -> 'a -> bool) -> ?hash:('a -> int) -> int -> ('a, 'b) t @@ -34,6 +42,15 @@ val create : ?max_load:float -> ?eq:('a -> 'a -> bool) -> and must be in ]0, 1[. Functions for equality check and hashing can also be provided. *) +module type Hashable = sig + type t + val equal : t -> t -> bool + val hash : t -> int +end + +val create_tc : (module Hashable with type t = 'a) -> int -> ('a, 'b) t + (** Create a hashtable from the given 'typeclass' *) + val copy : ('a, 'b) t -> ('a, 'b) t (** Copy of the hashtable *) @@ -61,6 +78,9 @@ val mem : ('a,_) t -> 'a -> bool val iter : ('a -> 'b -> unit) -> ('a, 'b) t -> unit (** Iterate on bindings *) +val map : ('a -> 'b -> 'c) -> ('a, 'b) t -> ('a, 'c) t + (** Map, replaces values by other values *) + val filter : ('a -> 'b -> bool) -> ('a, 'b) t -> unit (** Destructive filter (remove bindings that do not satisfiy predicate) *) @@ -75,3 +95,7 @@ val to_seq : ('a, 'b) t -> ('a * 'b) Sequence.t val stats : (_, _) t -> int * int * int * int * int * int (** Cf Weak.S *) + +val get_eq : ('v, _) t -> ('v -> 'v -> bool) + +val get_hash : ('v, _) t -> ('v -> int) diff --git a/tests/test_pHashtbl.ml b/tests/test_pHashtbl.ml index 9a021a5e..20a4af72 100644 --- a/tests/test_pHashtbl.ml +++ b/tests/test_pHashtbl.ml @@ -83,6 +83,16 @@ let test_filter () = OUnit.assert_bool "mem" (PHashtbl.mem h 4); OUnit.assert_bool "mem" (PHashtbl.mem h 2) +let test_map () = + let h = PHashtbl.create 5 in + PHashtbl.of_seq h my_seq; + let h' = PHashtbl.map (fun k v -> String.uppercase v) h in + OUnit.assert_equal (PHashtbl.length h') 4; + OUnit.assert_equal (PHashtbl.find h' 1) "A"; + OUnit.assert_equal (PHashtbl.find h' 2) "B"; + OUnit.assert_equal (PHashtbl.find h' 3) "C"; + OUnit.assert_equal (PHashtbl.find h' 4) "D" + let suite = "test_pHashtbl" >::: [ "test_add" >:: test_add;