(* (c) 2017, 2018 Hannes Mehnert, all rights reserved *) (* this code wouldn't exist without Justus Matthiesen, thanks for the help! *) module Order = struct type (_,_) t = | Lt : ('a, 'b) t | Eq : ('a, 'a) t | Gt : ('a, 'b) t end module type KEY = sig type _ t val compare : 'a t -> 'b t -> ('a, 'b) Order.t end module type S = sig type 'a key type t val empty : t val singleton : 'a key -> 'a -> t val is_empty : t -> bool val cardinal : t -> int val mem : 'a key -> t -> bool val find : 'a key -> t -> 'a option val get : 'a key -> t -> 'a val add_unless_bound : 'a key -> 'a -> t -> t option val add : 'a key -> 'a -> t -> t val remove : 'a key -> t -> t val update : 'a key -> ('a option -> 'a option) -> t -> t type b = B : 'a key * 'a -> b val min_binding : t -> b option val max_binding : t -> b option val any_binding : t -> b option val bindings : t -> b list type eq = { f : 'a . 'a key -> 'a -> 'a -> bool } val equal : eq -> t -> t -> bool type mapper = { f : 'a. 'a key -> 'a -> 'a } val map : mapper -> t -> t val iter : (b -> unit) -> t -> unit val fold : (b -> 'a -> 'a) -> t -> 'a -> 'a val for_all : (b -> bool) -> t -> bool val exists : (b -> bool) -> t -> bool val filter : (b -> bool) -> t -> t type merger = { f : 'a. 'a key -> 'a option -> 'a option -> 'a option } val merge : merger -> t -> t -> t type unionee = { f : 'a. 'a key -> 'a -> 'a -> 'a option } val union : unionee -> t -> t -> t end module Make (Key : KEY) : S with type 'a key = 'a Key.t = struct type 'a key = 'a Key.t type k = K : 'a key -> k type b = B : 'a key * 'a -> b module M = Map.Make(struct type t = k let compare (K a) (K b) = match Key.compare a b with | Order.Lt -> -1 | Order.Eq -> 0 | Order.Gt -> 1 end) type t = b M.t let empty = M.empty let singleton k v = M.singleton (K k) (B (k, v)) let is_empty = M.is_empty let mem k m = M.mem (K k) m let add k v m = M.add (K k) (B (k, v)) m let add_unless_bound k v m = if mem k m then None else Some (add k v m) let remove k m = M.remove (K k) m let get : type a. a key -> t -> a = fun k m -> match M.find (K k) m with | B (k', v) -> (* TODO this compare (and further below similar ones) is only needed for the type checker (to get the k = k' proof), because the invariant foreach k . t [K k] = B (k', v) -> k = k' is preserved by this library it could be replaced by: - Obj.magic - vendor and slight modification of Stdlib.Map - using integers as key -> compare can be a single instruction Stay better safe than sorry (at least for now) *) match Key.compare k k' with | Order.Eq -> v | _ -> assert false let find : type a. a key -> t -> a option = fun k m -> try Some (get k m) with Not_found -> None let update k f m = match f (find k m) with | None -> remove k m | Some v -> add k v m let any_binding m = try Some (snd (M.choose m)) with Not_found -> None let min_binding m = try Some (snd (M.min_binding m)) with Not_found -> None let max_binding m = try Some (snd (M.max_binding m)) with Not_found -> None let bindings m = snd (List.split (M.bindings m)) let cardinal m = M.cardinal m let for_all p m = M.for_all (fun _ b -> p b) m let exists p m = M.exists (fun _ b -> p b) m let iter f m = M.iter (fun _ b -> f b) m let fold f m acc = M.fold (fun _ b acc -> f b acc) m acc let filter p m = M.filter (fun _ b -> p b) m type mapper = { f : 'a. 'a key -> 'a -> 'a } let map f m = M.map (fun (B (k, v)) -> B (k, f.f k v)) m type merger = { f : 'a. 'a key -> 'a option -> 'a option -> 'a option } let merge f m m' = M.merge (fun (K k) b b' -> match b, b' with | None, None -> begin match f.f k None None with | None -> None | Some v -> Some (B (k, v)) end | None, Some (B (k', v)) -> (* see above comment about compare *) begin match Key.compare k k' with | Order.Eq -> (match f.f k None (Some v) with | None -> None | Some v -> Some (B (k, v))) | _ -> assert false end | Some (B (k', v)), None -> (* see above comment about compare *) begin match Key.compare k k' with | Order.Eq -> (match f.f k (Some v) None with | None -> None | Some v -> Some (B (k, v))) | _ -> assert false end | Some (B (k', v)), Some (B (k'', v')) -> (* see above comment about compare *) begin match Key.compare k k', Key.compare k k'' with | Order.Eq, Order.Eq -> (match f.f k (Some v) (Some v') with | None -> None | Some v -> Some (B (k, v))) | _ -> assert false end) m m' type unionee = { f : 'a. 'a key -> 'a -> 'a -> 'a option } let union f m m' = M.union (fun (K k) (B (k', v)) (B (k'', v')) -> (* see above comment about compare *) match Key.compare k k', Key.compare k k'' with | Order.Eq, Order.Eq -> (match f.f k v v' with None -> None | Some v'' -> Some (B (k, v''))) | _ -> assert false) m m' type eq = { f : 'a . 'a key -> 'a -> 'a -> bool } let equal cmp m m' = M.equal (fun (B (k, v)) (B (k', v')) -> (* see above comment about compare *) match Key.compare k k' with | Order.Eq -> cmp.f k v v' | _ -> assert false) m m' end