diff options
Diffstat (limited to 'clib')
| -rw-r--r-- | clib/cArray.ml | 25 | ||||
| -rw-r--r-- | clib/cArray.mli | 19 | ||||
| -rw-r--r-- | clib/cEphemeron.ml | 163 | ||||
| -rw-r--r-- | clib/cEphemeron.mli | 6 | ||||
| -rw-r--r-- | clib/cList.ml | 20 | ||||
| -rw-r--r-- | clib/cList.mli | 15 | ||||
| -rw-r--r-- | clib/cMap.ml | 11 | ||||
| -rw-r--r-- | clib/cMap.mli | 6 | ||||
| -rw-r--r-- | clib/hMap.ml | 3 | ||||
| -rw-r--r-- | clib/option.ml | 4 | ||||
| -rw-r--r-- | clib/option.mli | 7 |
11 files changed, 94 insertions, 185 deletions
diff --git a/clib/cArray.ml b/clib/cArray.ml index b9dcfd61d1..d3fa4ef65e 100644 --- a/clib/cArray.ml +++ b/clib/cArray.ml @@ -49,10 +49,6 @@ sig val map_to_list : ('a -> 'b) -> 'a array -> 'b list val map_of_list : ('a -> 'b) -> 'a list -> 'b array val chop : int -> 'a array -> 'a array * 'a array - val smartmap : ('a -> 'a) -> 'a array -> 'a array - [@@ocaml.deprecated "Same as [Smart.map]"] - val smartfoldmap : ('r -> 'a -> 'r * 'a) -> 'r -> 'a array -> 'r * 'a array - [@@ocaml.deprecated "Same as [Smart.fold_left_map]"] val map2 : ('a -> 'b -> 'c) -> 'a array -> 'b array -> 'c array val map2_i : (int -> 'a -> 'b -> 'c) -> 'a array -> 'b array -> 'c array val map3 : @@ -65,13 +61,6 @@ sig val fold_left2_map : ('a -> 'b -> 'c -> 'a * 'd) -> 'a -> 'b array -> 'c array -> 'a * 'd array val fold_left2_map_i : (int -> 'a -> 'b -> 'c -> 'a * 'd) -> 'a -> 'b array -> 'c array -> 'a * 'd array val fold_right2_map : ('a -> 'b -> 'c -> 'd * 'c) -> 'a array -> 'b array -> 'c -> 'd array * 'c - val fold_map : ('a -> 'b -> 'a * 'c) -> 'a -> 'b array -> 'a * 'c array - [@@ocaml.deprecated "Same as [fold_left_map]"] - val fold_map' : ('a -> 'c -> 'b * 'c) -> 'a array -> 'c -> 'b array * 'c - [@@ocaml.deprecated "Same as [fold_right_map]"] - val fold_map2' : - ('a -> 'b -> 'c -> 'd * 'c) -> 'a array -> 'b array -> 'c -> 'd array * 'c - [@@ocaml.deprecated "Same as [fold_right2_map]"] val distinct : 'a array -> bool val rev_of_list : 'a list -> 'a array val rev_to_list : 'a array -> 'a list @@ -86,8 +75,6 @@ sig module Fun1 : sig val map : ('r -> 'a -> 'b) -> 'r -> 'a array -> 'b array - val smartmap : ('r -> 'a -> 'a) -> 'r -> 'a array -> 'a array - [@@ocaml.deprecated "Same as [Fun1.Smart.map]"] val iter : ('r -> 'a -> unit) -> 'r -> 'a array -> unit val iter2 : ('r -> 'a -> 'b -> unit) -> 'r -> 'a array -> 'b array -> unit module Smart : @@ -429,15 +416,11 @@ else let v' = Array.map (fun x -> let (y,e) = f x !e' in e' := e; y) v in (v',!e') -let fold_map' = fold_right_map - let fold_left_map f e v = let e' = ref e in let v' = Array.map (fun x -> let (e,y) = f !e' x in e' := e; y) v in (!e',v') -let fold_map = fold_left_map - let fold_right2_map f v1 v2 e = let e' = ref e in let v' = @@ -445,8 +428,6 @@ let fold_right2_map f v1 v2 e = in (v',!e') -let fold_map2' = fold_right2_map - let fold_left2_map f e v1 v2 = let e' = ref e in let v' = map2 (fun x1 x2 -> let (e,y) = f !e' x1 x2 in e' := e; y) v1 v2 in @@ -617,10 +598,6 @@ struct end -(* Deprecated aliases *) -let smartmap = Smart.map -let smartfoldmap = Smart.fold_left_map - module Fun1 = struct @@ -687,6 +664,4 @@ struct end - let smartmap = Smart.map - end diff --git a/clib/cArray.mli b/clib/cArray.mli index 163191681a..f5b015b206 100644 --- a/clib/cArray.mli +++ b/clib/cArray.mli @@ -82,12 +82,6 @@ sig (** [chop i a] returns [(a1, a2)] s.t. [a = a1 + a2] and [length a1 = n]. Raise [Failure "Array.chop"] if [i] is not a valid index. *) - val smartmap : ('a -> 'a) -> 'a array -> 'a array - [@@ocaml.deprecated "Same as [Smart.map]"] - - val smartfoldmap : ('r -> 'a -> 'r * 'a) -> 'r -> 'a array -> 'r * 'a array - [@@ocaml.deprecated "Same as [Smart.fold_left_map]"] - val map2 : ('a -> 'b -> 'c) -> 'a array -> 'b array -> 'c array (** See also [Smart.map2] *) @@ -121,16 +115,6 @@ sig val fold_right2_map : ('a -> 'b -> 'c -> 'd * 'c) -> 'a array -> 'b array -> 'c -> 'd array * 'c (** Same with two arrays, folding on the left *) - val fold_map : ('a -> 'b -> 'a * 'c) -> 'a -> 'b array -> 'a * 'c array - [@@ocaml.deprecated "Same as [fold_left_map]"] - - val fold_map' : ('a -> 'c -> 'b * 'c) -> 'a array -> 'c -> 'b array * 'c - [@@ocaml.deprecated "Same as [fold_right_map]"] - - val fold_map2' : - ('a -> 'b -> 'c -> 'd * 'c) -> 'a array -> 'b array -> 'c -> 'd array * 'c - [@@ocaml.deprecated "Same as [fold_right2_map]"] - val distinct : 'a array -> bool (** Return [true] if every element of the array is unique (for default equality). *) @@ -175,9 +159,6 @@ sig val map : ('r -> 'a -> 'b) -> 'r -> 'a array -> 'b array (** [Fun1.map f x v = map (f x) v] *) - val smartmap : ('r -> 'a -> 'a) -> 'r -> 'a array -> 'a array - [@@ocaml.deprecated "Same as [Fun1.Smart.map]"] - val iter : ('r -> 'a -> unit) -> 'r -> 'a array -> unit (** [Fun1.iter f x v = iter (f x) v] *) diff --git a/clib/cEphemeron.ml b/clib/cEphemeron.ml index 3136d66e34..d7cc0a4dc2 100644 --- a/clib/cEphemeron.ml +++ b/clib/cEphemeron.ml @@ -8,84 +8,103 @@ (* * (see LICENSE file for the text of the license) *) (************************************************************************) -type key_type = int - -type boxed_key = key_type ref ref - -let mk_key : unit -> boxed_key = - (* TODO: take a random value here. Is there a random function in OCaml? *) - let bid = ref 0 in - (* According to OCaml Gc module documentation, Pervasives.ref is one of the - few ways of getting a boxed value the compiler will never alias. *) - fun () -> incr bid; Pervasives.ref (Pervasives.ref !bid) - -(* A phantom type to preserve type safety *) -type 'a key = boxed_key - -(* Comparing keys with == grants that if a key is unmarshalled (in the same - process where it was created or in another one) it is not mistaken for - an already existing one (unmarshal has no right to alias). If the initial - value of bid is taken at random, then one also avoids potential collisions *) -module HT = Hashtbl.Make(struct - type t = key_type ref - let equal k1 k2 = k1 == k2 - let hash id = !id +(* Type-safe implementation by whitequark *) + +(* An extensible variant has an internal representation equivalent + to the following: + + type constr = { + name: string, + id: int + } + type value = (*Object_tag*) constr * v1 * v2... + + and the code generated by the compiler looks like: + + (* type X += Y *) + let constr_Y = alloc { "Y", %caml_fresh_oo_id () } + (* match x with Y -> a | _ -> b *) + if x.0 == constr_Y then a else b + + and the polymorphic comparison function works like: + + let equal = fun (c1, ...) (c2, ...) -> + c1.id == c2.id + + In every new extension constructor, the name field is a constant + string and the id field is filled with an unique[1] value returned + by %caml_fresh_oo_id. Moreover, every value of an extensible variant + type is allocated as a new block. + + [1]: On 64-bit systems. On 32-bit systems, calling %caml_fresh_oo_id + 2**30 times will result in a wraparound. Note that this does + not affect soundness because constructors are compared by + physical equality during matching. See OCaml PR7809 for code + demonstrating this. + + An extensible variant can be marshalled and unmarshalled, and + is guaranteed to not be equal to itself after unmarshalling, + since the id field is filled with another unique value. + + Note that the explanation above is purely informative and we + do not depend on the exact representation of extensible variants, + only on the fact that no two constructor representations ever + alias. In particular, if the definition of constr is replaced with: + + type constr = int + + (where the value is truly unique for every created constructor), + correctness is preserved. + *) +type 'a typ = .. + +(* Erases the contained type so that the key can be put in a hash table. *) +type boxkey = Box : 'a typ -> boxkey [@@unboxed] + +(* Carry the type we just erased with the actual key. *) +type 'a key = 'a typ * boxkey + +module EHashtbl = Ephemeron.K1.Make(struct + type t = boxkey + let equal = (==) + let hash = Hashtbl.hash end) -(* A key is the (unique) value inside a boxed key, hence it does not - keep its corresponding boxed key reachable (replacing key_type by boxed_key - would make the key always reachable) *) -let values : Obj.t HT.t = HT.create 1001 - -(* To avoid a race condition between the finalization function and - get/create on the values hashtable, the finalization function just - enqueues in an imperative list the item to be collected. Being the list - imperative, even if the Gc enqueues an item while run_collection is operating, - the tail of the list is eventually set to Empty on completion. - Kudos to the authors of Why3 that came up with this solution for their - implementation of weak hash tables! *) -type imperative_list = cell ref -and cell = Empty | Item of key_type ref * imperative_list - -let collection_queue : imperative_list ref = ref (ref Empty) - -let enqueue x = collection_queue := ref (Item (!x, !collection_queue)) - -let run_collection () = - let rec aux l = match !l with - | Empty -> () - | Item (k, tl) -> HT.remove values k; aux tl in - let l = !collection_queue in - aux l; - l := Empty - -(* The only reference to the boxed key is the one returned, when the user drops - it the value eventually disappears from the values table above *) -let create (v : 'a) : 'a key = - run_collection (); - let k = mk_key () in - HT.add values !k (Obj.repr v); - Gc.finalise enqueue k; - k +type value = { get : 'k. 'k typ -> 'k } [@@unboxed] + +let values : value EHashtbl.t = + EHashtbl.create 1001 + +let create : type v. v -> v key = + fun value -> + let module M = struct + type _ typ += Typ : v typ + + let get : type k. k typ -> k = + fun typ -> + match typ with + | Typ -> value + | _ -> assert false + + let boxkey = Box Typ + let key = Typ, boxkey + let value = { get } + end in + EHashtbl.add values M.boxkey M.value; + M.key (* Avoid raising Not_found *) exception InvalidKey -let get (k : 'a key) : 'a = - run_collection (); - try Obj.obj (HT.find values !k) +let get (typ, boxkey) = + try (EHashtbl.find values boxkey).get typ with Not_found -> raise InvalidKey -(* Simple utils *) -let default k v = - try get k - with InvalidKey -> v +let default (typ, boxkey) default = + try (EHashtbl.find values boxkey).get typ + with Not_found -> default -let iter_opt k f = - match - try Some (get k) - with InvalidKey -> None - with - | None -> () - | Some v -> f v +let iter_opt (typ, boxkey) f = + try f ((EHashtbl.find values boxkey).get typ) + with Not_found -> () -let clear () = run_collection () +let clean () = EHashtbl.clean values diff --git a/clib/cEphemeron.mli b/clib/cEphemeron.mli index 8e753d0b62..96391e10fa 100644 --- a/clib/cEphemeron.mli +++ b/clib/cEphemeron.mli @@ -33,7 +33,7 @@ An ['a key] can always be marshalled. When marshalled, a key loses its value. The function [get] raises Not_found on unmarshalled keys. - + If a key is garbage collected, the corresponding value is garbage collected too (unless extra references to it exist). In short no memory management hassle, keys can just replace their @@ -48,7 +48,7 @@ exception InvalidKey val get : 'a key -> 'a (* These never fail. *) -val iter_opt : 'a key -> ('a -> unit) -> unit val default : 'a key -> 'a -> 'a +val iter_opt : 'a key -> ('a -> unit) -> unit -val clear : unit -> unit +val clean : unit -> unit diff --git a/clib/cList.ml b/clib/cList.ml index dc59ff2970..aba3e46bd5 100644 --- a/clib/cList.ml +++ b/clib/cList.ml @@ -36,16 +36,12 @@ sig val filteri : (int -> 'a -> bool) -> 'a list -> 'a list val filter_with : bool list -> 'a list -> 'a list - val smartfilter : ('a -> bool) -> 'a list -> 'a list - [@@ocaml.deprecated "Same as [filter]"] val map_filter : ('a -> 'b option) -> 'a list -> 'b list val map_filter_i : (int -> 'a -> 'b option) -> 'a list -> 'b list val partitioni : (int -> 'a -> bool) -> 'a list -> 'a list * 'a list val map : ('a -> 'b) -> 'a list -> 'b list val map2 : ('a -> 'b -> 'c) -> 'a list -> 'b list -> 'c list - val smartmap : ('a -> 'a) -> 'a list -> 'a list - [@@ocaml.deprecated "Same as [Smart.map]"] val map_left : ('a -> 'b) -> 'a list -> 'b list val map_i : (int -> 'a -> 'b) -> int -> 'a list -> 'b list val map2_i : @@ -75,10 +71,6 @@ sig val fold_right2_map : ('b -> 'c -> 'a -> 'd * 'a) -> 'b list -> 'c list -> 'a -> 'd list * 'a val fold_left3_map : ('a -> 'b -> 'c -> 'd -> 'a * 'e) -> 'a -> 'b list -> 'c list -> 'd list -> 'a * 'e list val fold_left4_map : ('a -> 'b -> 'c -> 'd -> 'e -> 'a * 'r) -> 'a -> 'b list -> 'c list -> 'd list -> 'e list -> 'a * 'r list - val fold_map : ('a -> 'b -> 'a * 'c) -> 'a -> 'b list -> 'a * 'c list - [@@ocaml.deprecated "Same as [fold_left_map]"] - val fold_map' : ('b -> 'a -> 'c * 'a) -> 'b list -> 'a -> 'c list * 'a - [@@ocaml.deprecated "Same as [fold_right_map]"] val except : 'a eq -> 'a -> 'a list -> 'a list val remove : 'a eq -> 'a -> 'a list -> 'a list val remove_first : ('a -> bool) -> 'a list -> 'a list @@ -116,8 +108,6 @@ sig val unionq : 'a list -> 'a list -> 'a list val subtract : 'a eq -> 'a list -> 'a list -> 'a list val subtractq : 'a list -> 'a list -> 'a list - val merge_uniq : ('a -> 'a -> int) -> 'a list -> 'a list -> 'a list - [@@ocaml.deprecated "Same as [merge_set]"] val distinct : 'a list -> bool val distinct_f : 'a cmp -> 'a list -> bool val duplicates : 'a eq -> 'a list -> 'a list @@ -337,8 +327,6 @@ let filteri p = in filter_i_rec 0 -let smartfilter = filter (* Alias *) - let rec filter_with_loop filter p l = match filter, l with | [], [] -> () | b :: filter, x :: l' -> @@ -618,8 +606,6 @@ let rec fold_left_map f e = function let e'',t' = fold_left_map f e' t in e'',h' :: t' -let fold_map = fold_left_map - (* (* tail-recursive version of the above function *) let fold_left_map f e l = let g (e,b') h = @@ -634,8 +620,6 @@ let fold_left_map f e l = let fold_right_map f l e = List.fold_right (fun x (l,e) -> let (y,e) = f x e in (y::l,e)) l ([],e) -let fold_map' = fold_right_map - let on_snd f (x,y) = (x,f y) let fold_left2_map f e l l' = @@ -905,8 +889,6 @@ let rec merge_set cmp l1 l2 = match l1, l2 with then h1 :: merge_set cmp t1 l2 else h2 :: merge_set cmp l1 t2 -let merge_uniq = merge_set - let intersect cmp l1 l2 = filter (fun x -> mem_f cmp x l2) l1 @@ -1047,8 +1029,6 @@ struct end -let smartmap = Smart.map - module type MonoS = sig type elt val equal : elt list -> elt list -> bool diff --git a/clib/cList.mli b/clib/cList.mli index 39d9a5e535..8582e6cd65 100644 --- a/clib/cList.mli +++ b/clib/cList.mli @@ -91,9 +91,6 @@ sig (** [filter_with bl l] selects elements of [l] whose corresponding element in [bl] is [true]. Raise [Invalid_argument _] if sizes differ. *) - val smartfilter : ('a -> bool) -> 'a list -> 'a list - [@@ocaml.deprecated "Same as [filter]"] - val map_filter : ('a -> 'b option) -> 'a list -> 'b list (** Like [map] but keeping only non-[None] elements *) @@ -111,9 +108,6 @@ sig val map2 : ('a -> 'b -> 'c) -> 'a list -> 'b list -> 'c list (** Like OCaml [List.map2] but tail-recursive *) - val smartmap : ('a -> 'a) -> 'a list -> 'a list - [@@ocaml.deprecated "Same as [Smart.map]"] - val map_left : ('a -> 'b) -> 'a list -> 'b list (** As [map] but ensures the left-to-right order of evaluation. *) @@ -208,12 +202,6 @@ sig val fold_left4_map : ('a -> 'b -> 'c -> 'd -> 'e -> 'a * 'r) -> 'a -> 'b list -> 'c list -> 'd list -> 'e list -> 'a * 'r list (** Same with four lists, folding on the left *) - val fold_map : ('a -> 'b -> 'a * 'c) -> 'a -> 'b list -> 'a * 'c list - [@@ocaml.deprecated "Same as [fold_left_map]"] - - val fold_map' : ('b -> 'a -> 'c * 'a) -> 'b list -> 'a -> 'c list * 'a - [@@ocaml.deprecated "Same as [fold_right_map]"] - (** {6 Splitting} *) val except : 'a eq -> 'a -> 'a list -> 'a list @@ -357,9 +345,6 @@ sig val subtractq : 'a list -> 'a list -> 'a list (** [subtract] specialized to physical equality *) - val merge_uniq : 'a cmp -> 'a list -> 'a list -> 'a list - [@@ocaml.deprecated "Same as [merge_set]"] - (** {6 Uniqueness and duplication} *) val distinct : 'a list -> bool diff --git a/clib/cMap.ml b/clib/cMap.ml index 54a8b25851..040dede0a2 100644 --- a/clib/cMap.ml +++ b/clib/cMap.ml @@ -34,10 +34,6 @@ sig val bind : (key -> 'a) -> Set.t -> 'a t val fold_left : (key -> 'a -> 'b -> 'b) -> 'a t -> 'b -> 'b val fold_right : (key -> 'a -> 'b -> 'b) -> 'a t -> 'b -> 'b - val smartmap : ('a -> 'a) -> 'a t -> 'a t - [@@ocaml.deprecated "Same as [Smart.map]"] - val smartmapi : (key -> 'a -> 'a) -> 'a t -> 'a t - [@@ocaml.deprecated "Same as [Smart.mapi]"] val height : 'a t -> int module Smart : sig @@ -65,10 +61,6 @@ sig val bind : (M.t -> 'a) -> Set.Make(M).t -> 'a map val fold_left : (M.t -> 'a -> 'b -> 'b) -> 'a map -> 'b -> 'b val fold_right : (M.t -> 'a -> 'b -> 'b) -> 'a map -> 'b -> 'b - val smartmap : ('a -> 'a) -> 'a map -> 'a map - [@@ocaml.deprecated "Same as [Smart.map]"] - val smartmapi : (M.t -> 'a -> 'a) -> 'a map -> 'a map - [@@ocaml.deprecated "Same as [Smart.mapi]"] val height : 'a map -> int module Smart : sig @@ -195,9 +187,6 @@ struct end - let smartmap = Smart.map - let smartmapi = Smart.mapi - module Unsafe = struct diff --git a/clib/cMap.mli b/clib/cMap.mli index 127bf23ab6..f5496239f6 100644 --- a/clib/cMap.mli +++ b/clib/cMap.mli @@ -57,12 +57,6 @@ sig val fold_right : (key -> 'a -> 'b -> 'b) -> 'a t -> 'b -> 'b (** Folding keys in decreasing order. *) - val smartmap : ('a -> 'a) -> 'a t -> 'a t - [@@ocaml.deprecated "Same as [Smart.map]"] - - val smartmapi : (key -> 'a -> 'a) -> 'a t -> 'a t - [@@ocaml.deprecated "Same as [Smart.mapi]"] - val height : 'a t -> int (** An indication of the logarithmic size of a map *) diff --git a/clib/hMap.ml b/clib/hMap.ml index b2cf474304..33cb6d0131 100644 --- a/clib/hMap.ml +++ b/clib/hMap.ml @@ -396,9 +396,6 @@ struct end - let smartmap = Smart.map - let smartmapi = Smart.mapi - let height s = Int.Map.height s module Unsafe = diff --git a/clib/option.ml b/clib/option.ml index 7a3d5f934f..3e57fd5c85 100644 --- a/clib/option.ml +++ b/clib/option.ml @@ -131,8 +131,6 @@ let fold_right_map f x a = | Some y -> let z, a = f y a in Some z, a | _ -> None, a -let fold_map = fold_left_map - (** [cata f a x] is [a] if [x] is [None] and [f y] if [x] is [Some y]. *) let cata f a = function | Some c -> f c @@ -183,8 +181,6 @@ struct end -let smartmap = Smart.map - (** {6 Operations with Lists} *) module List = diff --git a/clib/option.mli b/clib/option.mli index 8f82bf090b..e99c8015c4 100644 --- a/clib/option.mli +++ b/clib/option.mli @@ -75,9 +75,6 @@ val iter2 : ('a -> 'b -> unit) -> 'a option -> 'b option -> unit (** [map f x] is [None] if [x] is [None] and [Some (f y)] if [x] is [Some y]. *) val map : ('a -> 'b) -> 'a option -> 'b option -val smartmap : ('a -> 'a) -> 'a option -> 'a option -[@@ocaml.deprecated "Same as [Smart.map]"] - (** [fold_left f a x] is [f a y] if [x] is [Some y], and [a] otherwise. *) val fold_left : ('b -> 'a -> 'b) -> 'b -> 'a option -> 'b @@ -95,10 +92,6 @@ val fold_left_map : ('a -> 'b -> 'a * 'c) -> 'a -> 'b option -> 'a * 'c option (** Same as [fold_left_map] on the right *) val fold_right_map : ('b -> 'a -> 'c * 'a) -> 'b option -> 'a -> 'c option * 'a -(** @deprecated Same as [fold_left_map] *) -val fold_map : ('a -> 'b -> 'a * 'c) -> 'a -> 'b option -> 'a * 'c option -[@@ocaml.deprecated "Same as [fold_left_map]"] - (** [cata f e x] is [e] if [x] is [None] and [f a] if [x] is [Some a] *) val cata : ('a -> 'b) -> 'b -> 'a option -> 'b |
