From 8f313b3e47e0903e2868f5b638f21aa1187062ca Mon Sep 17 00:00:00 2001 From: Hongbo Zhang Date: Tue, 26 Dec 2017 20:51:41 +0800 Subject: [PATCH] add multimap initial --- jscomp/others/.depend | 3 + jscomp/others/Makefile | 1 + jscomp/others/bs.ml | 1 + jscomp/others/bs_HashMultiMap.ml | 264 +++++++++++++++++++ jscomp/others/bs_HashMultiMap.mli | 202 +++++++++++++++ lib/js/bs.js | 3 + lib/js/bs_HashMultiMap.js | 403 ++++++++++++++++++++++++++++++ 7 files changed, 877 insertions(+) create mode 100644 jscomp/others/bs_HashMultiMap.ml create mode 100644 jscomp/others/bs_HashMultiMap.mli create mode 100644 lib/js/bs_HashMultiMap.js diff --git a/jscomp/others/.depend b/jscomp/others/.depend index d9391b003f5..93300a09d28 100644 --- a/jscomp/others/.depend +++ b/jscomp/others/.depend @@ -28,6 +28,8 @@ bs_internalSetBuckets.cmj : bs_internalBucketsType.cmj bs_Array.cmj bs.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_HashMultiMap.cmj : bs_internalBucketsType.cmj bs_internalBuckets.cmj \ + bs_Hash.cmj bs_Bag.cmj bs_Array.cmj bs_HashMultiMap.cmi bs_HashSet.cmj : bs_internalSetBuckets.cmj bs_internalBucketsType.cmj \ bs_Hash.cmj bs_Bag.cmj bs_Array.cmj bs.cmj bs_HashSet.cmi bs_HashSetString.cmj : bs_internalSetBuckets.cmj bs_internalBucketsType.cmj \ @@ -71,6 +73,7 @@ bs_Hash.cmi : bs_Queue.cmi : bs_List.cmi : js_json.cmi bs_HashMap.cmi : bs_Hash.cmi bs_Bag.cmj +bs_HashMultiMap.cmi : bs_Hash.cmi bs_Bag.cmj bs_HashSet.cmi : bs_Hash.cmi bs_Bag.cmj bs_HashSetString.cmi : bs_HashSetInt.cmi : diff --git a/jscomp/others/Makefile b/jscomp/others/Makefile index 311dc5a4e37..c46a5009593 100644 --- a/jscomp/others/Makefile +++ b/jscomp/others/Makefile @@ -22,6 +22,7 @@ SOURCE_LIST= node_path node_fs node_process dict node_module js_array js_string bs_internalSetBuckets\ bs_internalBuckets\ bs_HashMap\ + bs_HashMultiMap\ bs_HashSet\ bs_HashSetString\ bs_HashSetInt\ diff --git a/jscomp/others/bs.ml b/jscomp/others/bs.ml index d852b6063cf..83fa1a1f0d0 100644 --- a/jscomp/others/bs.ml +++ b/jscomp/others/bs.ml @@ -36,6 +36,7 @@ module HashSet = Bs_HashSet module HashSetInt = Bs_HashSetInt module HashSetString = Bs_HashSetInt module HashMapString = Bs_HashMapString +module HashMultiMap = Bs_HashMultiMap module HashMapInt = Bs_HashMapInt module Map = Bs_Map module Set = Bs_Set diff --git a/jscomp/others/bs_HashMultiMap.ml b/jscomp/others/bs_HashMultiMap.ml new file mode 100644 index 00000000000..392325290fa --- /dev/null +++ b/jscomp/others/bs_HashMultiMap.ml @@ -0,0 +1,264 @@ +(***********************************************************************) +(* *) +(* OCaml *) +(* *) +(* Xavier Leroy, projet Cristal, INRIA Rocquencourt *) +(* *) +(* Copyright 1996 Institut National de Recherche en Informatique et *) +(* en Automatique. All rights reserved. This file is distributed *) +(* under the terms of the GNU Library General Public License, with *) +(* the special exception on linking described in file ../LICENSE. *) +(* *) +(***********************************************************************) +(** Adapted by Authors of BuckleScript 2017 *) + +module N = Bs_internalBuckets +module C = Bs_internalBucketsType +module B = Bs_Bag +type ('a, 'b,'id) t0 = ('a,'b) N.t0 + +type ('a,'b) bucket = ('a,'b) N.bucket + +type ('a,'b,'id) t = + (('a, 'id) Bs_Hash.t, + ('a,'b,'id) t0) B.bag + + + +let rec insert_bucket ~hash ~h_buckets ~ndata_tail h old_bucket = + match C.toOpt old_bucket with + | None -> () + | Some cell -> + let nidx = (Bs_Hash.getHash hash) (N.key cell) [@bs] land (Array.length h_buckets - 1) in + let v = C.return cell in + begin match C.toOpt (Bs_Array.unsafe_get ndata_tail nidx) with + | None -> + Bs_Array.unsafe_set h_buckets nidx v + | Some tail -> + N.nextSet tail v (* cell put at the end *) + end; + Bs_Array.unsafe_set ndata_tail nidx v; + insert_bucket ~hash ~h_buckets ~ndata_tail h (N.next cell) + + +let resize ~hash h = + let odata = C.buckets h in + let osize = Array.length odata in + let nsize = osize * 2 in + if nsize >= osize then begin (* no overflow *) + let h_buckets = C.makeSize nsize in + let ndata_tail = C.makeSize nsize in (* keep track of tail *) + C.bucketsSet h h_buckets; (* so that indexfun sees the new bucket count *) + for i = 0 to osize - 1 do + insert_bucket ~hash ~h_buckets ~ndata_tail h (Bs_Array.unsafe_get odata i) + done; + for i = 0 to nsize - 1 do + match C.toOpt (Bs_Array.unsafe_get ndata_tail i) with + | None -> () + | Some tail -> N.nextSet tail C.emptyOpt + done + end + + +let add0 ~hash h key value = + let h_buckets = C.buckets h in + let h_buckets_lenth = Array.length h_buckets in + let i = (Bs_Hash.getHash hash) key [@bs] land (h_buckets_lenth - 1) in + let bucket = + N.bucket ~key ~value ~next:(Bs_Array.unsafe_get h_buckets i) in + Bs_Array.unsafe_set h_buckets i (C.return bucket); + let h_new_size = C.size h + 1 in + C.sizeSet h h_new_size; + if h_new_size > h_buckets_lenth lsl 1 then resize ~hash h + + +let rec remove_bucket ~eq h h_buckets i key prec buckets = + match C.toOpt buckets with + | None -> () + | Some cell -> + let cell_next = N.next cell in + if (Bs_Hash.getEq eq) (N.key cell) key [@bs] + then + begin + (match C.toOpt prec with + | None -> Bs_Array.unsafe_set h_buckets i cell_next + | Some c -> N.nextSet c cell_next); + C.sizeSet h (C.size h - 1); + end + else remove_bucket ~eq h h_buckets i key buckets cell_next + +let remove0 ~hash ~eq h key = + let h_buckets = C.buckets h in + let i = (Bs_Hash.getHash hash) key [@bs] land (Array.length h_buckets - 1) in + remove_bucket ~eq h h_buckets i key C.emptyOpt (Bs_Array.unsafe_get h_buckets i) + +let rec removeAllBuckets ~eq h h_buckets i key prec buckets = + match C.toOpt buckets with + | None -> () + | Some cell -> + let cell_next = N.next cell in + if (Bs_Hash.getEq eq) (N.key cell) key [@bs] + then + begin + (match C.toOpt prec with + | None -> Bs_Array.unsafe_set h_buckets i cell_next + | Some c -> N.nextSet c cell_next); + C.sizeSet h (C.size h - 1); + end; + removeAllBuckets ~eq h h_buckets i key buckets cell_next + +let removeAll0 ~hash ~eq h key = + let h_buckets = C.buckets h in + let i = (Bs_Hash.getHash hash) key [@bs] land (Array.length h_buckets - 1) in + removeAllBuckets ~eq h h_buckets i key C.emptyOpt (Bs_Array.unsafe_get h_buckets i) + + +let rec find_rec ~eq key buckets = + match C.toOpt buckets with + | None -> + None + | Some cell -> + if (Bs_Hash.getEq eq) key (N.key cell) [@bs] then Some (N.value cell) + else find_rec ~eq key (N.next cell) + +let findOpt0 ~hash ~eq h key = + let h_buckets = C.buckets h in + let nid = (Bs_Hash.getHash hash) key [@bs] land (Array.length h_buckets - 1) in + match C.toOpt @@ Bs_Array.unsafe_get h_buckets nid with + | None -> None + | Some cell1 -> + if (Bs_Hash.getEq eq) key (N.key cell1) [@bs] then + Some (N.value cell1) + else + match C.toOpt (N.next cell1) with + | None -> None + | Some cell2 -> + if (Bs_Hash.getEq eq) key + (N.key cell2) [@bs] then + Some (N.value cell2) else + match C.toOpt (N.next cell2) with + | None -> None + | Some cell3 -> + if (Bs_Hash.getEq eq) key + (N.key cell3) [@bs] then + Some (N.value cell3) + else + find_rec ~eq key (N.next cell3) + + +let findAll0 ~hash ~eq h key = + let rec find_in_bucket buckets = + match C.toOpt buckets with + | None -> + [] + | Some cell -> + if (Bs_Hash.getEq eq) + (N.key cell) key [@bs] + then (N.value cell) :: find_in_bucket (N.next cell) + else find_in_bucket (N.next cell) in + let h_buckets = C.buckets h in + let nid = (Bs_Hash.getHash hash) key [@bs] land (Array.length h_buckets - 1) in + find_in_bucket (Bs_Array.unsafe_get h_buckets nid) + +let rec replace_bucket ~eq key info buckets = + match C.toOpt buckets with + | None -> + true + | Some cell -> + if (Bs_Hash.getEq eq) (N.key cell) key [@bs] + then + begin + N.keySet cell key; + N.valueSet cell info; + false + end + else + replace_bucket ~eq key info (N.next cell) + +let replace0 ~hash ~eq h key info = + let h_buckets = C.buckets h in + let i = (Bs_Hash.getHash hash) key [@bs] land (Array.length h_buckets - 1) in + let l = Array.unsafe_get h_buckets i in + if replace_bucket ~eq key info l then begin + Bs_Array.unsafe_set h_buckets i (C.return + (N.bucket ~key ~value:info ~next:l)); + C.sizeSet h (C.size h + 1); + if C.size h > Array.length (C.buckets h) lsl 1 then resize ~hash h + (* TODO: duplicate bucklets ? *) + end + +let rec mem_in_bucket ~eq key cell = + (Bs_Hash.getEq eq) + (N.key cell) key [@bs] || + (match C.toOpt (N.next cell) with + | None -> false + | Some nextCell -> + mem_in_bucket ~eq key nextCell) + +let mem0 ~hash ~eq h key = + let h_buckets = C.buckets h in + let nid = (Bs_Hash.getHash hash) key [@bs] land (Array.length h_buckets - 1) in + let bucket = (Bs_Array.unsafe_get h_buckets nid) in + match C.toOpt bucket with + | None -> false + | Some bucket -> + mem_in_bucket ~eq key bucket + + +let create0 = C.create0 +let clear0 = C.clear0 +let reset0 = C.reset0 +let length0 = C.length0 +let iter0 = N.iter0 +let fold0 = N.fold0 +let logStats0 = N.logStats0 +let filterMapInplace0 = N.filterMapInplace0 + +(* Wrapper *) +let create dict initialize_size = + B.bag ~data:(create0 initialize_size) + ~dict +let clear h = clear0 (B.data h) +let reset h = reset0 (B.data h) +let length h = length0 (B.data h) +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) = + let dict,data = B.(dict h, data h) in + let module M = (val dict) in + add0 ~hash:M.hash data key info + +let remove (type a) (type b) (type id) (h : (a,b,id) t) (key : a) = + let dict,data = B.(dict h, data h) in + let module M = (val dict) in + remove0 ~hash:M.hash ~eq:M.eq data key + +let removeAll (type a) (type b) (type id) (h : (a,b,id) t) (key : a) = + let dict,data = B.(dict h, data h) in + let module M = (val dict) in + removeAll0 ~hash:M.hash ~eq:M.eq data key + +let findOpt (type a) (type b) (type id) (h : (a,b,id) t) (key : a) = + let dict,data = B.(dict h, data h) in + let module M = (val dict) in + findOpt0 ~hash:M.hash ~eq:M.eq data key + +let findAll (type a) (type b) (type id) (h : (a,b,id) t) (key : a) = + let dict,data = B.(dict h, data h) in + let module M = (val dict) in + findAll0 ~hash:M.hash ~eq:M.eq data key + +let replace (type a) (type b) (type id) (h : (a,b,id) t) (key : a) (info : b) = + let dict,data = B.(dict h, data h) in + let module M = (val dict) in + replace0 ~hash:M.hash ~eq:M.eq data key info + +let mem (type a) (type b) (type id) (h : (a,b,id) t) (key : a) = + let dict,data = B.(dict h, data h) in + let module M = (val dict) in + mem0 ~hash:M.hash ~eq:M.eq data key + +let filterMapInplace h f = + filterMapInplace0 (B.data h) f diff --git a/jscomp/others/bs_HashMultiMap.mli b/jscomp/others/bs_HashMultiMap.mli new file mode 100644 index 00000000000..490c65fc85b --- /dev/null +++ b/jscomp/others/bs_HashMultiMap.mli @@ -0,0 +1,202 @@ + + +type ('a, 'b, 'id) t0 + +type ('a,'b,'id) t = + (('a, 'id) Bs_Hash.t, + ('a,'b,'id) t0) Bs_Bag.bag + +(** The type of hash tables from type ['a] to type ['b]. *) + +val create0 : int -> ('a, 'b, 'id) t0 +val create : ('a,'id) Bs_Hash.t -> int -> ('a,'b,'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, 'b, 'id) t0 -> unit +val clear : ('a, 'b, 'id) t -> unit +(** Empty a hash table. Use [reset] instead of [clear] to shrink the + size of the bucket table to its initial size. *) + +val reset0 : ('a, 'b, 'id) t0 -> unit +val reset : ('a, 'b, 'id) t -> unit +(** Empty a hash table and shrink the size of the bucket table + to its initial size. + @since 4.00.0 *) + + + +val add0 : hash:('a,'id) Bs_Hash.hash -> ('a,'b,'id) t0 -> 'a -> 'b -> unit +val add : ('a, 'b, 'id) t -> 'a -> '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 findOpt0: + hash:('a,'id) Bs_Hash.hash -> + eq:('a,'id) Bs_Hash.eq -> + ('a, 'b, 'id) t0 -> 'a -> 'b option +val findOpt: + ('a, 'b, 'id) t -> 'a -> 'b option +(** [findOpt tbl x] returns the current binding of [x] in [tbl], + *) + +val findAll0 : + hash:('a,'id) Bs_Hash.hash -> + eq:('a,'id) Bs_Hash.eq -> + ('a, 'b, 'id) t0 -> 'a -> 'b list + +val findAll: ('a, 'b, 'id) t -> 'a -> 'b 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 mem0: + hash:('a,'id) Bs_Hash.hash -> + eq:('a,'id) Bs_Hash.eq -> + ('a, 'b, 'id) t0 -> 'a -> bool +val mem: + ('a, 'b, 'id) t -> 'a -> bool +(** [Hashtbl.mem tbl x] checks if [x] is bound in [tbl]. *) + +val remove0: + hash:('a,'id) Bs_Hash.hash -> + eq:('a,'id) Bs_Hash.eq -> + ('a, 'b, 'id) t0 -> 'a -> unit +val remove: +('a, 'b, '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 removeAll0: + hash:('a,'id) Bs_Hash.hash -> + eq:('a,'id) Bs_Hash.eq -> + ('a, 'b, 'id) t0 -> 'a -> unit +val removeAll: +('a, 'b, 'id) t -> 'a -> unit + + +val replace0 : + hash:('a,'id) Bs_Hash.hash -> + eq:('a,'id) Bs_Hash.eq -> + ('a, 'b, 'id) t0 -> 'a -> 'b -> unit +val replace: + ('a, 'b, 'id) t -> 'a -> '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 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]. + + 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 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], + 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 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 +(** [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 logStats0 : ('a, 'b, 'id) t0 -> unit +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 *) + + + + + diff --git a/lib/js/bs.js b/lib/js/bs.js index 3f9aac92023..4964eb3bbee 100644 --- a/lib/js/bs.js +++ b/lib/js/bs.js @@ -21,6 +21,8 @@ var HashSetString = 0; var HashMapString = 0; +var HashMultiMap = 0; + var HashMapInt = 0; var $$Map = 0; @@ -47,6 +49,7 @@ exports.HashSet = HashSet; exports.HashSetInt = HashSetInt; exports.HashSetString = HashSetString; exports.HashMapString = HashMapString; +exports.HashMultiMap = HashMultiMap; exports.HashMapInt = HashMapInt; exports.$$Map = $$Map; exports.$$Set = $$Set; diff --git a/lib/js/bs_HashMultiMap.js b/lib/js/bs_HashMultiMap.js new file mode 100644 index 00000000000..93c35c12c5d --- /dev/null +++ b/lib/js/bs_HashMultiMap.js @@ -0,0 +1,403 @@ +'use strict'; + +var Bs_internalBuckets = require("./bs_internalBuckets.js"); +var Bs_internalBucketsType = require("./bs_internalBucketsType.js"); + +function insert_bucket(hash, h_buckets, ndata_tail, _, _old_bucket) { + while(true) { + var old_bucket = _old_bucket; + if (old_bucket !== undefined) { + var nidx = hash(old_bucket.key) & (h_buckets.length - 1 | 0); + var match = ndata_tail[nidx]; + if (match !== undefined) { + match.next = old_bucket; + } else { + h_buckets[nidx] = old_bucket; + } + ndata_tail[nidx] = old_bucket; + _old_bucket = old_bucket.next; + continue ; + + } else { + return /* () */0; + } + }; +} + +function resize(hash, h) { + var odata = h.buckets; + var osize = odata.length; + var nsize = (osize << 1); + if (nsize >= osize) { + var h_buckets = new Array(nsize); + var ndata_tail = new Array(nsize); + h.buckets = h_buckets; + for(var i = 0 ,i_finish = osize - 1 | 0; i <= i_finish; ++i){ + insert_bucket(hash, h_buckets, ndata_tail, h, odata[i]); + } + for(var i$1 = 0 ,i_finish$1 = nsize - 1 | 0; i$1 <= i_finish$1; ++i$1){ + var match = ndata_tail[i$1]; + if (match !== undefined) { + match.next = Bs_internalBucketsType.emptyOpt; + } + + } + return /* () */0; + } else { + return 0; + } +} + +function add0(hash, h, key, value) { + var h_buckets = h.buckets; + var h_buckets_lenth = h_buckets.length; + var i = hash(key) & (h_buckets_lenth - 1 | 0); + var bucket = { + key: key, + value: value, + next: h_buckets[i] + }; + h_buckets[i] = bucket; + var h_new_size = h.size + 1 | 0; + h.size = h_new_size; + if (h_new_size > (h_buckets_lenth << 1)) { + return resize(hash, h); + } else { + return 0; + } +} + +function remove0(hash, eq, h, key) { + var h_buckets = h.buckets; + var i = hash(key) & (h_buckets.length - 1 | 0); + var eq$1 = eq; + var h$1 = h; + var h_buckets$1 = h_buckets; + var i$1 = i; + var key$1 = key; + var _prec = Bs_internalBucketsType.emptyOpt; + var _buckets = h_buckets[i]; + while(true) { + var buckets = _buckets; + var prec = _prec; + if (buckets !== undefined) { + var cell_next = buckets.next; + if (eq$1(buckets.key, key$1)) { + if (prec !== undefined) { + prec.next = cell_next; + } else { + h_buckets$1[i$1] = cell_next; + } + h$1.size = h$1.size - 1 | 0; + return /* () */0; + } else { + _buckets = cell_next; + _prec = buckets; + continue ; + + } + } else { + return /* () */0; + } + }; +} + +function removeAll0(hash, eq, h, key) { + var h_buckets = h.buckets; + var i = hash(key) & (h_buckets.length - 1 | 0); + var eq$1 = eq; + var h$1 = h; + var h_buckets$1 = h_buckets; + var i$1 = i; + var key$1 = key; + var _prec = Bs_internalBucketsType.emptyOpt; + var _buckets = h_buckets[i]; + while(true) { + var buckets = _buckets; + var prec = _prec; + if (buckets !== undefined) { + var cell_next = buckets.next; + if (eq$1(buckets.key, key$1)) { + if (prec !== undefined) { + prec.next = cell_next; + } else { + h_buckets$1[i$1] = cell_next; + } + h$1.size = h$1.size - 1 | 0; + } + _buckets = cell_next; + _prec = buckets; + continue ; + + } else { + return /* () */0; + } + }; +} + +function findOpt0(hash, eq, h, key) { + var h_buckets = h.buckets; + var nid = hash(key) & (h_buckets.length - 1 | 0); + var match = h_buckets[nid]; + if (match !== undefined) { + if (eq(key, match.key)) { + return /* Some */[match.value]; + } else { + var match$1 = match.next; + if (match$1 !== undefined) { + if (eq(key, match$1.key)) { + return /* Some */[match$1.value]; + } else { + var match$2 = match$1.next; + if (match$2 !== undefined) { + if (eq(key, match$2.key)) { + return /* Some */[match$2.value]; + } else { + var eq$1 = eq; + var key$1 = key; + var _buckets = match$2.next; + while(true) { + var buckets = _buckets; + if (buckets !== undefined) { + if (eq$1(key$1, buckets.key)) { + return /* Some */[buckets.value]; + } else { + _buckets = buckets.next; + continue ; + + } + } else { + return /* None */0; + } + }; + } + } else { + return /* None */0; + } + } + } else { + return /* None */0; + } + } + } else { + return /* None */0; + } +} + +function findAll0(hash, eq, h, key) { + var find_in_bucket = function (_buckets) { + while(true) { + var buckets = _buckets; + if (buckets !== undefined) { + if (eq(buckets.key, key)) { + return /* :: */[ + buckets.value, + find_in_bucket(buckets.next) + ]; + } else { + _buckets = buckets.next; + continue ; + + } + } else { + return /* [] */0; + } + }; + }; + var h_buckets = h.buckets; + var nid = hash(key) & (h_buckets.length - 1 | 0); + return find_in_bucket(h_buckets[nid]); +} + +function replace_bucket(eq, key, info, _buckets) { + while(true) { + var buckets = _buckets; + if (buckets !== undefined) { + if (eq(buckets.key, key)) { + buckets.key = key; + buckets.value = info; + return /* false */0; + } else { + _buckets = buckets.next; + continue ; + + } + } else { + return /* true */1; + } + }; +} + +function replace0(hash, eq, h, key, info) { + var h_buckets = h.buckets; + var i = hash(key) & (h_buckets.length - 1 | 0); + var l = h_buckets[i]; + if (replace_bucket(eq, key, info, l)) { + h_buckets[i] = { + key: key, + value: info, + next: l + }; + h.size = h.size + 1 | 0; + if (h.size > (h.buckets.length << 1)) { + return resize(hash, h); + } else { + return 0; + } + } else { + return 0; + } +} + +function mem0(hash, eq, h, key) { + var h_buckets = h.buckets; + var nid = hash(key) & (h_buckets.length - 1 | 0); + var bucket = h_buckets[nid]; + if (bucket !== undefined) { + var eq$1 = eq; + var key$1 = key; + var _cell = bucket; + while(true) { + var cell = _cell; + if (eq$1(cell.key, key$1)) { + return /* true */1; + } else { + var match = cell.next; + if (match !== undefined) { + _cell = match; + continue ; + + } else { + return /* false */0; + } + } + }; + } else { + return /* false */0; + } +} + +function create(dict, initialize_size) { + return { + dict: dict, + data: Bs_internalBucketsType.create0(initialize_size) + }; +} + +function clear(h) { + return Bs_internalBucketsType.clear0(h.data); +} + +function reset(h) { + return Bs_internalBucketsType.reset0(h.data); +} + +function length(h) { + return h.data.size; +} + +function iter(h, f) { + return Bs_internalBuckets.iter0(h.data, f); +} + +function fold(h, init, f) { + return Bs_internalBuckets.fold0(h.data, init, f); +} + +function logStats(h) { + return Bs_internalBuckets.logStats0(h.data); +} + +function add(h, key, info) { + var dict = h.dict; + var data = h.data; + return add0(dict[/* hash */0], data, key, info); +} + +function remove(h, key) { + var dict = h.dict; + var data = h.data; + return remove0(dict[/* hash */0], dict[/* eq */1], data, key); +} + +function removeAll(h, key) { + var dict = h.dict; + var data = h.data; + return removeAll0(dict[/* hash */0], dict[/* eq */1], data, key); +} + +function findOpt(h, key) { + var dict = h.dict; + var data = h.data; + return findOpt0(dict[/* hash */0], dict[/* eq */1], data, key); +} + +function findAll(h, key) { + var dict = h.dict; + var data = h.data; + return findAll0(dict[/* hash */0], dict[/* eq */1], data, key); +} + +function replace(h, key, info) { + var dict = h.dict; + var data = h.data; + return replace0(dict[/* hash */0], dict[/* eq */1], data, key, info); +} + +function mem(h, key) { + var dict = h.dict; + var data = h.data; + return mem0(dict[/* hash */0], dict[/* eq */1], data, key); +} + +function filterMapInplace(h, f) { + return Bs_internalBuckets.filterMapInplace0(h.data, f); +} + +var create0 = Bs_internalBucketsType.create0; + +var clear0 = Bs_internalBucketsType.clear0; + +var reset0 = Bs_internalBucketsType.reset0; + +var iter0 = Bs_internalBuckets.iter0; + +var fold0 = Bs_internalBuckets.fold0; + +var filterMapInplace0 = Bs_internalBuckets.filterMapInplace0; + +var length0 = Bs_internalBucketsType.length0; + +var logStats0 = Bs_internalBuckets.logStats0; + +exports.create0 = create0; +exports.create = create; +exports.clear0 = clear0; +exports.clear = clear; +exports.reset0 = reset0; +exports.reset = reset; +exports.add0 = add0; +exports.add = add; +exports.findOpt0 = findOpt0; +exports.findOpt = findOpt; +exports.findAll0 = findAll0; +exports.findAll = findAll; +exports.mem0 = mem0; +exports.mem = mem; +exports.remove0 = remove0; +exports.remove = remove; +exports.removeAll0 = removeAll0; +exports.removeAll = removeAll; +exports.replace0 = replace0; +exports.replace = replace; +exports.iter0 = iter0; +exports.iter = iter; +exports.fold0 = fold0; +exports.fold = fold; +exports.filterMapInplace0 = filterMapInplace0; +exports.filterMapInplace = filterMapInplace; +exports.length0 = length0; +exports.length = length; +exports.logStats0 = logStats0; +exports.logStats = logStats; +/* No side effect */