diff --git a/src/core/CCMap.ml b/src/core/CCMap.ml index 8caa6a11..9beedded 100644 --- a/src/core/CCMap.ml +++ b/src/core/CCMap.ml @@ -23,6 +23,31 @@ module type S = sig [k] is removed from [m], and if the result is [Some v'] then [add k v' m] is returned. *) + val choose_opt : 'a t -> (key * 'a) option + (** Safe version of {!choose} + @since NEXT_RELEASE *) + + val min_binding_opt : 'a t -> (key * 'a) option + (** Safe version of {!min_binding} + @since NEXT_RELEASE *) + + val max_binding_opt : 'a t -> (key * 'a) option + (** Safe version of {!max_binding} + @since NEXT_RELEASE *) + + val find_opt : key -> 'a t -> 'a option + (** Safe version of {!find} + @since NEXT_RELEASE *) + + val find_first : (key -> bool) -> 'a t -> key * 'a + (** Find smallest binding satisfying the monotonic predicate. + See {!Map.S.find_first}. + @since NEXT_RELEASE *) + + val find_first_opt : (key -> bool) -> 'a t -> (key * 'a) option + (** Safe version of {!find_first} + @since NEXT_RELEASE *) + val merge_safe : f:(key -> [`Left of 'a | `Right of 'b | `Both of 'a * 'b] -> 'c option) -> 'a t -> 'b t -> 'c t @@ -35,6 +60,7 @@ module type S = sig @since 1.4 *) val of_seq : (key * 'a) sequence -> 'a t + (** Same as {!of_list} *) val add_seq : 'a t -> (key * 'a) sequence -> 'a t (** @since 0.14 *) @@ -42,6 +68,10 @@ module type S = sig val to_seq : 'a t -> (key * 'a) sequence val of_list : (key * 'a) list -> 'a t + (** Build a map from the given list of bindings [k_i -> v_i], + added in order using {!add}. + If a key occurs several times, only its last binding + will be present in the result. *) val add_list : 'a t -> (key * 'a) list -> 'a t (** @since 0.14 *) @@ -62,12 +92,70 @@ module type S = sig end module Make(O : Map.OrderedType) = struct - include Map.Make(O) + module M = Map.Make(O) - let get k m = - try Some (find k m) + (* overload [union] if it's not in [M] *) + let union f a b = + M.merge + (fun k v1 v2 -> match v1, v2 with + | None, None -> assert false + | None, (Some _ as r) -> r + | Some _ as r, None -> r + | Some v1, Some v2 -> f k v1 v2) + a b + + let choose_opt m = + try Some (M.choose m) with Not_found -> None + let find_opt k m = + try Some (M.find k m) + with Not_found -> None + + let max_binding_opt m = + try Some (M.max_binding m) + with Not_found -> None + + let min_binding_opt m = + try Some (M.min_binding m) + with Not_found -> None + + exception Find_binding_exit + + let find_first_opt f m = + let res = ref None in + try + M.iter + (fun k v -> + if f k then ( + res := Some (k,v); + raise Find_binding_exit + )) + m; + None + with Find_binding_exit -> + !res + + let find_first f m = match find_first_opt f m with + | None -> raise Not_found + | Some (k,v) -> k, v + + (* linear time, must traverse the whole map… *) + let find_last_opt f m = + let res = ref None in + M.iter + (fun k v -> if f k then res := Some (k,v)) + m; + !res + + let find_last f m = match find_last_opt f m with + | None -> raise Not_found + | Some (k,v) -> k, v + + include M + + let get = find_opt + let get_or k m ~default = try find k m with Not_found -> default @@ -90,15 +178,6 @@ module Make(O : Map.OrderedType) = struct | Some v1, Some v2 -> f k (`Both (v1,v2))) a b - let union f a b = - merge - (fun k v1 v2 -> match v1, v2 with - | None, None -> assert false - | None, (Some _ as r) -> r - | Some _ as r, None -> r - | Some v1, Some v2 -> f k v1 v2) - a b - let add_seq m s = let m = ref m in s (fun (k,v) -> m := add k v !m); diff --git a/src/core/CCMap.mli b/src/core/CCMap.mli index 5804b5a6..1fa26139 100644 --- a/src/core/CCMap.mli +++ b/src/core/CCMap.mli @@ -26,6 +26,31 @@ module type S = sig [k] is removed from [m], and if the result is [Some v'] then [add k v' m] is returned. *) + val choose_opt : 'a t -> (key * 'a) option + (** Safe version of {!choose} + @since NEXT_RELEASE *) + + val min_binding_opt : 'a t -> (key * 'a) option + (** Safe version of {!min_binding} + @since NEXT_RELEASE *) + + val max_binding_opt : 'a t -> (key * 'a) option + (** Safe version of {!max_binding} + @since NEXT_RELEASE *) + + val find_opt : key -> 'a t -> 'a option + (** Safe version of {!find} + @since NEXT_RELEASE *) + + val find_first : (key -> bool) -> 'a t -> key * 'a + (** Find smallest binding satisfying the monotonic predicate. + See {!Map.S.find_first}. + @since NEXT_RELEASE *) + + val find_first_opt : (key -> bool) -> 'a t -> (key * 'a) option + (** Safe version of {!find_first} + @since NEXT_RELEASE *) + val merge_safe : f:(key -> [`Left of 'a | `Right of 'b | `Both of 'a * 'b] -> 'c option) -> 'a t -> 'b t -> 'c t diff --git a/src/core/CCSet.ml b/src/core/CCSet.ml index cff89e3e..45195921 100644 --- a/src/core/CCSet.ml +++ b/src/core/CCSet.ml @@ -9,6 +9,38 @@ type 'a printer = Format.formatter -> 'a -> unit module type S = sig include Set.S + val min_elt_opt : t -> elt option + (** Safe version of {!min_elt} + @since NEXT_RELEASE *) + + val max_elt_opt : t -> elt option + (** Safe version of {!max_elt} + @since NEXT_RELEASE *) + + val choose_opt : t -> elt option + (** Safe version of {!choose} + @since NEXT_RELEASE *) + + val find_opt : elt -> t -> elt option + (** Safe version of {!find} + @since NEXT_RELEASE *) + + val find_first : (elt -> bool) -> t -> elt + (** Find minimum element satisfying predicate + @since NEXT_RELEASE *) + + val find_first_opt : (elt -> bool) -> t -> elt option + (** Safe version of {!find_first} + @since NEXT_RELEASE *) + + val find_last : (elt -> bool) -> t -> elt + (** Find maximum element satisfying predicate + @since NEXT_RELEASE *) + + val find_last_opt : (elt -> bool) -> t -> elt option + (** Safe version of {!find_last} + @since NEXT_RELEASE *) + val of_seq : elt sequence -> t val add_seq : t -> elt sequence -> t @@ -17,6 +49,8 @@ module type S = sig val to_seq : t -> elt sequence val of_list : elt list -> t + (** Build a set from the given list of elements, + added in order using {!add}. *) val add_list : t -> elt list -> t (** @since 0.14 *) @@ -29,7 +63,57 @@ module type S = sig end module Make(O : Map.OrderedType) = struct - include Set.Make(O) + module S = Set.Make(O) + + let find_opt x s = + try Some (S.find x s) + with Not_found -> None + + let choose_opt s = + try Some (S.choose s) + with Not_found -> None + + let min_elt_opt s = + try Some (S.min_elt s) + with Not_found -> None + + let max_elt_opt s = + try Some (S.max_elt s) + with Not_found -> None + + exception Find_binding_exit + + let find_first_opt f m = + let res = ref None in + try + S.iter + (fun x -> + if f x then ( + res := Some x; + raise Find_binding_exit + )) + m; + None + with Find_binding_exit -> + !res + + let find_first f m = match find_first_opt f m with + | None -> raise Not_found + | Some x -> x + + (* linear time, must traverse the whole set… *) + let find_last_opt f m = + let res = ref None in + S.iter + (fun x -> if f x then res := Some x) + m; + !res + + let find_last f m = match find_last_opt f m with + | None -> raise Not_found + | Some x -> x + + include S let add_seq set seq = let set = ref set in diff --git a/src/core/CCSet.mli b/src/core/CCSet.mli index 4f36ccb7..0af84de8 100644 --- a/src/core/CCSet.mli +++ b/src/core/CCSet.mli @@ -11,6 +11,38 @@ type 'a printer = Format.formatter -> 'a -> unit module type S = sig include Set.S + val min_elt_opt : t -> elt option + (** Safe version of {!min_elt} + @since NEXT_RELEASE *) + + val max_elt_opt : t -> elt option + (** Safe version of {!max_elt} + @since NEXT_RELEASE *) + + val choose_opt : t -> elt option + (** Safe version of {!choose} + @since NEXT_RELEASE *) + + val find_opt : elt -> t -> elt option + (** Safe version of {!find} + @since NEXT_RELEASE *) + + val find_first : (elt -> bool) -> t -> elt + (** Find minimum element satisfying predicate + @since NEXT_RELEASE *) + + val find_first_opt : (elt -> bool) -> t -> elt option + (** Safe version of {!find_first} + @since NEXT_RELEASE *) + + val find_last : (elt -> bool) -> t -> elt + (** Find maximum element satisfying predicate + @since NEXT_RELEASE *) + + val find_last_opt : (elt -> bool) -> t -> elt option + (** Safe version of {!find_last} + @since NEXT_RELEASE *) + val of_seq : elt sequence -> t val add_seq : t -> elt sequence -> t