From 708a92d027f6ec5634caaf8aca4fd3fab6f2c2e0 Mon Sep 17 00:00:00 2001 From: Simon Cruanes Date: Thu, 18 Feb 2016 12:21:21 +0100 Subject: [PATCH] add `{CCMap,CCHashtbl}.get_or` for lookup with default value --- src/core/CCHashtbl.ml | 32 +++++++++++++++++++++++++++++--- src/core/CCHashtbl.mli | 10 ++++++++++ src/core/CCMap.ml | 9 +++++++++ src/core/CCMap.mli | 5 +++++ 4 files changed, 53 insertions(+), 3 deletions(-) diff --git a/src/core/CCHashtbl.ml b/src/core/CCHashtbl.ml index 856dee9a..665ff329 100644 --- a/src/core/CCHashtbl.ml +++ b/src/core/CCHashtbl.ml @@ -1,7 +1,6 @@ (* This file is free software, part of containers. See file "license" for more details. *) - (** {1 Extension to the standard Hashtbl} *) type 'a sequence = ('a -> unit) -> unit @@ -15,6 +14,15 @@ let get tbl x = try Some (Hashtbl.find tbl x) with Not_found -> None +let get_or tbl x ~or_ = + try Hashtbl.find tbl x + with Not_found -> or_ + +(*$= + "c" (let tbl = of_list [1,"a"; 2,"b"] in get_or tbl 3 ~or_:"c") + "b" (let tbl = of_list [1,"a"; 2,"b"] in get_or tbl 2 ~or_:"c") +*) + let keys tbl k = Hashtbl.iter (fun key _ -> k key) tbl let values tbl k = Hashtbl.iter (fun _ v -> k v) tbl @@ -89,6 +97,11 @@ module type S = sig val get : 'a t -> key -> 'a option (** Safe version of {!Hashtbl.find} *) + val get_or : 'a t -> key -> or_:'a -> 'a + (** [get_or tbl k ~or_] returns the value associated to [k] if present, + and returns [or_] otherwise (if [k] doesn't belong in [tbl]) + @since NEXT_RELEASE *) + val keys : 'a t -> key sequence (** Iterate on keys (similar order as {!Hashtbl.iter}) *) @@ -96,11 +109,11 @@ module type S = sig (** Iterate on values in the table *) val keys_list : ('a, 'b) Hashtbl.t -> 'a list - (** [keys_list t] is the list of keys in [t]. + (** [keys t] is the list of keys in [t]. @since 0.8 *) val values_list : ('a, 'b) Hashtbl.t -> 'b list - (** [values_list t] is the list of values in [t]. + (** [values t] is the list of values in [t]. @since 0.8 *) val map_list : (key -> 'a -> 'b) -> 'a t -> 'b list @@ -131,6 +144,10 @@ module type S = sig @since 0.13 *) end +(*$inject + module T = Make(CCInt) +*) + module Make(X : Hashtbl.HashedType) : S with type key = X.t and type 'a t = 'a Hashtbl.Make(X).t = struct @@ -140,6 +157,15 @@ module Make(X : Hashtbl.HashedType) try Some (find tbl x) with Not_found -> None + let get_or tbl x ~or_ = + try find tbl x + with Not_found -> or_ + + (*$= + "c" (let tbl = T.of_list [1,"a"; 2,"b"] in T.get_or tbl 3 ~or_:"c") + "b" (let tbl = T.of_list [1,"a"; 2,"b"] in T.get_or tbl 2 ~or_:"c") + *) + let keys tbl k = iter (fun key _ -> k key) tbl let values tbl k = iter (fun _ v -> k v) tbl diff --git a/src/core/CCHashtbl.mli b/src/core/CCHashtbl.mli index a2ea8850..79bc22b8 100644 --- a/src/core/CCHashtbl.mli +++ b/src/core/CCHashtbl.mli @@ -15,6 +15,11 @@ type 'a printer = Format.formatter -> 'a -> unit val get : ('a,'b) Hashtbl.t -> 'a -> 'b option (** Safe version of {!Hashtbl.find} *) +val get_or : ('a,'b) Hashtbl.t -> 'a -> or_:'b -> 'b +(** [get_or tbl k ~or_] returns the value associated to [k] if present, + and returns [or_] otherwise (if [k] doesn't belong in [tbl]) + @since NEXT_RELEASE *) + val keys : ('a,'b) Hashtbl.t -> 'a sequence (** Iterate on keys (similar order as {!Hashtbl.iter}) *) @@ -64,6 +69,11 @@ module type S = sig val get : 'a t -> key -> 'a option (** Safe version of {!Hashtbl.find} *) + val get_or : 'a t -> key -> or_:'a -> 'a + (** [get_or tbl k ~or_] returns the value associated to [k] if present, + and returns [or_] otherwise (if [k] doesn't belong in [tbl]) + @since NEXT_RELEASE *) + val keys : 'a t -> key sequence (** Iterate on keys (similar order as {!Hashtbl.iter}) *) diff --git a/src/core/CCMap.ml b/src/core/CCMap.ml index 14f7f885..087eaaeb 100644 --- a/src/core/CCMap.ml +++ b/src/core/CCMap.ml @@ -13,6 +13,11 @@ module type S = sig val get : key -> 'a t -> 'a option (** Safe version of {!find} *) + val get_or : key -> 'a t -> or_:'a -> 'a + (** [get_or k m ~or_] returns the value associated to [k] if present, + and returns [or_] otherwise (if [k] doesn't belong in [m]) + @since NEXT_RELEASE *) + val update : key -> ('a option -> 'a option) -> 'a t -> 'a t (** [update k f m] calls [f (Some v)] if [find k m = v], otherwise it calls [f None]. In any case, if the result is [None] @@ -57,6 +62,10 @@ module Make(O : Map.OrderedType) = struct try Some (find k m) with Not_found -> None + let get_or k m ~or_ = + try find k m + with Not_found -> or_ + let update k f m = let x = try f (Some (find k m)) diff --git a/src/core/CCMap.mli b/src/core/CCMap.mli index 436a4d41..819ba2b6 100644 --- a/src/core/CCMap.mli +++ b/src/core/CCMap.mli @@ -16,6 +16,11 @@ module type S = sig val get : key -> 'a t -> 'a option (** Safe version of {!find} *) + val get_or : key -> 'a t -> or_:'a -> 'a + (** [get_or k m ~or_] returns the value associated to [k] if present, + and returns [or_] otherwise (if [k] doesn't belong in [m]) + @since NEXT_RELEASE *) + val update : key -> ('a option -> 'a option) -> 'a t -> 'a t (** [update k f m] calls [f (Some v)] if [find k m = v], otherwise it calls [f None]. In any case, if the result is [None]