From 34b1a4f9ae7627b47db2995050c590ab7ab5b21a Mon Sep 17 00:00:00 2001 From: Simon Cruanes Date: Sun, 21 Feb 2016 17:15:27 +0100 Subject: [PATCH] add counter function in `CCHashtbl`, to replace `CCHashtbl.Counter` --- src/core/CCHashtbl.ml | 77 ++++++++++++++++++++++++++++++++++++++++-- src/core/CCHashtbl.mli | 54 +++++++++++++++++++++++++++++ 2 files changed, 129 insertions(+), 2 deletions(-) diff --git a/src/core/CCHashtbl.ml b/src/core/CCHashtbl.ml index 665ff329..d5089e6b 100644 --- a/src/core/CCHashtbl.ml +++ b/src/core/CCHashtbl.ml @@ -30,6 +30,20 @@ let values tbl k = Hashtbl.iter (fun _ v -> k v) tbl let keys_list tbl = Hashtbl.fold (fun k _ a -> k::a) tbl [] let values_list tbl = Hashtbl.fold (fun _ v a -> v::a) tbl [] +let incr ?(by=1) tbl x = + let n = get_or tbl x ~or_:0 in + if n+by <= 0 + then Hashtbl.remove tbl x + else Hashtbl.replace tbl x (n+by) + +let decr ?(by=1) tbl x = + try + let n = Hashtbl.find tbl x in + if n-by <= 0 + then Hashtbl.remove tbl x + else Hashtbl.replace tbl x (n-by) + with Not_found -> () + let map_list f h = Hashtbl.fold (fun x y acc -> f x y :: acc) @@ -42,9 +56,18 @@ let map_list f h = let to_seq tbl k = Hashtbl.iter (fun key v -> k (key,v)) tbl +let add_seq tbl seq = seq (fun (k,v) -> Hashtbl.add tbl k v) + let of_seq seq = let tbl = Hashtbl.create 32 in - seq (fun (k,v) -> Hashtbl.add tbl k v); + add_seq tbl seq; + tbl + +let add_seq_count tbl seq = seq (fun k -> incr tbl k) + +let of_seq_count seq = + let tbl = Hashtbl.create 32 in + add_seq_count tbl seq; tbl let to_list tbl = @@ -102,6 +125,19 @@ module type S = sig and returns [or_] otherwise (if [k] doesn't belong in [tbl]) @since NEXT_RELEASE *) + val incr : ?by:int -> int t -> key -> unit + (** [incr ?by tbl x] increments or initializes the counter associated with [x]. + If [get tbl x = None], then after update, [get tbl x = Some 1]; + otherwise, if [get tbl x = Some n], now [get tbl x = Some (n+1)]. + @param by if specified, the int value is incremented by [by] rather than 1 + @since NEXT_RELEASE *) + + val decr : ?by:int -> int t -> key -> unit + (** Same as {!incr} but substract 1 (or the value of [by]). + If the value reaches 0, the key is removed from the table. + This does nothing if the key is not already present in the table. + @since NEXT_RELEASE *) + val keys : 'a t -> key sequence (** Iterate on keys (similar order as {!Hashtbl.iter}) *) @@ -125,6 +161,20 @@ module type S = sig val of_seq : (key * 'a) sequence -> 'a t (** From the given bindings, added in order *) + val add_seq : 'a t -> (key * 'a) sequence -> unit + (** Add the corresponding pairs to the table, using {!Hashtbl.add}. + @since NEXT_RELEASE *) + + val add_seq_count : int t -> key sequence -> unit + (** [add_seq_count tbl seq] increments the count of each element of [seq] + by calling {!incr}. This is useful for counting how many times each + element of [seq] occurs. + @since NEXT_RELEASE *) + + val of_seq_count : key sequence -> int t + (** Similar to {!add_seq_count}, but allocates a new table and returns it + @since NEXT_RELEASE *) + val to_list : 'a t -> (key * 'a) list (** List of bindings (order unspecified) *) @@ -166,6 +216,20 @@ module Make(X : Hashtbl.HashedType) "b" (let tbl = T.of_list [1,"a"; 2,"b"] in T.get_or tbl 2 ~or_:"c") *) + let incr ?(by=1) tbl x = + let n = get_or tbl x ~or_:0 in + if n+by <= 0 + then remove tbl x + else replace tbl x (n+by) + + let decr ?(by=1) tbl x = + try + let n = find tbl x in + if n-by <= 0 + then remove tbl x + else replace tbl x (n-by) + with Not_found -> () + let keys tbl k = iter (fun key _ -> k key) tbl let values tbl k = iter (fun _ v -> k v) tbl @@ -188,9 +252,18 @@ module Make(X : Hashtbl.HashedType) let to_seq tbl k = iter (fun key v -> k (key,v)) tbl + let add_seq tbl seq = seq (fun (k,v) -> add tbl k v) + let of_seq seq = let tbl = create 32 in - seq (fun (k,v) -> add tbl k v); + add_seq tbl seq; + tbl + + let add_seq_count tbl seq = seq (fun k -> incr tbl k) + + let of_seq_count seq = + let tbl = create 32 in + add_seq_count tbl seq; tbl let to_list tbl = diff --git a/src/core/CCHashtbl.mli b/src/core/CCHashtbl.mli index bcbb8187..f6c88c28 100644 --- a/src/core/CCHashtbl.mli +++ b/src/core/CCHashtbl.mli @@ -37,12 +37,39 @@ val values_list : ('a, 'b) Hashtbl.t -> 'b list val map_list : ('a -> 'b -> 'c) -> ('a, 'b) Hashtbl.t -> 'c list (** Map on a hashtable's items, collect into a list *) +val incr : ?by:int -> ('a, int) Hashtbl.t -> 'a -> unit +(** [incr ?by tbl x] increments or initializes the counter associated with [x]. + If [get tbl x = None], then after update, [get tbl x = Some 1]; + otherwise, if [get tbl x = Some n], now [get tbl x = Some (n+1)]. + @param by if specified, the int value is incremented by [by] rather than 1 + @since NEXT_RELEASE *) + +val decr : ?by:int -> ('a, int) Hashtbl.t -> 'a -> unit +(** Same as {!incr} but substract 1 (or the value of [by]). + If the value reaches 0, the key is removed from the table. + This does nothing if the key is not already present in the table. + @since NEXT_RELEASE *) + val to_seq : ('a,'b) Hashtbl.t -> ('a * 'b) sequence (** Iterate on bindings in the table *) +val add_seq : ('a,'b) Hashtbl.t -> ('a * 'b) sequence -> unit +(** Add the corresponding pairs to the table, using {!Hashtbl.add}. + @since NEXT_RELEASE *) + val of_seq : ('a * 'b) sequence -> ('a,'b) Hashtbl.t (** From the given bindings, added in order *) +val add_seq_count : ('a, int) Hashtbl.t -> 'a sequence -> unit +(** [add_seq_count tbl seq] increments the count of each element of [seq] + by calling {!incr}. This is useful for counting how many times each + element of [seq] occurs. + @since NEXT_RELEASE *) + +val of_seq_count : 'a sequence -> ('a, int) Hashtbl.t +(** Similar to {!add_seq_count}, but allocates a new table and returns it + @since NEXT_RELEASE *) + val to_list : ('a,'b) Hashtbl.t -> ('a * 'b) list (** List of bindings (order unspecified) *) @@ -74,6 +101,19 @@ module type S = sig and returns [or_] otherwise (if [k] doesn't belong in [tbl]) @since NEXT_RELEASE *) + val incr : ?by:int -> int t -> key -> unit + (** [incr ?by tbl x] increments or initializes the counter associated with [x]. + If [get tbl x = None], then after update, [get tbl x = Some 1]; + otherwise, if [get tbl x = Some n], now [get tbl x = Some (n+1)]. + @param by if specified, the int value is incremented by [by] rather than 1 + @since NEXT_RELEASE *) + + val decr : ?by:int -> int t -> key -> unit + (** Same as {!incr} but substract 1 (or the value of [by]). + If the value reaches 0, the key is removed from the table. + This does nothing if the key is not already present in the table. + @since NEXT_RELEASE *) + val keys : 'a t -> key sequence (** Iterate on keys (similar order as {!Hashtbl.iter}) *) @@ -97,6 +137,20 @@ module type S = sig val of_seq : (key * 'a) sequence -> 'a t (** From the given bindings, added in order *) + val add_seq : 'a t -> (key * 'a) sequence -> unit + (** Add the corresponding pairs to the table, using {!Hashtbl.add}. + @since NEXT_RELEASE *) + + val add_seq_count : int t -> key sequence -> unit + (** [add_seq_count tbl seq] increments the count of each element of [seq] + by calling {!incr}. This is useful for counting how many times each + element of [seq] occurs. + @since NEXT_RELEASE *) + + val of_seq_count : key sequence -> int t + (** Similar to {!add_seq_count}, but allocates a new table and returns it + @since NEXT_RELEASE *) + val to_list : 'a t -> (key * 'a) list (** List of bindings (order unspecified) *)