diff --git a/jscomp/others/.depend b/jscomp/others/.depend index bae070d01f..d9391b003f 100644 --- a/jscomp/others/.depend +++ b/jscomp/others/.depend @@ -25,7 +25,7 @@ bs_Queue.cmj : bs_Array.cmj bs_Queue.cmi bs_List.cmj : js_json.cmj bs_Array.cmj bs_List.cmi bs_internalBucketsType.cmj : bs_Array.cmj bs_internalSetBuckets.cmj : bs_internalBucketsType.cmj bs_Array.cmj bs.cmj -bs_internalBuckets.cmj : bs_internalBucketsType.cmj bs_Array.cmj +bs_internalBuckets.cmj : bs_internalBucketsType.cmj bs_Array.cmj bs.cmj bs_HashMap.cmj : bs_internalBucketsType.cmj bs_internalBuckets.cmj \ bs_Hash.cmj bs_Bag.cmj bs_Array.cmj bs_HashMap.cmi bs_HashSet.cmj : bs_internalSetBuckets.cmj bs_internalBucketsType.cmj \ @@ -53,9 +53,9 @@ js_global.cmj : js_cast.cmj : js_cast.cmi js_promise.cmj : bs_HashMapInt.cmj : bs_internalBucketsType.cmj bs_internalBuckets.cmj \ - bs_Array.cmj bs_HashMapInt.cmi + bs_Array.cmj bs.cmj bs_HashMapInt.cmi bs_HashMapString.cmj : bs_internalBucketsType.cmj bs_internalBuckets.cmj \ - bs_Array.cmj bs_HashMapString.cmi + bs_Array.cmj bs.cmj bs_HashMapString.cmi node_process.cmi : js_dict.cmi js_re.cmi : js_null_undefined.cmi : diff --git a/jscomp/others/bs_HashMap.ml b/jscomp/others/bs_HashMap.ml index 1f56770f9b..55b58d78df 100644 --- a/jscomp/others/bs_HashMap.ml +++ b/jscomp/others/bs_HashMap.ml @@ -222,8 +222,8 @@ let create dict initialize_size = let clear h = clear0 (B.data h) let reset h = reset0 (B.data h) let length h = length0 (B.data h) -let iter f h = iter0 f (B.data h) -let fold f h init = fold0 f (B.data h) init +let iter h f = iter0 (B.data h) f +let fold h init f = fold0 (B.data h) init f let logStats h = logStats0 (B.data h) let add (type a) (type b ) (type id) (h : (a,b,id) t) (key:a) (info:b) = @@ -261,5 +261,5 @@ let mem (type a) (type b) (type id) (h : (a,b,id) t) (key : a) = let module M = (val dict) in mem0 ~hash:M.hash ~eq:M.eq data key -let filterMapInplace f h = - filterMapInplace0 f (B.data h) +let filterMapInplace h f = + filterMapInplace0 (B.data h) f diff --git a/jscomp/others/bs_HashMap.mli b/jscomp/others/bs_HashMap.mli index 1b6e45fe8e..490c65fc85 100644 --- a/jscomp/others/bs_HashMap.mli +++ b/jscomp/others/bs_HashMap.mli @@ -127,8 +127,8 @@ val replace: This is functionally equivalent to {!Hashtbl.remove}[ tbl x] followed by {!Hashtbl.add}[ tbl x y]. *) -val iter0 : ('a -> 'b -> unit [@bs]) -> ('a, 'b, 'id) t0 -> unit -val iter : ('a -> 'b -> unit [@bs]) -> ('a, 'b, 'id) t -> unit +val iter0 : ('a, 'b, 'id) t0 -> ('a -> 'b -> unit [@bs]) -> unit +val iter : ('a, 'b, 'id) t -> ('a -> 'b -> unit [@bs]) -> unit (** [Hashtbl.iter f tbl] applies [f] to all bindings in table [tbl]. [f] receives the key as first argument, and the associated value as second argument. Each binding is presented exactly once to [f]. @@ -144,8 +144,8 @@ val iter : ('a -> 'b -> unit [@bs]) -> ('a, 'b, 'id) t -> unit of OCaml. For randomized hash tables, the order of enumeration is entirely random. *) -val fold0 : ('a -> 'b -> 'c -> 'c [@bs]) -> ('a, 'b, 'id) t0 -> 'c -> 'c -val fold : ('a -> 'b -> 'c -> 'c [@bs]) -> ('a, 'b, 'id) t -> 'c -> 'c +val fold0 : ('a, 'b, 'id) t0 -> 'c -> ('a -> 'b -> 'c -> 'c [@bs]) -> 'c +val fold : ('a, 'b, 'id) t -> 'c -> ('a -> 'b -> 'c -> 'c [@bs]) -> 'c (** [Hashtbl.fold f tbl init] computes [(f kN dN ... (f k1 d1 init)...)], where [k1 ... kN] are the keys of all bindings in [tbl], @@ -163,8 +163,8 @@ val fold : ('a -> 'b -> 'c -> 'c [@bs]) -> ('a, 'b, 'id) t -> 'c -> 'c of OCaml. For randomized hash tables, the order of enumeration is entirely random. *) -val filterMapInplace0 : ('a -> 'b -> 'b option [@bs]) -> ('a, 'b, 'id) t0 -> unit -val filterMapInplace : ('a -> 'b -> 'b option [@bs]) -> ('a, 'b, 'id) t -> unit +val filterMapInplace0 : ('a, 'b, 'id) t0 -> ('a -> 'b -> 'b option [@bs]) -> unit +val filterMapInplace : ('a, 'b, 'id) t -> ('a -> 'b -> 'b option [@bs]) -> unit val length0 : ('a, 'b, 'id) t0 -> int val length : ('a, 'b, 'id) t -> int @@ -196,36 +196,7 @@ val logStats : _ t -> unit buckets by size. @since 4.00.0 *) -(** {6 Functorial interface} *) -(** The functorial interface allows the use of specific comparison - and hash functions, either for performance/security concerns, - or because keys are not hashable/comparable with the polymorphic builtins. - - For instance, one might want to specialize a table for integer keys: - {[ - module IntHash = - struct - type t = int - let equal i j = i=j - let hash i = i land max_int - end - - module IntHashtbl = Hashtbl.Make(IntHash) - - let h = IntHashtbl.create 17 in - IntHashtbl.add h 12 "hello";; - ]} - - This creates a new module [IntHashtbl], with a new type ['a - IntHashtbl.t] of tables from [int] to ['a]. In this example, [h] - contains [string] values so its type is [string IntHashtbl.t]. - - Note that the new type ['a IntHashtbl.t] is not compatible with - the type [('a,'b) Hashtbl.t] of the generic interface. For - example, [Hashtbl.length h] would not type-check, you must use - [IntHashtbl.length]. -*) diff --git a/jscomp/others/bs_HashMapInt.ml b/jscomp/others/bs_HashMapInt.ml index 8a7ac368ac..8755f8f251 100644 --- a/jscomp/others/bs_HashMapInt.ml +++ b/jscomp/others/bs_HashMapInt.ml @@ -203,4 +203,21 @@ let iter = N.iter0 let fold = N.fold0 let logStats = N.logStats0 let filterMapInplace = N.filterMapInplace0 - +let toArray = N.toArray0 + +let ofArray arr = + let len = Bs.Array.length arr in + let v = create len in + for i = 0 to len - 1 do + let k,value = (Bs.Array.unsafe_get arr i) in + add v k value + done ; + v + +(* TOOD: optimize heuristics for resizing *) +let addArray h arr = + let len = Bs.Array.length arr in + for i = 0 to len - 1 do + let k,v = (Bs_Array.unsafe_get arr i) in + add h k v +done diff --git a/jscomp/others/bs_HashMapInt.mli b/jscomp/others/bs_HashMapInt.mli index 75d6e13d37..b6209cc7d4 100644 --- a/jscomp/others/bs_HashMapInt.mli +++ b/jscomp/others/bs_HashMapInt.mli @@ -7,44 +7,6 @@ type 'b t val create : int -> 'b t -(** [Hashtbl.create n] creates a new, empty hash table, with - initial size [n]. For best results, [n] should be on the - order of the expected number of elements that will be in - the table. The table grows as needed, so [n] is just an - initial guess. - - The optional [random] parameter (a boolean) controls whether - the internal organization of the hash table is randomized at each - execution of [Hashtbl.create] or deterministic over all executions. - - A hash table that is created with [~random:false] uses a - fixed hash function ({!Hashtbl.hash}) to distribute keys among - buckets. As a consequence, collisions between keys happen - deterministically. In Web-facing applications or other - security-sensitive applications, the deterministic collision - patterns can be exploited by a malicious user to create a - denial-of-service attack: the attacker sends input crafted to - create many collisions in the table, slowing the application down. - - A hash table that is created with [~random:true] uses the seeded - hash function {!Hashtbl.seeded_hash} with a seed that is randomly - chosen at hash table creation time. In effect, the hash function - used is randomly selected among [2^{30}] different hash functions. - All these hash functions have different collision patterns, - rendering ineffective the denial-of-service attack described above. - However, because of randomization, enumerating all elements of the - hash table using {!Hashtbl.fold} or {!Hashtbl.iter} is no longer - deterministic: elements are enumerated in different orders at - different runs of the program. - - If no [~random] parameter is given, hash tables are created - in non-random mode by default. This default can be changed - either programmatically by calling {!Hashtbl.randomize} or by - setting the [R] flag in the [OCAMLRUNPARAM] environment variable. - - @before 4.00.0 the [random] parameter was not present and all - hash tables were created in non-randomized mode. *) - val clear : 'b t -> unit (** Empty a hash table. Use [reset] instead of [clear] to shrink the @@ -56,146 +18,38 @@ val reset : 'b t -> unit to its initial size. @since 4.00.0 *) +val add : 'a t -> key -> 'a -> unit +val findOpt: 'a t -> key -> 'a option - -val add : 'b t -> key -> 'b -> unit -(** [Hashtbl.add tbl x y] adds a binding of [x] to [y] in table [tbl]. - Previous bindings for [x] are not removed, but simply - hidden. That is, after performing {!Hashtbl.remove}[ tbl x], - the previous binding for [x], if any, is restored. - (Same behavior as with association lists.) *) - -val findOpt: - 'b t -> key -> 'b option -(** [findOpt tbl x] returns the current binding of [x] in [tbl], - *) - -val findAll: 'b t -> key -> 'b list +val findAll: 'a t -> key -> 'a list (** [Hashtbl.find_all tbl x] returns the list of all data associated with [x] in [tbl]. The current binding is returned first, then the previous bindings, in reverse order of introduction in the table. *) -val mem: - 'b t -> key -> bool -(** [Hashtbl.mem tbl x] checks if [x] is bound in [tbl]. *) - -val remove: - 'b t -> key -> unit -(** [Hashtbl.remove tbl x] removes the current binding of [x] in [tbl], - restoring the previous binding if it exists. - It does nothing if [x] is not bound in [tbl]. *) - -val removeAll: - 'b t -> key -> unit - - -val replace: - 'b t -> key -> 'b -> unit -(** [Hashtbl.replace tbl x y] replaces the current binding of [x] - in [tbl] by a binding of [x] to [y]. If [x] is unbound in [tbl], - a binding of [x] to [y] is added to [tbl]. - This is functionally equivalent to {!Hashtbl.remove}[ tbl x] - followed by {!Hashtbl.add}[ tbl x y]. *) - - -val iter : (key -> 'b -> unit [@bs]) -> 'b t -> unit -(** [Hashtbl.iter f tbl] applies [f] to all bindings in table [tbl]. - [f] receives the key as first argument, and the associated value - as second argument. Each binding is presented exactly once to [f]. - - The order in which the bindings are passed to [f] is unspecified. - However, if the table contains several bindings for the same key, - they are passed to [f] in reverse order of introduction, that is, - the most recent binding is passed first. - - If the hash table was created in non-randomized mode, the order - in which the bindings are enumerated is reproducible between - successive runs of the program, and even between minor versions - of OCaml. For randomized hash tables, the order of enumeration - is entirely random. *) - - -val fold : (key -> 'b -> 'c -> 'c [@bs]) -> 'b t -> 'c -> 'c -(** [Hashtbl.fold f tbl init] computes - [(f kN dN ... (f k1 d1 init)...)], - where [k1 ... kN] are the keys of all bindings in [tbl], - and [d1 ... dN] are the associated values. - Each binding is presented exactly once to [f]. - - The order in which the bindings are passed to [f] is unspecified. - However, if the table contains several bindings for the same key, - they are passed to [f] in reverse order of introduction, that is, - the most recent binding is passed first. - - If the hash table was created in non-randomized mode, the order - in which the bindings are enumerated is reproducible between - successive runs of the program, and even between minor versions - of OCaml. For randomized hash tables, the order of enumeration - is entirely random. *) - - -val filterMapInplace : (key -> 'b -> 'b option [@bs]) -> 'b t -> unit - -val length : 'b t -> int -(** [Hashtbl.length tbl] returns the number of bindings in [tbl]. - It takes constant time. Multiple bindings are counted once each, so - [Hashtbl.length] gives the number of times [Hashtbl.iter] calls its - first argument. *) - - -(* -type statistics = { - num_bindings: int; - (** Number of bindings present in the table. - Same value as returned by {!Hashtbl.length}. *) - num_buckets: int; - (** Number of buckets in the table. *) - max_bucket_length: int; - (** Maximal number of bindings per bucket. *) - bucket_histogram: int array - (** Histogram of bucket sizes. This array [histo] has - length [max_bucket_length + 1]. The value of - [histo.(i)] is the number of buckets whose size is [i]. *) -} *) +val mem: 'b t -> key -> bool -val logStats : _ t -> unit -(** [Hashtbl.stats tbl] returns statistics about the table [tbl]: - number of buckets, size of the biggest bucket, distribution of - buckets by size. - @since 4.00.0 *) +val remove: 'a t -> key -> unit + +val removeAll: 'b t -> key -> unit -(** {6 Functorial interface} *) +val replace: 'b t -> key -> 'b -> unit -(** The functorial interface allows the use of specific comparison - and hash functions, either for performance/security concerns, - or because keys are not hashable/comparable with the polymorphic builtins. - For instance, one might want to specialize a table for integer keys: - {[ - module IntHash = - struct - type t = int - let equal i j = i=j - let hash i = i land max_int - end +val iter : 'b t -> (key -> 'b -> unit [@bs]) -> unit - module IntHashtbl = Hashtbl.Make(IntHash) +val fold : 'b t -> 'c -> (key -> 'b -> 'c -> 'c [@bs]) -> 'c - let h = IntHashtbl.create 17 in - IntHashtbl.add h 12 "hello";; - ]} - This creates a new module [IntHashtbl], with a new type ['a - IntHashtbl.t] of tables from [int] to ['a]. In this example, [h] - contains [string] values so its type is [string IntHashtbl.t]. +val filterMapInplace : 'a t -> (key -> 'a -> 'a option [@bs]) -> unit + +val length : _ t -> int +val logStats : _ t -> unit - Note that the new type ['a IntHashtbl.t] is not compatible with - the type [('a,'b) Hashtbl.t] of the generic interface. For - example, [Hashtbl.length h] would not type-check, you must use - [IntHashtbl.length]. -*) +val toArray : 'a t -> (key * 'a) array +val ofArray : (key * 'a) array -> 'a t +val addArray : 'a t -> (key * 'a) array -> unit diff --git a/jscomp/others/bs_HashMapString.ml b/jscomp/others/bs_HashMapString.ml index e4f4f30c67..bcc229ec70 100644 --- a/jscomp/others/bs_HashMapString.ml +++ b/jscomp/others/bs_HashMapString.ml @@ -203,4 +203,21 @@ let iter = N.iter0 let fold = N.fold0 let logStats = N.logStats0 let filterMapInplace = N.filterMapInplace0 - +let toArray = N.toArray0 + +let ofArray arr = + let len = Bs.Array.length arr in + let v = create len in + for i = 0 to len - 1 do + let k,value = (Bs.Array.unsafe_get arr i) in + add v k value + done ; + v + +(* TOOD: optimize heuristics for resizing *) +let addArray h arr = + let len = Bs.Array.length arr in + for i = 0 to len - 1 do + let k,v = (Bs_Array.unsafe_get arr i) in + add h k v +done diff --git a/jscomp/others/bs_HashMapString.mli b/jscomp/others/bs_HashMapString.mli index 7443a890f7..d38c6d1159 100644 --- a/jscomp/others/bs_HashMapString.mli +++ b/jscomp/others/bs_HashMapString.mli @@ -7,44 +7,6 @@ type 'b t val create : int -> 'b t -(** [Hashtbl.create n] creates a new, empty hash table, with - initial size [n]. For best results, [n] should be on the - order of the expected number of elements that will be in - the table. The table grows as needed, so [n] is just an - initial guess. - - The optional [random] parameter (a boolean) controls whether - the internal organization of the hash table is randomized at each - execution of [Hashtbl.create] or deterministic over all executions. - - A hash table that is created with [~random:false] uses a - fixed hash function ({!Hashtbl.hash}) to distribute keys among - buckets. As a consequence, collisions between keys happen - deterministically. In Web-facing applications or other - security-sensitive applications, the deterministic collision - patterns can be exploited by a malicious user to create a - denial-of-service attack: the attacker sends input crafted to - create many collisions in the table, slowing the application down. - - A hash table that is created with [~random:true] uses the seeded - hash function {!Hashtbl.seeded_hash} with a seed that is randomly - chosen at hash table creation time. In effect, the hash function - used is randomly selected among [2^{30}] different hash functions. - All these hash functions have different collision patterns, - rendering ineffective the denial-of-service attack described above. - However, because of randomization, enumerating all elements of the - hash table using {!Hashtbl.fold} or {!Hashtbl.iter} is no longer - deterministic: elements are enumerated in different orders at - different runs of the program. - - If no [~random] parameter is given, hash tables are created - in non-random mode by default. This default can be changed - either programmatically by calling {!Hashtbl.randomize} or by - setting the [R] flag in the [OCAMLRUNPARAM] environment variable. - - @before 4.00.0 the [random] parameter was not present and all - hash tables were created in non-randomized mode. *) - val clear : 'b t -> unit (** Empty a hash table. Use [reset] instead of [clear] to shrink the @@ -56,146 +18,38 @@ val reset : 'b t -> unit to its initial size. @since 4.00.0 *) +val add : 'a t -> key -> 'a -> unit +val findOpt: 'a t -> key -> 'a option - -val add : 'b t -> key -> 'b -> unit -(** [Hashtbl.add tbl x y] adds a binding of [x] to [y] in table [tbl]. - Previous bindings for [x] are not removed, but simply - hidden. That is, after performing {!Hashtbl.remove}[ tbl x], - the previous binding for [x], if any, is restored. - (Same behavior as with association lists.) *) - -val findOpt: - 'b t -> key -> 'b option -(** [findOpt tbl x] returns the current binding of [x] in [tbl], - *) - -val findAll: 'b t -> key -> 'b list +val findAll: 'a t -> key -> 'a list (** [Hashtbl.find_all tbl x] returns the list of all data associated with [x] in [tbl]. The current binding is returned first, then the previous bindings, in reverse order of introduction in the table. *) -val mem: - 'b t -> key -> bool -(** [Hashtbl.mem tbl x] checks if [x] is bound in [tbl]. *) - -val remove: - 'b t -> key -> unit -(** [Hashtbl.remove tbl x] removes the current binding of [x] in [tbl], - restoring the previous binding if it exists. - It does nothing if [x] is not bound in [tbl]. *) - -val removeAll: - 'b t -> key -> unit - - -val replace: - 'b t -> key -> 'b -> unit -(** [Hashtbl.replace tbl x y] replaces the current binding of [x] - in [tbl] by a binding of [x] to [y]. If [x] is unbound in [tbl], - a binding of [x] to [y] is added to [tbl]. - This is functionally equivalent to {!Hashtbl.remove}[ tbl x] - followed by {!Hashtbl.add}[ tbl x y]. *) - - -val iter : (key -> 'b -> unit [@bs]) -> 'b t -> unit -(** [Hashtbl.iter f tbl] applies [f] to all bindings in table [tbl]. - [f] receives the key as first argument, and the associated value - as second argument. Each binding is presented exactly once to [f]. - - The order in which the bindings are passed to [f] is unspecified. - However, if the table contains several bindings for the same key, - they are passed to [f] in reverse order of introduction, that is, - the most recent binding is passed first. - - If the hash table was created in non-randomized mode, the order - in which the bindings are enumerated is reproducible between - successive runs of the program, and even between minor versions - of OCaml. For randomized hash tables, the order of enumeration - is entirely random. *) - - -val fold : (key -> 'b -> 'c -> 'c [@bs]) -> 'b t -> 'c -> 'c -(** [Hashtbl.fold f tbl init] computes - [(f kN dN ... (f k1 d1 init)...)], - where [k1 ... kN] are the keys of all bindings in [tbl], - and [d1 ... dN] are the associated values. - Each binding is presented exactly once to [f]. - - The order in which the bindings are passed to [f] is unspecified. - However, if the table contains several bindings for the same key, - they are passed to [f] in reverse order of introduction, that is, - the most recent binding is passed first. - - If the hash table was created in non-randomized mode, the order - in which the bindings are enumerated is reproducible between - successive runs of the program, and even between minor versions - of OCaml. For randomized hash tables, the order of enumeration - is entirely random. *) - - -val filterMapInplace : (key -> 'b -> 'b option [@bs]) -> 'b t -> unit - -val length : 'b t -> int -(** [Hashtbl.length tbl] returns the number of bindings in [tbl]. - It takes constant time. Multiple bindings are counted once each, so - [Hashtbl.length] gives the number of times [Hashtbl.iter] calls its - first argument. *) - - -(* -type statistics = { - num_bindings: int; - (** Number of bindings present in the table. - Same value as returned by {!Hashtbl.length}. *) - num_buckets: int; - (** Number of buckets in the table. *) - max_bucket_length: int; - (** Maximal number of bindings per bucket. *) - bucket_histogram: int array - (** Histogram of bucket sizes. This array [histo] has - length [max_bucket_length + 1]. The value of - [histo.(i)] is the number of buckets whose size is [i]. *) -} *) +val mem: 'b t -> key -> bool -val logStats : _ t -> unit -(** [Hashtbl.stats tbl] returns statistics about the table [tbl]: - number of buckets, size of the biggest bucket, distribution of - buckets by size. - @since 4.00.0 *) +val remove: 'a t -> key -> unit + +val removeAll: 'b t -> key -> unit -(** {6 Functorial interface} *) +val replace: 'b t -> key -> 'b -> unit -(** The functorial interface allows the use of specific comparison - and hash functions, either for performance/security concerns, - or because keys are not hashable/comparable with the polymorphic builtins. - For instance, one might want to specialize a table for integer keys: - {[ - module IntHash = - struct - type t = int - let equal i j = i=j - let hash i = i land max_int - end +val iter : 'b t -> (key -> 'b -> unit [@bs]) -> unit - module IntHashtbl = Hashtbl.Make(IntHash) +val fold : 'b t -> 'c -> (key -> 'b -> 'c -> 'c [@bs]) -> 'c - let h = IntHashtbl.create 17 in - IntHashtbl.add h 12 "hello";; - ]} - This creates a new module [IntHashtbl], with a new type ['a - IntHashtbl.t] of tables from [int] to ['a]. In this example, [h] - contains [string] values so its type is [string IntHashtbl.t]. +val filterMapInplace : 'a t -> (key -> 'a -> 'a option [@bs]) -> unit + +val length : _ t -> int +val logStats : _ t -> unit - Note that the new type ['a IntHashtbl.t] is not compatible with - the type [('a,'b) Hashtbl.t] of the generic interface. For - example, [Hashtbl.length h] would not type-check, you must use - [IntHashtbl.length]. -*) +val toArray : 'a t -> (key * 'a) array +val ofArray : (key * 'a) array -> 'a t +val addArray : 'a t -> (key * 'a) array -> unit diff --git a/jscomp/others/bs_HashSet.ml b/jscomp/others/bs_HashSet.ml index 13036d71a3..cd97af9343 100644 --- a/jscomp/others/bs_HashSet.ml +++ b/jscomp/others/bs_HashSet.ml @@ -172,8 +172,8 @@ let create dict initialize_size = let clear h = clear0 (B.data h) let reset h = reset0 (B.data h) let length h = length0 (B.data h) -let iter f h = iter0 f (B.data h) -let fold f h init = fold0 f (B.data h) init +let iter h f = iter0 (B.data h) f +let fold h init f = fold0 (B.data h) init f let logStats h = logStats0 (B.data h) let add (type a) (type id) (h : (a,id) t) (key:a) = diff --git a/jscomp/others/bs_HashSet.mli b/jscomp/others/bs_HashSet.mli index b8d3906db9..9bdfdd90bc 100644 --- a/jscomp/others/bs_HashSet.mli +++ b/jscomp/others/bs_HashSet.mli @@ -8,43 +8,7 @@ type ('a, 'id) t = val create0 : int -> ('a, 'id) t0 val create : ('a,'id) Bs_Hash.t -> int -> ('a, 'id) t -(** [Hashtbl.create n] creates a new, empty hash table, with - initial size [n]. For best results, [n] should be on the - order of the expected number of elements that will be in - the table. The table grows as needed, so [n] is just an - initial guess. - - The optional [random] parameter (a boolean) controls whether - the internal organization of the hash table is randomized at each - execution of [Hashtbl.create] or deterministic over all executions. - - A hash table that is created with [~random:false] uses a - fixed hash function ({!Hashtbl.hash}) to distribute keys among - buckets. As a consequence, collisions between keys happen - deterministically. In Web-facing applications or other - security-sensitive applications, the deterministic collision - patterns can be exploited by a malicious user to create a - denial-of-service attack: the attacker sends input crafted to - create many collisions in the table, slowing the application down. - - A hash table that is created with [~random:true] uses the seeded - hash function {!Hashtbl.seeded_hash} with a seed that is randomly - chosen at hash table creation time. In effect, the hash function - used is randomly selected among [2^{30}] different hash functions. - All these hash functions have different collision patterns, - rendering ineffective the denial-of-service attack described above. - However, because of randomization, enumerating all elements of the - hash table using {!Hashtbl.fold} or {!Hashtbl.iter} is no longer - deterministic: elements are enumerated in different orders at - different runs of the program. - - If no [~random] parameter is given, hash tables are created - in non-random mode by default. This default can be changed - either programmatically by calling {!Hashtbl.randomize} or by - setting the [R] flag in the [OCAMLRUNPARAM] environment variable. - - @before 4.00.0 the [random] parameter was not present and all - hash tables were created in non-randomized mode. *) + val clear0 : ('a, 'id) t0 -> unit val clear : ('a, 'id) t -> unit @@ -64,11 +28,6 @@ val add0 : eq:('a,'id) Bs_Hash.eq -> ('a,'id) t0 -> 'a -> unit val add : ('a, 'id) t -> 'a -> unit -(** [Hashtbl.add tbl x y] adds a binding of [x] to [y] in table [tbl]. - Previous bindings for [x] are not removed, but simply - hidden. That is, after performing {!Hashtbl.remove}[ tbl x], - the previous binding for [x], if any, is restored. - (Same behavior as with association lists.) *) val mem0: hash:('a,'id) Bs_Hash.hash -> @@ -76,7 +35,7 @@ val mem0: ('a, 'id) t0 -> 'a -> bool val mem: ('a, 'id) t -> 'a -> bool -(** [Hashtbl.mem tbl x] checks if [x] is bound in [tbl]. *) + val remove0: hash:('a,'id) Bs_Hash.hash -> @@ -84,43 +43,21 @@ val remove0: ('a, 'id) t0 -> 'a -> unit val remove: ('a, 'id) t -> 'a -> unit -(** [Hashtbl.remove tbl x] removes the current binding of [x] in [tbl], - restoring the previous binding if it exists. - It does nothing if [x] is not bound in [tbl]. *) - - - -val iter0 : ('a -> unit [@bs]) -> ('a, 'id) t0 -> unit -val iter : ('a -> unit [@bs]) -> ('a, 'id) t -> unit -(** [Hashtbl.iter f tbl] applies [f] to all bindings in table [tbl]. - [f] receives the key as first argument, and the associated value - as second argument. Each binding is presented exactly once to [f]. - The order in which the bindings are passed to [f] is unspecified. - However, if the table contains several bindings for the same key, - they are passed to [f] in reverse order of introduction, that is, - the most recent binding is passed first. +val iter0 : ('a, 'id) t0 -> ('a -> unit [@bs]) -> unit +val iter : ('a, 'id) t -> ('a -> unit [@bs]) -> unit +(** If the hash table was created in non-randomized mode, the order in which the bindings are enumerated is reproducible between successive runs of the program, and even between minor versions of OCaml. For randomized hash tables, the order of enumeration is entirely random. *) -val fold0 : ('a -> 'c -> 'c [@bs]) -> ('a, 'id) t0 -> 'c -> 'c -val fold : ('a -> 'c -> 'c [@bs]) -> ('a, 'id) t -> 'c -> 'c -(** [Hashtbl.fold f tbl init] computes - [(f kN dN ... (f k1 d1 init)...)], - where [k1 ... kN] are the keys of all bindings in [tbl], - and [d1 ... dN] are the associated values. - Each binding is presented exactly once to [f]. - - The order in which the bindings are passed to [f] is unspecified. - However, if the table contains several bindings for the same key, - they are passed to [f] in reverse order of introduction, that is, - the most recent binding is passed first. - +val fold0 : ('a, 'id) t0 -> 'c -> ('a -> 'c -> 'c [@bs]) -> 'c +val fold : ('a, 'id) t -> 'c -> ('a -> 'c -> 'c [@bs]) -> 'c +(** If the hash table was created in non-randomized mode, the order in which the bindings are enumerated is reproducible between successive runs of the program, and even between minor versions @@ -130,13 +67,6 @@ val fold : ('a -> 'c -> 'c [@bs]) -> ('a, 'id) t -> 'c -> 'c val length0 : ('a, 'id) t0 -> int val length : ('a, 'id) t -> int -(** [Hashtbl.length tbl] returns the number of bindings in [tbl]. - It takes constant time. Multiple bindings are counted once each, so - [Hashtbl.length] gives the number of times [Hashtbl.iter] calls its - first argument. *) - - - val logStats0 : ('a, 'id) t0 -> unit val logStats : _ t -> unit @@ -145,37 +75,6 @@ val logStats : _ t -> unit buckets by size. @since 4.00.0 *) -(** {6 Functorial interface} *) - -(** The functorial interface allows the use of specific comparison - and hash functions, either for performance/security concerns, - or because keys are not hashable/comparable with the polymorphic builtins. - - For instance, one might want to specialize a table for integer keys: - {[ - module IntHash = - struct - type t = int - let equal i j = i=j - let hash i = i land max_int - end - - module IntHashtbl = Hashtbl.Make(IntHash) - - let h = IntHashtbl.create 17 in - IntHashtbl.add h 12 "hello";; - ]} - - This creates a new module [IntHashtbl], with a new type ['a - IntHashtbl.t] of tables from [int] to ['a]. In this example, [h] - contains [string] values so its type is [string IntHashtbl.t]. - - Note that the new type ['a IntHashtbl.t] is not compatible with - the type [('a,'b) Hashtbl.t] of the generic interface. For - example, [Hashtbl.length h] would not type-check, you must use - [IntHashtbl.length]. -*) - val toArray0 : ('a,'id) t0 -> 'a array val toArray : ('a,'id) t -> 'a array diff --git a/jscomp/others/bs_HashSetInt.mli b/jscomp/others/bs_HashSetInt.mli index 979837d100..7d007944a8 100644 --- a/jscomp/others/bs_HashSetInt.mli +++ b/jscomp/others/bs_HashSetInt.mli @@ -4,172 +4,18 @@ type key = int # 10 type t - - - - val create : int -> t - -(** [Hashtbl.create n] creates a new, empty hash table, with - initial size [n]. For best results, [n] should be on the - order of the expected number of elements that will be in - the table. The table grows as needed, so [n] is just an - initial guess. - - The optional [random] parameter (a boolean) controls whether - the internal organization of the hash table is randomized at each - execution of [Hashtbl.create] or deterministic over all executions. - - A hash table that is created with [~random:false] uses a - fixed hash function ({!Hashtbl.hash}) to distribute keys among - buckets. As a consequence, collisions between keys happen - deterministically. In Web-facing applications or other - security-sensitive applications, the deterministic collision - patterns can be exploited by a malicious user to create a - denial-of-service attack: the attacker sends input crafted to - create many collisions in the table, slowing the application down. - - A hash table that is created with [~random:true] uses the seeded - hash function {!Hashtbl.seeded_hash} with a seed that is randomly - chosen at hash table creation time. In effect, the hash function - used is randomly selected among [2^{30}] different hash functions. - All these hash functions have different collision patterns, - rendering ineffective the denial-of-service attack described above. - However, because of randomization, enumerating all elements of the - hash table using {!Hashtbl.fold} or {!Hashtbl.iter} is no longer - deterministic: elements are enumerated in different orders at - different runs of the program. - - If no [~random] parameter is given, hash tables are created - in non-random mode by default. This default can be changed - either programmatically by calling {!Hashtbl.randomize} or by - setting the [R] flag in the [OCAMLRUNPARAM] environment variable. - - @before 4.00.0 the [random] parameter was not present and all - hash tables were created in non-randomized mode. *) - - val clear : t -> unit -(** Empty a hash table. Use [reset] instead of [clear] to shrink the - size of the bucket table to its initial size. *) - - val reset : t -> unit -(** Empty a hash table and shrink the size of the bucket table - to its initial size. - @since 4.00.0 *) - - - val add : t -> key -> unit -(** [Hashtbl.add tbl x y] adds a binding of [x] to [y] in table [tbl]. - Previous bindings for [x] are not removed, but simply - hidden. That is, after performing {!Hashtbl.remove}[ tbl x], - the previous binding for [x], if any, is restored. - (Same behavior as with association lists.) *) - - val mem: t -> key -> bool -(** [Hashtbl.mem tbl x] checks if [x] is bound in [tbl]. *) - val remove: t -> key -> unit -(** [Hashtbl.remove tbl x] removes the current binding of [x] in [tbl], - restoring the previous binding if it exists. - It does nothing if [x] is not bound in [tbl]. *) - - - - - -val iter : (key -> unit [@bs]) -> t -> unit -(** [Hashtbl.iter f tbl] applies [f] to all bindings in table [tbl]. - [f] receives the key as first argument, and the associated value - as second argument. Each binding is presented exactly once to [f]. - - The order in which the bindings are passed to [f] is unspecified. - However, if the table contains several bindings for the same key, - they are passed to [f] in reverse order of introduction, that is, - the most recent binding is passed first. - - If the hash table was created in non-randomized mode, the order - in which the bindings are enumerated is reproducible between - successive runs of the program, and even between minor versions - of OCaml. For randomized hash tables, the order of enumeration - is entirely random. *) - - -val fold : (key -> 'c -> 'c [@bs]) -> t -> 'c -> 'c -(** [Hashtbl.fold f tbl init] computes - [(f kN dN ... (f k1 d1 init)...)], - where [k1 ... kN] are the keys of all bindings in [tbl], - and [d1 ... dN] are the associated values. - Each binding is presented exactly once to [f]. - - The order in which the bindings are passed to [f] is unspecified. - However, if the table contains several bindings for the same key, - they are passed to [f] in reverse order of introduction, that is, - the most recent binding is passed first. - - If the hash table was created in non-randomized mode, the order - in which the bindings are enumerated is reproducible between - successive runs of the program, and even between minor versions - of OCaml. For randomized hash tables, the order of enumeration - is entirely random. *) - - +val iter : t -> (key -> unit [@bs]) -> unit +val fold : t -> 'c -> (key -> 'c -> 'c [@bs]) -> 'c val length : t -> int -(** [Hashtbl.length tbl] returns the number of bindings in [tbl]. - It takes constant time. Multiple bindings are counted once each, so - [Hashtbl.length] gives the number of times [Hashtbl.iter] calls its - first argument. *) - - - - - val logStats : t -> unit -(** [Hashtbl.stats tbl] returns statistics about the table [tbl]: - number of buckets, size of the biggest bucket, distribution of - buckets by size. - @since 4.00.0 *) - -(** {6 Functorial interface} *) - -(** The functorial interface allows the use of specific comparison - and hash functions, either for performance/security concerns, - or because keys are not hashable/comparable with the polymorphic builtins. - - For instance, one might want to specialize a table for integer keys: - {[ - module IntHash = - struct - type t = int - let equal i j = i=j - let hash i = i land max_int - end - - module IntHashtbl = Hashtbl.Make(IntHash) - - let h = IntHashtbl.create 17 in - IntHashtbl.add h 12 "hello";; - ]} - - This creates a new module [IntHashtbl], with a new type ['a - IntHashtbl.t] of tables from [int] to ['a]. In this example, [h] - contains [string] values so its type is [string IntHashtbl.t]. - - Note that the new type ['a IntHashtbl.t] is not compatible with - the type [('a,'b) Hashtbl.t] of the generic interface. For - example, [Hashtbl.length h] would not type-check, you must use - [IntHashtbl.length]. -*) - - - val toArray : t -> key array - val ofArray : key array -> t - val addArray : t -> key array -> unit \ No newline at end of file diff --git a/jscomp/others/bs_HashSetString.mli b/jscomp/others/bs_HashSetString.mli index 5e5b82d8a6..29feff2aed 100644 --- a/jscomp/others/bs_HashSetString.mli +++ b/jscomp/others/bs_HashSetString.mli @@ -4,172 +4,18 @@ type key = string # 10 type t - - - - val create : int -> t - -(** [Hashtbl.create n] creates a new, empty hash table, with - initial size [n]. For best results, [n] should be on the - order of the expected number of elements that will be in - the table. The table grows as needed, so [n] is just an - initial guess. - - The optional [random] parameter (a boolean) controls whether - the internal organization of the hash table is randomized at each - execution of [Hashtbl.create] or deterministic over all executions. - - A hash table that is created with [~random:false] uses a - fixed hash function ({!Hashtbl.hash}) to distribute keys among - buckets. As a consequence, collisions between keys happen - deterministically. In Web-facing applications or other - security-sensitive applications, the deterministic collision - patterns can be exploited by a malicious user to create a - denial-of-service attack: the attacker sends input crafted to - create many collisions in the table, slowing the application down. - - A hash table that is created with [~random:true] uses the seeded - hash function {!Hashtbl.seeded_hash} with a seed that is randomly - chosen at hash table creation time. In effect, the hash function - used is randomly selected among [2^{30}] different hash functions. - All these hash functions have different collision patterns, - rendering ineffective the denial-of-service attack described above. - However, because of randomization, enumerating all elements of the - hash table using {!Hashtbl.fold} or {!Hashtbl.iter} is no longer - deterministic: elements are enumerated in different orders at - different runs of the program. - - If no [~random] parameter is given, hash tables are created - in non-random mode by default. This default can be changed - either programmatically by calling {!Hashtbl.randomize} or by - setting the [R] flag in the [OCAMLRUNPARAM] environment variable. - - @before 4.00.0 the [random] parameter was not present and all - hash tables were created in non-randomized mode. *) - - val clear : t -> unit -(** Empty a hash table. Use [reset] instead of [clear] to shrink the - size of the bucket table to its initial size. *) - - val reset : t -> unit -(** Empty a hash table and shrink the size of the bucket table - to its initial size. - @since 4.00.0 *) - - - val add : t -> key -> unit -(** [Hashtbl.add tbl x y] adds a binding of [x] to [y] in table [tbl]. - Previous bindings for [x] are not removed, but simply - hidden. That is, after performing {!Hashtbl.remove}[ tbl x], - the previous binding for [x], if any, is restored. - (Same behavior as with association lists.) *) - - val mem: t -> key -> bool -(** [Hashtbl.mem tbl x] checks if [x] is bound in [tbl]. *) - val remove: t -> key -> unit -(** [Hashtbl.remove tbl x] removes the current binding of [x] in [tbl], - restoring the previous binding if it exists. - It does nothing if [x] is not bound in [tbl]. *) - - - - - -val iter : (key -> unit [@bs]) -> t -> unit -(** [Hashtbl.iter f tbl] applies [f] to all bindings in table [tbl]. - [f] receives the key as first argument, and the associated value - as second argument. Each binding is presented exactly once to [f]. - - The order in which the bindings are passed to [f] is unspecified. - However, if the table contains several bindings for the same key, - they are passed to [f] in reverse order of introduction, that is, - the most recent binding is passed first. - - If the hash table was created in non-randomized mode, the order - in which the bindings are enumerated is reproducible between - successive runs of the program, and even between minor versions - of OCaml. For randomized hash tables, the order of enumeration - is entirely random. *) - - -val fold : (key -> 'c -> 'c [@bs]) -> t -> 'c -> 'c -(** [Hashtbl.fold f tbl init] computes - [(f kN dN ... (f k1 d1 init)...)], - where [k1 ... kN] are the keys of all bindings in [tbl], - and [d1 ... dN] are the associated values. - Each binding is presented exactly once to [f]. - - The order in which the bindings are passed to [f] is unspecified. - However, if the table contains several bindings for the same key, - they are passed to [f] in reverse order of introduction, that is, - the most recent binding is passed first. - - If the hash table was created in non-randomized mode, the order - in which the bindings are enumerated is reproducible between - successive runs of the program, and even between minor versions - of OCaml. For randomized hash tables, the order of enumeration - is entirely random. *) - - +val iter : t -> (key -> unit [@bs]) -> unit +val fold : t -> 'c -> (key -> 'c -> 'c [@bs]) -> 'c val length : t -> int -(** [Hashtbl.length tbl] returns the number of bindings in [tbl]. - It takes constant time. Multiple bindings are counted once each, so - [Hashtbl.length] gives the number of times [Hashtbl.iter] calls its - first argument. *) - - - - - val logStats : t -> unit -(** [Hashtbl.stats tbl] returns statistics about the table [tbl]: - number of buckets, size of the biggest bucket, distribution of - buckets by size. - @since 4.00.0 *) - -(** {6 Functorial interface} *) - -(** The functorial interface allows the use of specific comparison - and hash functions, either for performance/security concerns, - or because keys are not hashable/comparable with the polymorphic builtins. - - For instance, one might want to specialize a table for integer keys: - {[ - module IntHash = - struct - type t = int - let equal i j = i=j - let hash i = i land max_int - end - - module IntHashtbl = Hashtbl.Make(IntHash) - - let h = IntHashtbl.create 17 in - IntHashtbl.add h 12 "hello";; - ]} - - This creates a new module [IntHashtbl], with a new type ['a - IntHashtbl.t] of tables from [int] to ['a]. In this example, [h] - contains [string] values so its type is [string IntHashtbl.t]. - - Note that the new type ['a IntHashtbl.t] is not compatible with - the type [('a,'b) Hashtbl.t] of the generic interface. For - example, [Hashtbl.length h] would not type-check, you must use - [IntHashtbl.length]. -*) - - - val toArray : t -> key array - val ofArray : key array -> t - val addArray : t -> key array -> unit \ No newline at end of file diff --git a/jscomp/others/bs_internalBuckets.ml b/jscomp/others/bs_internalBuckets.ml index 5b6d4145bb..f00e67dcbe 100644 --- a/jscomp/others/bs_internalBuckets.ml +++ b/jscomp/others/bs_internalBuckets.ml @@ -55,7 +55,7 @@ let rec do_bucket_iter ~f buckets = | Some cell -> f (key cell) (value cell) [@bs]; do_bucket_iter ~f (next cell) -let iter0 f h = +let iter0 h f = let d = C.buckets h in for i = 0 to Bs_Array.length d - 1 do do_bucket_iter f (Bs_Array.unsafe_get d i) @@ -69,7 +69,7 @@ let rec do_bucket_fold ~f b accu = | Some cell -> do_bucket_fold ~f (next cell) (f (key cell) (value cell) accu [@bs]) -let fold0 f h init = +let fold0 h init f = let d = C.buckets h in let accu = ref init in for i = 0 to Bs_Array.length d - 1 do @@ -124,7 +124,7 @@ let rec filterMapInplaceBucket f h i prec cell = filterMapInplaceBucket f h i bucket nextCell end -let filterMapInplace0 f h = +let filterMapInplace0 h f = let h_buckets = C.buckets h in for i = 0 to Bs_Array.length h_buckets - 1 do let v = Bs_Array.unsafe_get h_buckets i in @@ -132,3 +132,22 @@ let filterMapInplace0 f h = | None -> () | Some v -> filterMapInplaceBucket f h i C.emptyOpt v done + +let rec fillArray i arr cell = + Bs_Array.unsafe_set arr i (key cell, value cell); + match C.toOpt (next cell) with + | None -> i + 1 + | Some v -> fillArray (i + 1) arr v + +let toArray0 h = + let d = C.buckets h in + let current = ref 0 in + let arr = Bs.Array.makeUninitializedUnsafe (C.size h) in + for i = 0 to Bs_Array.length d - 1 do + let cell = Bs_Array.unsafe_get d i in + match C.toOpt cell with + | None -> () + | Some cell -> + current := fillArray !current arr cell + done; + arr \ No newline at end of file diff --git a/jscomp/others/bs_internalSetBuckets.ml b/jscomp/others/bs_internalSetBuckets.ml index 3b6a74b599..ad6bb7cc6a 100644 --- a/jscomp/others/bs_internalSetBuckets.ml +++ b/jscomp/others/bs_internalSetBuckets.ml @@ -52,7 +52,7 @@ let rec do_bucket_iter ~f buckets = | Some cell -> f (key cell) [@bs]; do_bucket_iter ~f (next cell) -let iter0 f h = +let iter0 h f = let d = C.buckets h in for i = 0 to Bs_Array.length d - 1 do do_bucket_iter f (Bs_Array.unsafe_get d i) @@ -86,7 +86,7 @@ let rec do_bucket_fold ~f b accu = | Some cell -> do_bucket_fold ~f (next cell) (f (key cell) accu [@bs]) -let fold0 f h init = +let fold0 h init f = let d = C.buckets h in let accu = ref init in for i = 0 to Bs_Array.length d - 1 do diff --git a/jscomp/others/hashmap.cppo.ml b/jscomp/others/hashmap.cppo.ml index dd98ef2f31..f1a9b99ad2 100644 --- a/jscomp/others/hashmap.cppo.ml +++ b/jscomp/others/hashmap.cppo.ml @@ -212,4 +212,21 @@ let iter = N.iter0 let fold = N.fold0 let logStats = N.logStats0 let filterMapInplace = N.filterMapInplace0 - +let toArray = N.toArray0 + +let ofArray arr = + let len = Bs.Array.length arr in + let v = create len in + for i = 0 to len - 1 do + let k,value = (Bs.Array.unsafe_get arr i) in + add v k value + done ; + v + +(* TOOD: optimize heuristics for resizing *) +let addArray h arr = + let len = Bs.Array.length arr in + for i = 0 to len - 1 do + let k,v = (Bs_Array.unsafe_get arr i) in + add h k v +done diff --git a/jscomp/others/hashmap.cppo.mli b/jscomp/others/hashmap.cppo.mli index b63f26203b..20ff884bce 100644 --- a/jscomp/others/hashmap.cppo.mli +++ b/jscomp/others/hashmap.cppo.mli @@ -11,44 +11,6 @@ type 'b t val create : int -> 'b t -(** [Hashtbl.create n] creates a new, empty hash table, with - initial size [n]. For best results, [n] should be on the - order of the expected number of elements that will be in - the table. The table grows as needed, so [n] is just an - initial guess. - - The optional [random] parameter (a boolean) controls whether - the internal organization of the hash table is randomized at each - execution of [Hashtbl.create] or deterministic over all executions. - - A hash table that is created with [~random:false] uses a - fixed hash function ({!Hashtbl.hash}) to distribute keys among - buckets. As a consequence, collisions between keys happen - deterministically. In Web-facing applications or other - security-sensitive applications, the deterministic collision - patterns can be exploited by a malicious user to create a - denial-of-service attack: the attacker sends input crafted to - create many collisions in the table, slowing the application down. - - A hash table that is created with [~random:true] uses the seeded - hash function {!Hashtbl.seeded_hash} with a seed that is randomly - chosen at hash table creation time. In effect, the hash function - used is randomly selected among [2^{30}] different hash functions. - All these hash functions have different collision patterns, - rendering ineffective the denial-of-service attack described above. - However, because of randomization, enumerating all elements of the - hash table using {!Hashtbl.fold} or {!Hashtbl.iter} is no longer - deterministic: elements are enumerated in different orders at - different runs of the program. - - If no [~random] parameter is given, hash tables are created - in non-random mode by default. This default can be changed - either programmatically by calling {!Hashtbl.randomize} or by - setting the [R] flag in the [OCAMLRUNPARAM] environment variable. - - @before 4.00.0 the [random] parameter was not present and all - hash tables were created in non-randomized mode. *) - val clear : 'b t -> unit (** Empty a hash table. Use [reset] instead of [clear] to shrink the @@ -60,146 +22,38 @@ val reset : 'b t -> unit to its initial size. @since 4.00.0 *) +val add : 'a t -> key -> 'a -> unit +val findOpt: 'a t -> key -> 'a option - -val add : 'b t -> key -> 'b -> unit -(** [Hashtbl.add tbl x y] adds a binding of [x] to [y] in table [tbl]. - Previous bindings for [x] are not removed, but simply - hidden. That is, after performing {!Hashtbl.remove}[ tbl x], - the previous binding for [x], if any, is restored. - (Same behavior as with association lists.) *) - -val findOpt: - 'b t -> key -> 'b option -(** [findOpt tbl x] returns the current binding of [x] in [tbl], - *) - -val findAll: 'b t -> key -> 'b list +val findAll: 'a t -> key -> 'a list (** [Hashtbl.find_all tbl x] returns the list of all data associated with [x] in [tbl]. The current binding is returned first, then the previous bindings, in reverse order of introduction in the table. *) -val mem: - 'b t -> key -> bool -(** [Hashtbl.mem tbl x] checks if [x] is bound in [tbl]. *) - -val remove: - 'b t -> key -> unit -(** [Hashtbl.remove tbl x] removes the current binding of [x] in [tbl], - restoring the previous binding if it exists. - It does nothing if [x] is not bound in [tbl]. *) - -val removeAll: - 'b t -> key -> unit - - -val replace: - 'b t -> key -> 'b -> unit -(** [Hashtbl.replace tbl x y] replaces the current binding of [x] - in [tbl] by a binding of [x] to [y]. If [x] is unbound in [tbl], - a binding of [x] to [y] is added to [tbl]. - This is functionally equivalent to {!Hashtbl.remove}[ tbl x] - followed by {!Hashtbl.add}[ tbl x y]. *) - - -val iter : (key -> 'b -> unit [@bs]) -> 'b t -> unit -(** [Hashtbl.iter f tbl] applies [f] to all bindings in table [tbl]. - [f] receives the key as first argument, and the associated value - as second argument. Each binding is presented exactly once to [f]. - - The order in which the bindings are passed to [f] is unspecified. - However, if the table contains several bindings for the same key, - they are passed to [f] in reverse order of introduction, that is, - the most recent binding is passed first. - - If the hash table was created in non-randomized mode, the order - in which the bindings are enumerated is reproducible between - successive runs of the program, and even between minor versions - of OCaml. For randomized hash tables, the order of enumeration - is entirely random. *) - - -val fold : (key -> 'b -> 'c -> 'c [@bs]) -> 'b t -> 'c -> 'c -(** [Hashtbl.fold f tbl init] computes - [(f kN dN ... (f k1 d1 init)...)], - where [k1 ... kN] are the keys of all bindings in [tbl], - and [d1 ... dN] are the associated values. - Each binding is presented exactly once to [f]. - - The order in which the bindings are passed to [f] is unspecified. - However, if the table contains several bindings for the same key, - they are passed to [f] in reverse order of introduction, that is, - the most recent binding is passed first. - - If the hash table was created in non-randomized mode, the order - in which the bindings are enumerated is reproducible between - successive runs of the program, and even between minor versions - of OCaml. For randomized hash tables, the order of enumeration - is entirely random. *) - - -val filterMapInplace : (key -> 'b -> 'b option [@bs]) -> 'b t -> unit - -val length : 'b t -> int -(** [Hashtbl.length tbl] returns the number of bindings in [tbl]. - It takes constant time. Multiple bindings are counted once each, so - [Hashtbl.length] gives the number of times [Hashtbl.iter] calls its - first argument. *) - - -(* -type statistics = { - num_bindings: int; - (** Number of bindings present in the table. - Same value as returned by {!Hashtbl.length}. *) - num_buckets: int; - (** Number of buckets in the table. *) - max_bucket_length: int; - (** Maximal number of bindings per bucket. *) - bucket_histogram: int array - (** Histogram of bucket sizes. This array [histo] has - length [max_bucket_length + 1]. The value of - [histo.(i)] is the number of buckets whose size is [i]. *) -} *) +val mem: 'b t -> key -> bool -val logStats : _ t -> unit -(** [Hashtbl.stats tbl] returns statistics about the table [tbl]: - number of buckets, size of the biggest bucket, distribution of - buckets by size. - @since 4.00.0 *) +val remove: 'a t -> key -> unit + +val removeAll: 'b t -> key -> unit -(** {6 Functorial interface} *) +val replace: 'b t -> key -> 'b -> unit -(** The functorial interface allows the use of specific comparison - and hash functions, either for performance/security concerns, - or because keys are not hashable/comparable with the polymorphic builtins. - For instance, one might want to specialize a table for integer keys: - {[ - module IntHash = - struct - type t = int - let equal i j = i=j - let hash i = i land max_int - end +val iter : 'b t -> (key -> 'b -> unit [@bs]) -> unit - module IntHashtbl = Hashtbl.Make(IntHash) +val fold : 'b t -> 'c -> (key -> 'b -> 'c -> 'c [@bs]) -> 'c - let h = IntHashtbl.create 17 in - IntHashtbl.add h 12 "hello";; - ]} - This creates a new module [IntHashtbl], with a new type ['a - IntHashtbl.t] of tables from [int] to ['a]. In this example, [h] - contains [string] values so its type is [string IntHashtbl.t]. +val filterMapInplace : 'a t -> (key -> 'a -> 'a option [@bs]) -> unit + +val length : _ t -> int +val logStats : _ t -> unit - Note that the new type ['a IntHashtbl.t] is not compatible with - the type [('a,'b) Hashtbl.t] of the generic interface. For - example, [Hashtbl.length h] would not type-check, you must use - [IntHashtbl.length]. -*) +val toArray : 'a t -> (key * 'a) array +val ofArray : (key * 'a) array -> 'a t +val addArray : 'a t -> (key * 'a) array -> unit diff --git a/jscomp/others/hashset.cppo.mli b/jscomp/others/hashset.cppo.mli index 74e4b66861..b6bccf55dc 100644 --- a/jscomp/others/hashset.cppo.mli +++ b/jscomp/others/hashset.cppo.mli @@ -8,172 +8,18 @@ type key = int type t - - - - val create : int -> t - -(** [Hashtbl.create n] creates a new, empty hash table, with - initial size [n]. For best results, [n] should be on the - order of the expected number of elements that will be in - the table. The table grows as needed, so [n] is just an - initial guess. - - The optional [random] parameter (a boolean) controls whether - the internal organization of the hash table is randomized at each - execution of [Hashtbl.create] or deterministic over all executions. - - A hash table that is created with [~random:false] uses a - fixed hash function ({!Hashtbl.hash}) to distribute keys among - buckets. As a consequence, collisions between keys happen - deterministically. In Web-facing applications or other - security-sensitive applications, the deterministic collision - patterns can be exploited by a malicious user to create a - denial-of-service attack: the attacker sends input crafted to - create many collisions in the table, slowing the application down. - - A hash table that is created with [~random:true] uses the seeded - hash function {!Hashtbl.seeded_hash} with a seed that is randomly - chosen at hash table creation time. In effect, the hash function - used is randomly selected among [2^{30}] different hash functions. - All these hash functions have different collision patterns, - rendering ineffective the denial-of-service attack described above. - However, because of randomization, enumerating all elements of the - hash table using {!Hashtbl.fold} or {!Hashtbl.iter} is no longer - deterministic: elements are enumerated in different orders at - different runs of the program. - - If no [~random] parameter is given, hash tables are created - in non-random mode by default. This default can be changed - either programmatically by calling {!Hashtbl.randomize} or by - setting the [R] flag in the [OCAMLRUNPARAM] environment variable. - - @before 4.00.0 the [random] parameter was not present and all - hash tables were created in non-randomized mode. *) - - val clear : t -> unit -(** Empty a hash table. Use [reset] instead of [clear] to shrink the - size of the bucket table to its initial size. *) - - val reset : t -> unit -(** Empty a hash table and shrink the size of the bucket table - to its initial size. - @since 4.00.0 *) - - - val add : t -> key -> unit -(** [Hashtbl.add tbl x y] adds a binding of [x] to [y] in table [tbl]. - Previous bindings for [x] are not removed, but simply - hidden. That is, after performing {!Hashtbl.remove}[ tbl x], - the previous binding for [x], if any, is restored. - (Same behavior as with association lists.) *) - - val mem: t -> key -> bool -(** [Hashtbl.mem tbl x] checks if [x] is bound in [tbl]. *) - val remove: t -> key -> unit -(** [Hashtbl.remove tbl x] removes the current binding of [x] in [tbl], - restoring the previous binding if it exists. - It does nothing if [x] is not bound in [tbl]. *) - - - - - -val iter : (key -> unit [@bs]) -> t -> unit -(** [Hashtbl.iter f tbl] applies [f] to all bindings in table [tbl]. - [f] receives the key as first argument, and the associated value - as second argument. Each binding is presented exactly once to [f]. - - The order in which the bindings are passed to [f] is unspecified. - However, if the table contains several bindings for the same key, - they are passed to [f] in reverse order of introduction, that is, - the most recent binding is passed first. - - If the hash table was created in non-randomized mode, the order - in which the bindings are enumerated is reproducible between - successive runs of the program, and even between minor versions - of OCaml. For randomized hash tables, the order of enumeration - is entirely random. *) - - -val fold : (key -> 'c -> 'c [@bs]) -> t -> 'c -> 'c -(** [Hashtbl.fold f tbl init] computes - [(f kN dN ... (f k1 d1 init)...)], - where [k1 ... kN] are the keys of all bindings in [tbl], - and [d1 ... dN] are the associated values. - Each binding is presented exactly once to [f]. - - The order in which the bindings are passed to [f] is unspecified. - However, if the table contains several bindings for the same key, - they are passed to [f] in reverse order of introduction, that is, - the most recent binding is passed first. - - If the hash table was created in non-randomized mode, the order - in which the bindings are enumerated is reproducible between - successive runs of the program, and even between minor versions - of OCaml. For randomized hash tables, the order of enumeration - is entirely random. *) - - +val iter : t -> (key -> unit [@bs]) -> unit +val fold : t -> 'c -> (key -> 'c -> 'c [@bs]) -> 'c val length : t -> int -(** [Hashtbl.length tbl] returns the number of bindings in [tbl]. - It takes constant time. Multiple bindings are counted once each, so - [Hashtbl.length] gives the number of times [Hashtbl.iter] calls its - first argument. *) - - - - - val logStats : t -> unit -(** [Hashtbl.stats tbl] returns statistics about the table [tbl]: - number of buckets, size of the biggest bucket, distribution of - buckets by size. - @since 4.00.0 *) - -(** {6 Functorial interface} *) - -(** The functorial interface allows the use of specific comparison - and hash functions, either for performance/security concerns, - or because keys are not hashable/comparable with the polymorphic builtins. - - For instance, one might want to specialize a table for integer keys: - {[ - module IntHash = - struct - type t = int - let equal i j = i=j - let hash i = i land max_int - end - - module IntHashtbl = Hashtbl.Make(IntHash) - - let h = IntHashtbl.create 17 in - IntHashtbl.add h 12 "hello";; - ]} - - This creates a new module [IntHashtbl], with a new type ['a - IntHashtbl.t] of tables from [int] to ['a]. In this example, [h] - contains [string] values so its type is [string IntHashtbl.t]. - - Note that the new type ['a IntHashtbl.t] is not compatible with - the type [('a,'b) Hashtbl.t] of the generic interface. For - example, [Hashtbl.length h] would not type-check, you must use - [IntHashtbl.length]. -*) - - - val toArray : t -> key array - val ofArray : key array -> t - val addArray : t -> key array -> unit \ No newline at end of file diff --git a/jscomp/test/.depend b/jscomp/test/.depend index 6a0e80100f..5d1487596b 100644 --- a/jscomp/test/.depend +++ b/jscomp/test/.depend @@ -90,7 +90,7 @@ bs_abstract_test.cmj : ../runtime/js.cmj bs_array_test.cmj : mt.cmj ../runtime/js.cmj ../others/bs.cmj bs_auto_uncurry.cmj : ../runtime/js.cmj bs_auto_uncurry_test.cmj : mt.cmj ../others/js_array.cmj ../runtime/js.cmj -bs_hashmap_test.cmj : +bs_hashmap_test.cmj : mt.cmj ../others/bs.cmj array_data_util.cmj bs_hashset_int_test.cmj : mt.cmj ../others/bs.cmj array_data_util.cmj bs_hashtbl_string_test.cmj : ../stdlib/hashtbl.cmj ../others/bs.cmj bs_ignore_effect.cmj : mt.cmj diff --git a/jscomp/test/bs_hashmap_test.js b/jscomp/test/bs_hashmap_test.js index ae1b9f17e6..c7c6c5c9f1 100644 --- a/jscomp/test/bs_hashmap_test.js +++ b/jscomp/test/bs_hashmap_test.js @@ -1 +1,36 @@ -/* This output is empty. Its source's type definitions, externals and/or unused code got optimized away. */ +'use strict'; + +var Mt = require("./mt.js"); +var Bs_Array = require("../../lib/js/bs_Array.js"); + +var suites = [/* [] */0]; + +var test_id = [0]; + +function eq(loc, x, y) { + return Mt.eq_suites(test_id, suites, loc, x, y); +} + +function add(x, y) { + return x + y | 0; +} + +Mt.from_pair_suites("bs_hashmap_test.ml", suites[0]); + +var N = 0; + +var S = 0; + +var I = 0; + +var $plus$plus = Bs_Array.append; + +exports.suites = suites; +exports.test_id = test_id; +exports.eq = eq; +exports.N = N; +exports.S = S; +exports.I = I; +exports.$plus$plus = $plus$plus; +exports.add = add; +/* Not a pure module */ diff --git a/jscomp/test/bs_hashmap_test.ml b/jscomp/test/bs_hashmap_test.ml index e69de29bb2..676f331974 100644 --- a/jscomp/test/bs_hashmap_test.ml +++ b/jscomp/test/bs_hashmap_test.ml @@ -0,0 +1,16 @@ +let suites : Mt.pair_suites ref = ref [] +let test_id = ref 0 +let eq loc x y = Mt.eq_suites ~test_id ~suites loc x y + +module N = Bs.HashMapInt +module S = Bs.SetInt + +module I = Array_data_util +let (++) = Bs.Array.append +let add = fun [@bs] x y -> x + y + + + + + +;; Mt.from_pair_suites __FILE__ !suites \ No newline at end of file diff --git a/jscomp/test/bs_hashset_int_test.js b/jscomp/test/bs_hashset_int_test.js index 89dde3137d..b0ff435b5c 100644 --- a/jscomp/test/bs_hashset_int_test.js +++ b/jscomp/test/bs_hashset_int_test.js @@ -1,7 +1,6 @@ 'use strict'; var Mt = require("./mt.js"); -var Block = require("../../lib/js/block.js"); var Bs_Array = require("../../lib/js/bs_Array.js"); var Bs_SetInt = require("../../lib/js/bs_SetInt.js"); var Bs_HashSetInt = require("../../lib/js/bs_HashSetInt.js"); @@ -12,31 +11,35 @@ var suites = [/* [] */0]; var test_id = [0]; function eq(loc, x, y) { - test_id[0] = test_id[0] + 1 | 0; - suites[0] = /* :: */[ - /* tuple */[ - loc + (" id " + test_id[0]), - (function () { - return /* Eq */Block.__(0, [ - x, - y - ]); - }) - ], - suites[0] - ]; - return /* () */0; + return Mt.eq_suites(test_id, suites, loc, x, y); +} + +function add(x, y) { + return x + y | 0; +} + +function sum2(h) { + var v = [0]; + Bs_HashSetInt.iter(h, (function (x) { + v[0] = v[0] + x | 0; + return /* () */0; + })); + return v[0]; } var u = Bs_Array.append(Array_data_util.randomRange(30, 100), Array_data_util.randomRange(40, 120)); var v = Bs_HashSetInt.ofArray(u); -eq("File \"bs_hashset_int_test.ml\", line 17, characters 5-12", Bs_HashSetInt.length(v), 91); +eq("File \"bs_hashset_int_test.ml\", line 19, characters 5-12", Bs_HashSetInt.length(v), 91); var xs = Bs_SetInt.toArray(Bs_SetInt.ofArray(Bs_HashSetInt.toArray(v))); -eq("File \"bs_hashset_int_test.ml\", line 19, characters 5-12", xs, Array_data_util.range(30, 120)); +eq("File \"bs_hashset_int_test.ml\", line 21, characters 5-12", xs, Array_data_util.range(30, 120)); + +eq("File \"bs_hashset_int_test.ml\", line 23, characters 5-12", Bs_HashSetInt.fold(v, 0, add), 6825); + +eq("File \"bs_hashset_int_test.ml\", line 24, characters 5-12", sum2(v), 6825); var u$1 = Bs_Array.append(Array_data_util.randomRange(0, 100000), Array_data_util.randomRange(0, 100)); @@ -44,19 +47,19 @@ var v$1 = Bs_HashSetInt.create(40); Bs_HashSetInt.addArray(v$1, u$1); -eq("File \"bs_hashset_int_test.ml\", line 25, characters 5-12", Bs_HashSetInt.length(v$1), 100001); +eq("File \"bs_hashset_int_test.ml\", line 30, characters 5-12", Bs_HashSetInt.length(v$1), 100001); for(var i = 0; i <= 1000; ++i){ Bs_HashSetInt.remove(v$1, i); } -eq("File \"bs_hashset_int_test.ml\", line 29, characters 5-12", Bs_HashSetInt.length(v$1), 99000); +eq("File \"bs_hashset_int_test.ml\", line 34, characters 5-12", Bs_HashSetInt.length(v$1), 99000); for(var i$1 = 0; i$1 <= 2000; ++i$1){ Bs_HashSetInt.remove(v$1, i$1); } -eq("File \"bs_hashset_int_test.ml\", line 33, characters 5-12", Bs_HashSetInt.length(v$1), 98000); +eq("File \"bs_hashset_int_test.ml\", line 38, characters 5-12", Bs_HashSetInt.length(v$1), 98000); Mt.from_pair_suites("bs_hashset_int_test.ml", suites[0]); @@ -75,4 +78,6 @@ exports.N = N; exports.S = S; exports.I = I; exports.$plus$plus = $plus$plus; +exports.add = add; +exports.sum2 = sum2; /* u Not a pure module */ diff --git a/jscomp/test/bs_hashset_int_test.ml b/jscomp/test/bs_hashset_int_test.ml index 9d61af6547..dfc312eb06 100644 --- a/jscomp/test/bs_hashset_int_test.ml +++ b/jscomp/test/bs_hashset_int_test.ml @@ -1,22 +1,27 @@ let suites : Mt.pair_suites ref = ref [] let test_id = ref 0 -let eq loc x y = - incr test_id ; - suites := - (loc ^" id " ^ (string_of_int !test_id), (fun _ -> Mt.Eq(x,y))) :: !suites +let eq loc x y = Mt.eq_suites ~test_id ~suites loc x y module N = Bs.HashSetInt module S = Bs.SetInt module I = Array_data_util let (++) = Bs.Array.append +let add = fun [@bs] x y -> x + y +let sum2 h = + let v = ref 0 in + N.iter h (fun [@bs] x -> v := !v + x) ; + !v let () = let u = I.randomRange 30 100 ++ I.randomRange 40 120 in let v = N.ofArray u in eq __LOC__ (N.length v) 91 ; let xs = S.toArray (S.ofArray (N.toArray v)) in - eq __LOC__ xs (I.range 30 120) + eq __LOC__ xs (I.range 30 120); + let x = ((30 + 120)/2 * 91) in + eq __LOC__ (N.fold v 0 add) x ; + eq __LOC__ (sum2 v ) x let () = let u = I.randomRange 0 100_000 ++ I.randomRange 0 100 in diff --git a/lib/js/bs_HashMap.js b/lib/js/bs_HashMap.js index 7f1c7f73bf..93c35c12c5 100644 --- a/lib/js/bs_HashMap.js +++ b/lib/js/bs_HashMap.js @@ -296,12 +296,12 @@ function length(h) { return h.data.size; } -function iter(f, h) { - return Bs_internalBuckets.iter0(f, h.data); +function iter(h, f) { + return Bs_internalBuckets.iter0(h.data, f); } -function fold(f, h, init) { - return Bs_internalBuckets.fold0(f, h.data, init); +function fold(h, init, f) { + return Bs_internalBuckets.fold0(h.data, init, f); } function logStats(h) { @@ -350,8 +350,8 @@ function mem(h, key) { return mem0(dict[/* hash */0], dict[/* eq */1], data, key); } -function filterMapInplace(f, h) { - return Bs_internalBuckets.filterMapInplace0(f, h.data); +function filterMapInplace(h, f) { + return Bs_internalBuckets.filterMapInplace0(h.data, f); } var create0 = Bs_internalBucketsType.create0; diff --git a/lib/js/bs_HashMapInt.js b/lib/js/bs_HashMapInt.js index b897c37a1b..2db240549c 100644 --- a/lib/js/bs_HashMapInt.js +++ b/lib/js/bs_HashMapInt.js @@ -269,6 +269,25 @@ function mem(h, key) { }; } +function ofArray(arr) { + var len = arr.length; + var v = Bs_internalBucketsType.create0(len); + for(var i = 0 ,i_finish = len - 1 | 0; i <= i_finish; ++i){ + var match = arr[i]; + add(v, match[0], match[1]); + } + return v; +} + +function addArray(h, arr) { + var len = arr.length; + for(var i = 0 ,i_finish = len - 1 | 0; i <= i_finish; ++i){ + var match = arr[i]; + add(h, match[0], match[1]); + } + return /* () */0; +} + var create = Bs_internalBucketsType.create0; var clear = Bs_internalBucketsType.clear0; @@ -285,6 +304,8 @@ var length = Bs_internalBucketsType.length0; var logStats = Bs_internalBuckets.logStats0; +var toArray = Bs_internalBuckets.toArray0; + exports.create = create; exports.clear = clear; exports.reset = reset; @@ -300,4 +321,7 @@ exports.fold = fold; exports.filterMapInplace = filterMapInplace; exports.length = length; exports.logStats = logStats; +exports.toArray = toArray; +exports.ofArray = ofArray; +exports.addArray = addArray; /* No side effect */ diff --git a/lib/js/bs_HashMapString.js b/lib/js/bs_HashMapString.js index bfd3cf7200..4f5abaa1eb 100644 --- a/lib/js/bs_HashMapString.js +++ b/lib/js/bs_HashMapString.js @@ -269,6 +269,25 @@ function mem(h, key) { }; } +function ofArray(arr) { + var len = arr.length; + var v = Bs_internalBucketsType.create0(len); + for(var i = 0 ,i_finish = len - 1 | 0; i <= i_finish; ++i){ + var match = arr[i]; + add(v, match[0], match[1]); + } + return v; +} + +function addArray(h, arr) { + var len = arr.length; + for(var i = 0 ,i_finish = len - 1 | 0; i <= i_finish; ++i){ + var match = arr[i]; + add(h, match[0], match[1]); + } + return /* () */0; +} + var create = Bs_internalBucketsType.create0; var clear = Bs_internalBucketsType.clear0; @@ -285,6 +304,8 @@ var length = Bs_internalBucketsType.length0; var logStats = Bs_internalBuckets.logStats0; +var toArray = Bs_internalBuckets.toArray0; + exports.create = create; exports.clear = clear; exports.reset = reset; @@ -300,4 +321,7 @@ exports.fold = fold; exports.filterMapInplace = filterMapInplace; exports.length = length; exports.logStats = logStats; +exports.toArray = toArray; +exports.ofArray = ofArray; +exports.addArray = addArray; /* No side effect */ diff --git a/lib/js/bs_HashSet.js b/lib/js/bs_HashSet.js index c87b206f03..e1c3b682d4 100644 --- a/lib/js/bs_HashSet.js +++ b/lib/js/bs_HashSet.js @@ -182,12 +182,12 @@ function length(h) { return h.data.size; } -function iter(f, h) { - return Bs_internalSetBuckets.iter0(f, h.data); +function iter(h, f) { + return Bs_internalSetBuckets.iter0(h.data, f); } -function fold(f, h, init) { - return Bs_internalSetBuckets.fold0(f, h.data, init); +function fold(h, init, f) { + return Bs_internalSetBuckets.fold0(h.data, init, f); } function logStats(h) { diff --git a/lib/js/bs_internalBuckets.js b/lib/js/bs_internalBuckets.js index 9e19859ed1..9ba15a56c9 100644 --- a/lib/js/bs_internalBuckets.js +++ b/lib/js/bs_internalBuckets.js @@ -33,7 +33,7 @@ function do_bucket_iter(f, _buckets) { }; } -function iter0(f, h) { +function iter0(h, f) { var d = h.buckets; for(var i = 0 ,i_finish = d.length - 1 | 0; i <= i_finish; ++i){ do_bucket_iter(f, d[i]); @@ -56,7 +56,7 @@ function do_bucket_fold(f, _b, _accu) { }; } -function fold0(f, h, init) { +function fold0(h, init, f) { var d = h.buckets; var accu = init; for(var i = 0 ,i_finish = d.length - 1 | 0; i <= i_finish; ++i){ @@ -128,7 +128,7 @@ function filterMapInplaceBucket(f, h, i, _prec, _cell) { }; } -function filterMapInplace0(f, h) { +function filterMapInplace0(h, f) { var h_buckets = h.buckets; for(var i = 0 ,i_finish = h_buckets.length - 1 | 0; i <= i_finish; ++i){ var v = h_buckets[i]; @@ -140,6 +140,40 @@ function filterMapInplace0(f, h) { return /* () */0; } +function fillArray(_i, arr, _cell) { + while(true) { + var cell = _cell; + var i = _i; + arr[i] = /* tuple */[ + cell.key, + cell.value + ]; + var match = cell.next; + if (match !== undefined) { + _cell = match; + _i = i + 1 | 0; + continue ; + + } else { + return i + 1 | 0; + } + }; +} + +function toArray0(h) { + var d = h.buckets; + var current = 0; + var arr = new Array(h.size); + for(var i = 0 ,i_finish = d.length - 1 | 0; i <= i_finish; ++i){ + var cell = d[i]; + if (cell !== undefined) { + current = fillArray(current, arr, cell); + } + + } + return arr; +} + var C = 0; exports.C = C; @@ -151,4 +185,6 @@ exports.fold0 = fold0; exports.logStats0 = logStats0; exports.filterMapInplaceBucket = filterMapInplaceBucket; exports.filterMapInplace0 = filterMapInplace0; +exports.fillArray = fillArray; +exports.toArray0 = toArray0; /* No side effect */ diff --git a/lib/js/bs_internalSetBuckets.js b/lib/js/bs_internalSetBuckets.js index eb39cae7fc..ca6024e3e5 100644 --- a/lib/js/bs_internalSetBuckets.js +++ b/lib/js/bs_internalSetBuckets.js @@ -32,7 +32,7 @@ function do_bucket_iter(f, _buckets) { }; } -function iter0(f, h) { +function iter0(h, f) { var d = h.buckets; for(var i = 0 ,i_finish = d.length - 1 | 0; i <= i_finish; ++i){ do_bucket_iter(f, d[i]); @@ -86,7 +86,7 @@ function do_bucket_fold(f, _b, _accu) { }; } -function fold0(f, h, init) { +function fold0(h, init, f) { var d = h.buckets; var accu = init; for(var i = 0 ,i_finish = d.length - 1 | 0; i <= i_finish; ++i){