diff --git a/jscomp/index.html b/jscomp/index.html
index 5c99e4ee34..e1d0cc2038 100644
--- a/jscomp/index.html
+++ b/jscomp/index.html
@@ -10,7 +10,7 @@
diff --git a/jscomp/js_config.ml b/jscomp/js_config.ml
index 4a3e426a2c..97f0cb5ef7 100644
--- a/jscomp/js_config.ml
+++ b/jscomp/js_config.ml
@@ -163,7 +163,7 @@ let format = "Caml_format"
let string = "Caml_string"
let float = "Caml_float"
-
+let hash = "Caml_hash"
let oo = "Caml_oo"
let curry = "Caml_curry"
let internalMod = "Caml_internalMod"
diff --git a/jscomp/js_config.mli b/jscomp/js_config.mli
index 5850edf4e2..64113cdbfa 100644
--- a/jscomp/js_config.mli
+++ b/jscomp/js_config.mli
@@ -64,3 +64,4 @@ val bigarray : string
val unix : string
val int64 : string
val md5 : string
+val hash : string
diff --git a/jscomp/lam_dispatch_primitive.ml b/jscomp/lam_dispatch_primitive.ml
index dc88c93939..e15e4b4122 100644
--- a/jscomp/lam_dispatch_primitive.ml
+++ b/jscomp/lam_dispatch_primitive.ml
@@ -791,6 +791,9 @@ let query (prim : Lam_compile_env.primitive_description)
end
| "caml_md5_string"
-> E.runtime_call Js_config.md5 prim.prim_name args
+ | "caml_hash"
+ -> E.runtime_call Js_config.hash prim.prim_name args
+
| "caml_output_value_to_buffer"
| "caml_marshal_data_size"
| "caml_input_value_from_string"
@@ -799,7 +802,7 @@ let query (prim : Lam_compile_env.primitive_description)
| "caml_output_value_to_string"
| "caml_md5_chan"
- | "caml_hash"
+
| "caml_hash_univ_param"
| "caml_weak_set"
| "caml_weak_create"
diff --git a/jscomp/runtime/.depend b/jscomp/runtime/.depend
index e07a5ad26f..70b3df2c7e 100644
--- a/jscomp/runtime/.depend
+++ b/jscomp/runtime/.depend
@@ -3,6 +3,7 @@ caml_bigarray.cmi :
caml_builtin_exceptions.cmi :
caml_float.cmi :
caml_format.cmi :
+caml_hash.cmi :
caml_int64.cmi :
caml_lexer.cmi :
caml_md5.cmi :
@@ -10,6 +11,7 @@ caml_obj.cmi :
caml_oo.cmi :
caml_parser.cmi :
caml_primitive.cmi :
+caml_queue.cmi :
caml_string.cmi :
caml_sys.cmi :
caml_utils.cmi :
@@ -25,6 +27,8 @@ caml_float.cmo : typed_array.cmo js.cmo caml_float.cmi
caml_float.cmx : typed_array.cmx js.cmx caml_float.cmi
caml_format.cmo : js.cmo caml_utils.cmi caml_format.cmi
caml_format.cmx : js.cmx caml_utils.cmx caml_format.cmi
+caml_hash.cmo : js.cmo caml_queue.cmi caml_hash.cmi
+caml_hash.cmx : js.cmx caml_queue.cmx caml_hash.cmi
caml_int64.cmo : typed_array.cmo js.cmo caml_utils.cmi caml_int64.cmi
caml_int64.cmx : typed_array.cmx js.cmx caml_utils.cmx caml_int64.cmi
caml_io.cmo : js.cmo
@@ -41,6 +45,8 @@ caml_parser.cmo : caml_parser.cmi
caml_parser.cmx : caml_parser.cmi
caml_primitive.cmo : caml_primitive.cmi
caml_primitive.cmx : caml_primitive.cmi
+caml_queue.cmo : caml_queue.cmi
+caml_queue.cmx : caml_queue.cmi
caml_string.cmo : js.cmo caml_string.cmi
caml_string.cmx : js.cmx caml_string.cmi
caml_sys.cmo : js.cmo caml_sys.cmi
@@ -67,6 +73,8 @@ caml_float.cmo : typed_array.cmo js.cmo caml_float.cmi
caml_float.cmj : typed_array.cmj js.cmj caml_float.cmi
caml_format.cmo : js.cmo caml_utils.cmi caml_format.cmi
caml_format.cmj : js.cmj caml_utils.cmj caml_format.cmi
+caml_hash.cmo : js.cmo caml_queue.cmi caml_hash.cmi
+caml_hash.cmj : js.cmj caml_queue.cmj caml_hash.cmi
caml_int64.cmo : typed_array.cmo js.cmo caml_utils.cmi caml_int64.cmi
caml_int64.cmj : typed_array.cmj js.cmj caml_utils.cmj caml_int64.cmi
caml_io.cmo : js.cmo
@@ -83,6 +91,8 @@ caml_parser.cmo : caml_parser.cmi
caml_parser.cmj : caml_parser.cmi
caml_primitive.cmo : caml_primitive.cmi
caml_primitive.cmj : caml_primitive.cmi
+caml_queue.cmo : caml_queue.cmi
+caml_queue.cmj : caml_queue.cmi
caml_string.cmo : js.cmo caml_string.cmi
caml_string.cmj : js.cmj caml_string.cmi
caml_sys.cmo : js.cmo caml_sys.cmi
diff --git a/jscomp/runtime/caml_hash.js b/jscomp/runtime/caml_hash.js
new file mode 100644
index 0000000000..d2f78bc11a
--- /dev/null
+++ b/jscomp/runtime/caml_hash.js
@@ -0,0 +1,111 @@
+// Generated CODE, PLEASE EDIT WITH CARE
+'use strict';
+
+var Caml_builtin_exceptions = require("./caml_builtin_exceptions");
+var Caml_queue = require("./caml_queue");
+var Caml_primitive = require("./caml_primitive");
+
+function rotl32(x, n) {
+ return (x << n) | (x >>> (32 - n | 0));
+}
+
+function mix(h, d) {
+ var d$1 = d;
+ d$1 = Caml_primitive.imul(d$1, 3432918353);
+ d$1 = rotl32(d$1, 15);
+ d$1 = Caml_primitive.imul(d$1, 461845907);
+ var h$1 = h ^ d$1;
+ h$1 = rotl32(h$1, 13);
+ return (h$1 + (h$1 << 2) | 0) + 3864292196 | 0;
+}
+
+function final_mix(h) {
+ var h$1 = h ^ (h >>> 16);
+ h$1 = Caml_primitive.imul(h$1, 2246822507);
+ h$1 = h$1 ^ (h$1 >>> 13);
+ h$1 = Caml_primitive.imul(h$1, 3266489909);
+ return h$1 ^ (h$1 >>> 16);
+}
+
+function caml_hash_mix_string(h, s) {
+ var len = s.length;
+ var block = (len / 4 | 0) - 1 | 0;
+ var hash = h;
+ for(var i = 0; i<= block; ++i){
+ var j = (i << 2);
+ var w = s.charCodeAt(j) | (s.charCodeAt(j + 1 | 0) << 8) | (s.charCodeAt(j + 2 | 0) << 16) | (s.charCodeAt(j + 3 | 0) << 24);
+ hash = mix(hash, w);
+ }
+ var modulo = len & 3;
+ if (modulo !== 0) {
+ var w$1 = modulo === 3 ? (s.charCodeAt(len - 1 | 0) << 16) | (s.charCodeAt(len - 2 | 0) << 8) | s.charCodeAt(len - 3 | 0) : (
+ modulo === 2 ? (s.charCodeAt(len - 1 | 0) << 8) | s.charCodeAt(len - 2 | 0) : s.charCodeAt(len - 1 | 0)
+ );
+ hash = mix(hash, w$1);
+ }
+ hash = hash ^ len;
+ return hash;
+}
+
+function caml_hash(count, _, seed, obj) {
+ var hash = seed;
+ if (typeof obj === "number") {
+ var u = obj | 0;
+ hash = mix(hash, (u + u | 0) + 1 | 0);
+ return final_mix(hash);
+ }
+ else if (typeof obj === "string") {
+ hash = caml_hash_mix_string(hash, obj);
+ return final_mix(hash);
+ }
+ else {
+ var queue = /* record */[
+ 0,
+ /* None */0
+ ];
+ var num = count;
+ Caml_queue.push(obj, queue);
+ num = num - 1 | 0;
+ while(queue[/* length */0] !== 0 && num > 0) {
+ var obj$1 = Caml_queue.unsafe_pop(queue);
+ if (typeof obj$1 === "number") {
+ hash = mix(hash, obj$1 | 0);
+ num = num - 1 | 0;
+ }
+ else if (typeof obj$1 === "string") {
+ hash = caml_hash_mix_string(hash, obj$1);
+ num = num - 1 | 0;
+ }
+ else if (typeof obj$1 !== "boolean") {
+ if (typeof obj$1 !== "undefined") {
+ if (typeof obj$1 === "symbol") {
+ throw [
+ Caml_builtin_exceptions.assert_failure,
+ [
+ "caml_hash.ml",
+ 124,
+ 8
+ ]
+ ];
+ }
+ else if (typeof obj$1 !== "function") {
+ var tag = obj$1.tag | 0;
+ hash = mix(hash, tag);
+ var v = obj$1.length - 1 | 0;
+ var block = v < num ? v : num;
+ for(var i = 0; i<= block; ++i){
+ Caml_queue.push(obj$1[i], queue);
+ }
+ }
+
+ }
+
+ }
+
+ };
+ return final_mix(hash);
+ }
+}
+
+exports.caml_hash = caml_hash;
+/* No side effect */
diff --git a/jscomp/runtime/caml_hash.ml b/jscomp/runtime/caml_hash.ml
new file mode 100644
index 0000000000..abdf4a44e8
--- /dev/null
+++ b/jscomp/runtime/caml_hash.ml
@@ -0,0 +1,137 @@
+(* BuckleScript compiler
+ * Copyright (C) 2015-2016 Bloomberg Finance L.P.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, with linking exception;
+ * either version 2.1 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *)
+
+(* Author: Hongbo Zhang *)
+
+let (<< ) = Nativeint.shift_left
+let (>>>) = Nativeint.shift_right_logical
+let (|~) = Nativeint.logor
+let (^) = Nativeint.logxor
+
+external ( *~ ) : nativeint -> nativeint -> nativeint = "caml_int32_mul"
+external ( +~ ) : nativeint -> nativeint -> nativeint = "caml_int32_add"
+
+
+
+let rotl32 (x : nativeint) n =
+ (x << n) |~ (x >>> (32 - n))
+
+
+let mix h d =
+ let d = ref d in
+ d := !d *~ 0xcc9e2d51n ;
+ d := rotl32 !d 15 ;
+ d := !d *~ 0x1b873593n ;
+ let h = ref (h ^ !d) in
+ h := rotl32 !h 13 ;
+ !h +~ (!h << 2) +~ 0xe6546b64n
+
+let final_mix h =
+ let h = ref (h ^ (h >>> 16)) in
+ h := !h *~ 0x85ebca6bn ;
+ h := !h ^ (!h >>> 13);
+ h := !h *~ 0xc2b2ae35n ;
+ !h ^ (!h >>> 16)
+ (* Nativeint.logand (!h ^ (!h >>> 16)) 0x3FFFFFFFn *)
+
+let caml_hash_mix_string h s =
+ let len = String.length s in
+ let block = len / 4 - 1 in
+ let hash = ref h in
+ for i = 0 to block do
+ let j = 4 * i in
+ let w =
+ Char.code s.[j] lor
+ (Char.code s.[j+1] lsl 8) lor
+ (Char.code s.[j+2] lsl 16) lor
+ (Char.code s.[j+3] lsl 24)
+ in
+ hash := mix !hash (Nativeint.of_int w)
+ done ;
+ let modulo = len land 0b11 in
+ if modulo <> 0 then
+ begin
+ let w =
+ if modulo = 3 then
+ (Char.code s.[len - 1] lsl 16) lor
+ (Char.code s.[len - 2] lsl 8) lor
+ (Char.code s.[len - 3])
+ else if modulo = 2 then
+ (Char.code s.[len -1] lsl 8) lor
+ Char.code s.[len -2]
+ else Char.code s.[len - 1]
+ in
+ hash := mix !hash (Nativeint.of_int w)
+ end;
+ hash := !hash ^ (Nativeint.of_int len) ;
+ !hash
+
+
+let caml_hash count _limit seed obj =
+ let hash = ref seed in
+ if Js.typeof obj = "number" then
+ begin
+ let u = (Nativeint.of_float (Obj.magic obj)) in
+ hash := mix !hash (u +~ u +~ 1n) ;
+ final_mix !hash
+ end
+ else if Js.typeof obj = "string" then
+ begin
+ hash := caml_hash_mix_string !hash (Obj.magic obj : string);
+ final_mix !hash
+ end
+ (* TODO: hash [null] [undefined] as well *)
+ else
+
+ let queue = Caml_queue.create () in
+ let num = ref count in
+ let () =
+ Caml_queue.push obj queue;
+ decr num
+ in
+ while not @@ Caml_queue.is_empty queue && !num > 0 do
+ let obj = Caml_queue.unsafe_pop queue in
+ if Js.typeof obj = "number" then
+ begin
+ hash := mix !hash (Nativeint.of_float (Obj.magic obj));
+ decr num ;
+ end
+ else if Js.typeof obj = "string" then
+ begin
+ hash := caml_hash_mix_string !hash (Obj.magic obj : string);
+ decr num
+ end
+ else if Js.typeof obj = "boolean" then
+ ()
+ else if Js.typeof obj = "undefined" then
+ ()
+ else if Js.typeof obj = "symbol" then
+ assert false (* TODO *)
+ else if Js.typeof obj = "function" then
+ ()
+ else
+ let tag = Obj.tag obj in
+ hash := mix !hash (Nativeint.of_int tag) ;
+ let block =
+ let v = Obj.size obj - 1 in if v < !num then v else !num in
+ for i = 0 to block do
+ Caml_queue.push (Obj.field obj i ) queue
+ done
+ done;
+ final_mix !hash
+
diff --git a/jscomp/runtime/caml_hash.mli b/jscomp/runtime/caml_hash.mli
new file mode 100644
index 0000000000..039d77c979
--- /dev/null
+++ b/jscomp/runtime/caml_hash.mli
@@ -0,0 +1,21 @@
+(* BuckleScript compiler
+ * Copyright (C) 2015-2016 Bloomberg Finance L.P.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, with linking exception;
+ * either version 2.1 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *)
+
+(* Author: Hongbo Zhang *)
+
+val caml_hash : int -> 'a -> nativeint -> Obj.t -> nativeint
diff --git a/jscomp/runtime/caml_primitive.js b/jscomp/runtime/caml_primitive.js
index 9ded5b6756..f0cac019b2 100644
--- a/jscomp/runtime/caml_primitive.js
+++ b/jscomp/runtime/caml_primitive.js
@@ -11,44 +11,6 @@ function caml_int32_bswap(x) {
return ((x & 255) << 24) | ((x & 65280) << 8) | ((x & 16711680) >>> 8) | ((x & 4278190080) >>> 24);
}
-
-
-/**
- * Maximum value of #goog.string.hashCode, exclusive. 2^32.
- * @type {number}
- * @private
- */
-var HASHCODE_MAX_ = 0x100000000;
-/**
- * String hash function similar to java.lang.String.hashCode().
- * The hash code for a string is computed as
- * s[0] * 31 ^ (n - 1) + s[1] * 31 ^ (n - 2) + ... + s[n - 1],
- * where s[i] is the ith character of the string and n is the length of
- * the string. We mod the result to make it between 0 (inclusive) and 2^32
- * (exclusive).
- * @param {string} str A string.
- * @return {number} Hash value for {@code str}, between 0 (inclusive) and 2^32
- * (exclusive). The empty string returns 0.
- */
-function $$hashCode(str) {
- var result = 0;
- for (var i = 0; i < str.length; ++i) {
- result = 31 * result + str.charCodeAt(i);
- // Normalize to 4 byte range, 0 ... 2^32.
- result %= HASHCODE_MAX_;
- }
- return result;
-}
-;
-
-// Poor man's hash
-// Updated later
-function $$caml_hash(count, limit, seed, o) {
- return $$hashCode(JSON.stringify(o));
-}
-
-;
-
function caml_sys_getcwd() {
return "/";
}
@@ -73,14 +35,9 @@ function caml_string_get32(s, i) {
return ((s.charCodeAt(i) + (s.charCodeAt(i + 1 | 0) << 8) | 0) + (s.charCodeAt(i + 2 | 0) << 16) | 0) + (s.charCodeAt(i + 3 | 0) << 24) | 0;
}
-function caml_hash(prim, prim$1, prim$2, prim$3) {
- return $$caml_hash(prim, prim$1, prim$2, prim$3);
-}
-
var caml_nativeint_bswap = caml_int32_bswap;
exports.caml_sys_getcwd = caml_sys_getcwd;
-exports.caml_hash = caml_hash;
exports.caml_bswap16 = caml_bswap16;
exports.caml_int32_bswap = caml_int32_bswap;
exports.caml_nativeint_bswap = caml_nativeint_bswap;
@@ -88,4 +45,4 @@ exports.caml_convert_raw_backtrace_slot = caml_convert_raw_backtrace_slot;
exports.imul = imul;
exports.caml_string_get16 = caml_string_get16;
exports.caml_string_get32 = caml_string_get32;
-/* Not a pure module */
+/* imul Not a pure module */
diff --git a/jscomp/runtime/caml_primitive.ml b/jscomp/runtime/caml_primitive.ml
index 03876612b0..4e66c677f3 100644
--- a/jscomp/runtime/caml_primitive.ml
+++ b/jscomp/runtime/caml_primitive.ml
@@ -30,46 +30,6 @@ let caml_int32_bswap (x : nativeint) =
(logor (shift_right_logical (logand x 0x00FF0000n) 8)
(shift_right_logical (logand x 0xFF000000n) 24)))
-[%%bs.raw{|
-
-/**
- * Maximum value of #goog.string.hashCode, exclusive. 2^32.
- * @type {number}
- * @private
- */
-var HASHCODE_MAX_ = 0x100000000;
-/**
- * String hash function similar to java.lang.String.hashCode().
- * The hash code for a string is computed as
- * s[0] * 31 ^ (n - 1) + s[1] * 31 ^ (n - 2) + ... + s[n - 1],
- * where s[i] is the ith character of the string and n is the length of
- * the string. We mod the result to make it between 0 (inclusive) and 2^32
- * (exclusive).
- * @param {string} str A string.
- * @return {number} Hash value for {@code str}, between 0 (inclusive) and 2^32
- * (exclusive). The empty string returns 0.
- */
-function $$hashCode(str) {
- var result = 0;
- for (var i = 0; i < str.length; ++i) {
- result = 31 * result + str.charCodeAt(i);
- // Normalize to 4 byte range, 0 ... 2^32.
- result %= HASHCODE_MAX_;
- }
- return result;
-}
-;
-
-// Poor man's hash
-// Updated later
-function $$caml_hash(count, limit, seed, o) {
- return $$hashCode(JSON.stringify(o));
-}
-|}]
-
-
-external caml_hash : int -> int -> int -> 'a -> int = "$$caml_hash"
- [@@bs.call ] [@@bs.local]
let caml_nativeint_bswap = caml_int32_bswap
diff --git a/jscomp/runtime/caml_primitive.mli b/jscomp/runtime/caml_primitive.mli
index b973de634a..70d9d86561 100644
--- a/jscomp/runtime/caml_primitive.mli
+++ b/jscomp/runtime/caml_primitive.mli
@@ -19,7 +19,7 @@
(* Author: Hongbo Zhang *)
val caml_sys_getcwd : unit -> string
-val caml_hash : int -> int -> int -> 'a -> int
+
val caml_bswap16 : nativeint -> nativeint
val caml_int32_bswap : nativeint -> nativeint
diff --git a/jscomp/runtime/caml_queue.js b/jscomp/runtime/caml_queue.js
new file mode 100644
index 0000000000..fd21fc10cf
--- /dev/null
+++ b/jscomp/runtime/caml_queue.js
@@ -0,0 +1,56 @@
+// Generated CODE, PLEASE EDIT WITH CARE
+'use strict';
+
+
+function create() {
+ return /* record */[
+ 0,
+ /* None */0
+ ];
+}
+
+function push(x, q) {
+ if (q[/* length */0]) {
+ var tail = q[/* tail */1];
+ var head = tail[/* next */1];
+ var cell = /* record */[
+ x,
+ head
+ ];
+ q[/* length */0] = q[/* length */0] + 1 | 0;
+ tail[/* next */1] = cell;
+ q[/* tail */1] = cell;
+ return /* () */0;
+ }
+ else {
+ var cell$1 = [];
+ cell$1[0] = x;
+ cell$1[1] = cell$1;
+ q[/* length */0] = 1;
+ q[/* tail */1] = cell$1;
+ return /* () */0;
+ }
+}
+
+function unsafe_pop(q) {
+ q[/* length */0] = q[/* length */0] - 1 | 0;
+ var tail = q[/* tail */1];
+ var head = tail[/* next */1];
+ if (head === tail) {
+ q[/* tail */1] = /* None */0;
+ }
+ else {
+ tail[/* next */1] = head[/* next */1];
+ }
+ return head[/* content */0];
+}
+
+function is_empty(q) {
+ return +(q[/* length */0] === 0);
+}
+
+exports.create = create;
+exports.push = push;
+exports.unsafe_pop = unsafe_pop;
+exports.is_empty = is_empty;
+/* No side effect */
diff --git a/jscomp/runtime/caml_queue.ml b/jscomp/runtime/caml_queue.ml
new file mode 100644
index 0000000000..4759cd582f
--- /dev/null
+++ b/jscomp/runtime/caml_queue.ml
@@ -0,0 +1,83 @@
+(***********************************************************************)
+(* *)
+(* OCaml *)
+(* *)
+(* Francois Pottier, projet Cristal, INRIA Rocquencourt *)
+(* *)
+(* Copyright 2002 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 Hongbo Zhang for Js backend and minimal code size *)
+
+(* OCaml currently does not allow the components of a sum type to be
+ mutable. Yet, for optimal space efficiency, we must have cons cells
+ whose [next] field is mutable. This leads us to define a type of
+ cyclic lists, so as to eliminate the [Nil] case and the sum
+ type. *)
+
+type 'a cell = {
+ content: 'a;
+ mutable next: 'a cell
+ }
+
+(* A queue is a reference to either nothing or some cell of a cyclic
+ list. By convention, that cell is to be viewed as the last cell in
+ the queue. The first cell in the queue is then found in constant
+ time: it is the next cell in the cyclic list. The queue's length is
+ also recorded, so as to make [length] a constant-time operation.
+
+ The [tail] field should really be of type ['a cell option], but
+ then it would be [None] when [length] is 0 and [Some] otherwise,
+ leading to redundant memory allocation and accesses. We avoid this
+ overhead by filling [tail] with a dummy value when [length] is 0.
+ Of course, this requires bending the type system's arm slightly,
+ because it does not have dependent sums. *)
+
+type 'a t = {
+ mutable length: int;
+ mutable tail: 'a cell
+ }
+
+
+let create () = {
+ length = 0;
+ tail = Obj.magic None
+}
+
+
+let push x q =
+ if q.length = 0 then
+ let rec cell = {
+ content = x;
+ next = cell
+ } in
+ q.length <- 1;
+ q.tail <- cell
+ else
+ let tail = q.tail in
+ let head = tail.next in
+ let cell = {
+ content = x;
+ next = head
+ } in
+ q.length <- q.length + 1;
+ tail.next <- cell;
+ q.tail <- cell
+
+let unsafe_pop (q : 'a t) : 'a =
+ q.length <- q.length - 1;
+ let tail = q.tail in
+ let head = tail.next in
+ if head == tail then
+ q.tail <- Obj.magic None
+ else
+ tail.next <- head.next;
+ head.content
+
+
+let is_empty q =
+ q.length = 0
diff --git a/jscomp/runtime/caml_queue.mli b/jscomp/runtime/caml_queue.mli
new file mode 100644
index 0000000000..1ec90a9cac
--- /dev/null
+++ b/jscomp/runtime/caml_queue.mli
@@ -0,0 +1,29 @@
+(* BuckleScript compiler
+ * Copyright (C) 2015-2016 Bloomberg Finance L.P.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, with linking exception;
+ * either version 2.1 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *)
+
+(* Author: Hongbo Zhang *)
+
+type 'a t
+
+val create : unit -> 'a t
+
+val push : 'a -> 'a t -> unit
+
+val unsafe_pop : 'a t -> 'a
+
+val is_empty : 'a t -> bool
diff --git a/jscomp/runtime/runtime.mllib b/jscomp/runtime/runtime.mllib
index 0d1a478626..0deb9a5aa1 100644
--- a/jscomp/runtime/runtime.mllib
+++ b/jscomp/runtime/runtime.mllib
@@ -15,7 +15,8 @@ caml_primitive
caml_format
caml_bigarray
caml_md5
-
+caml_queue
+caml_hash
typed_array
js
fn
diff --git a/jscomp/stdlib/hashtbl.js b/jscomp/stdlib/hashtbl.js
index e943cb7889..64af90df24 100644
--- a/jscomp/stdlib/hashtbl.js
+++ b/jscomp/stdlib/hashtbl.js
@@ -13,18 +13,19 @@ var Caml_array = require("../runtime/caml_array");
var $$Array = require("./array");
var Caml_curry = require("../runtime/caml_curry");
var Caml_string = require("../runtime/caml_string");
+var Caml_hash = require("../runtime/caml_hash");
var Random = require("./random");
function hash(x) {
- return Caml_primitive.caml_hash(10, 100, 0, x);
+ return Caml_hash.caml_hash(10, 100, 0, x);
}
function hash_param(n1, n2, x) {
- return Caml_primitive.caml_hash(n1, n2, 0, x);
+ return Caml_hash.caml_hash(n1, n2, 0, x);
}
function seeded_hash(seed, x) {
- return Caml_primitive.caml_hash(10, 100, seed, x);
+ return Caml_hash.caml_hash(10, 100, seed, x);
}
var params;
@@ -165,7 +166,7 @@ function resize(indexfun, h) {
function key_index(h, key) {
if (h.length >= 3) {
- return Caml_primitive.caml_hash(10, 100, h[/* seed */2], key) & (h[/* data */1].length - 1 | 0);
+ return Caml_hash.caml_hash(10, 100, h[/* seed */2], key) & (h[/* data */1].length - 1 | 0);
}
else {
return Caml_primitive.caml_hash_univ_param(10, 100, key) % h[/* data */1].length;
@@ -865,7 +866,7 @@ function Make(H) {
];
}
-var seeded_hash_param = Caml_primitive.caml_hash
+var seeded_hash_param = Caml_hash.caml_hash
exports.create = create;
exports.clear = clear;
diff --git a/jscomp/test/.depend b/jscomp/test/.depend
index 91e7aaa67c..44cdc443e0 100644
--- a/jscomp/test/.depend
+++ b/jscomp/test/.depend
@@ -186,6 +186,10 @@ hamming_test.cmo : ../stdlib/printf.cmi mt.cmi ../stdlib/lazy.cmi \
../stdlib/int64.cmi ../stdlib/buffer.cmi
hamming_test.cmx : ../stdlib/printf.cmx mt.cmx ../stdlib/lazy.cmx \
../stdlib/int64.cmx ../stdlib/buffer.cmx
+hash_test.cmo : ../stdlib/string.cmi mt_global.cmi mt.cmi \
+ ../stdlib/hashtbl.cmi ../stdlib/char.cmi ../stdlib/array.cmi
+hash_test.cmx : ../stdlib/string.cmx mt_global.cmx mt.cmx \
+ ../stdlib/hashtbl.cmx ../stdlib/char.cmx ../stdlib/array.cmx
hashtbl_test.cmo : mt.cmi ../stdlib/list.cmi ../stdlib/hashtbl.cmi \
../stdlib/array.cmi
hashtbl_test.cmx : mt.cmx ../stdlib/list.cmx ../stdlib/hashtbl.cmx \
@@ -728,6 +732,10 @@ hamming_test.cmo : ../stdlib/printf.cmi mt.cmi ../stdlib/lazy.cmi \
../stdlib/int64.cmi ../stdlib/buffer.cmi
hamming_test.cmj : ../stdlib/printf.cmj mt.cmj ../stdlib/lazy.cmj \
../stdlib/int64.cmj ../stdlib/buffer.cmj
+hash_test.cmo : ../stdlib/string.cmi mt_global.cmi mt.cmi \
+ ../stdlib/hashtbl.cmi ../stdlib/char.cmi ../stdlib/array.cmi
+hash_test.cmj : ../stdlib/string.cmj mt_global.cmj mt.cmj \
+ ../stdlib/hashtbl.cmj ../stdlib/char.cmj ../stdlib/array.cmj
hashtbl_test.cmo : mt.cmi ../stdlib/list.cmi ../stdlib/hashtbl.cmi \
../stdlib/array.cmi
hashtbl_test.cmj : mt.cmj ../stdlib/list.cmj ../stdlib/hashtbl.cmj \
diff --git a/jscomp/test/hash_test.js b/jscomp/test/hash_test.js
new file mode 100644
index 0000000000..24d2ec9143
--- /dev/null
+++ b/jscomp/test/hash_test.js
@@ -0,0 +1,92 @@
+// Generated CODE, PLEASE EDIT WITH CARE
+'use strict';
+
+var Bytes = require("../stdlib/bytes");
+var Hashtbl = require("../stdlib/hashtbl");
+var Mt = require("./mt");
+var Char = require("../stdlib/char");
+var Mt_global = require("./mt_global");
+var $$Array = require("../stdlib/array");
+var Caml_string = require("../runtime/caml_string");
+
+var suites = [/* [] */0];
+
+var test_id = [0];
+
+function eq(f) {
+ return function (param, param$1) {
+ return Mt_global.collect_eq(test_id, suites, f, param, param$1);
+ };
+}
+
+var test_strings = $$Array.init(32, function (i) {
+ var c = Char.chr(i);
+ return Caml_string.bytes_to_string(Bytes.make(i, c));
+ });
+
+var test_strings_hash_results = /* array */[
+ 0,
+ 904391063,
+ 889600889,
+ 929588010,
+ 596566298,
+ 365199070,
+ 448044845,
+ 311625091,
+ 681445541,
+ 634941451,
+ 82108334,
+ 17482990,
+ 491949228,
+ 696194769,
+ 711728152,
+ 594966620,
+ 820561748,
+ 958901713,
+ 102794744,
+ 378848504,
+ 349314368,
+ 114167579,
+ 71240932,
+ 110067399,
+ 280623927,
+ 323523937,
+ 310683234,
+ 178511779,
+ 585018975,
+ 544388424,
+ 1043872806,
+ 831138595
+];
+
+function normalize(x) {
+ return x & 1073741823;
+}
+
+var param = $$Array.map(function (x) {
+ return Hashtbl.hash(x) & 1073741823;
+ }, test_strings);
+
+Mt_global.collect_eq(test_id, suites, 'File "hash_test.ml", line 17, characters 5-12', param, test_strings_hash_results);
+
+var param$1 = Hashtbl.hash(0) & 1073741823;
+
+Mt_global.collect_eq(test_id, suites, 'File "hash_test.ml", line 23, characters 5-12', param$1, 129913994);
+
+var param$2 = Hashtbl.hash("x") & 1073741823;
+
+Mt_global.collect_eq(test_id, suites, 'File "hash_test.ml", line 26, characters 5-12', param$2, 780510073);
+
+var param$3 = Hashtbl.hash("xy") & 1073741823;
+
+Mt_global.collect_eq(test_id, suites, 'File "hash_test.ml", line 29, characters 5-12', param$3, 194127723);
+
+Mt.from_pair_suites("hash_test.ml", suites[0]);
+
+exports.suites = suites;
+exports.test_id = test_id;
+exports.eq = eq;
+exports.test_strings = test_strings;
+exports.test_strings_hash_results = test_strings_hash_results;
+exports.normalize = normalize;
+/* test_strings Not a pure module */
diff --git a/jscomp/test/hash_test.ml b/jscomp/test/hash_test.ml
new file mode 100644
index 0000000000..45cf2193e0
--- /dev/null
+++ b/jscomp/test/hash_test.ml
@@ -0,0 +1,32 @@
+let suites : Mt.pair_suites ref = ref []
+let test_id = ref 0
+let eq f = Mt_global.collect_eq test_id suites f
+
+let test_strings =
+ Array.init 32 (fun i -> String.make i (Char.chr i))
+
+let test_strings_hash_results =
+ [|0; 904391063; 889600889; 929588010; 596566298; 365199070; 448044845;
+ 311625091; 681445541; 634941451; 82108334; 17482990; 491949228; 696194769;
+ 711728152; 594966620; 820561748; 958901713; 102794744; 378848504;
+ 349314368; 114167579; 71240932; 110067399; 280623927; 323523937; 310683234;
+ 178511779; 585018975; 544388424; 1043872806; 831138595|]
+
+let normalize x = x land 0x3FFFFFFF
+let () =
+ eq __LOC__
+ (test_strings |> Array.map (fun x -> normalize (Hashtbl.hash x) ))
+ test_strings_hash_results
+
+
+let () =
+ eq __LOC__ (Hashtbl.hash 0 |> normalize) 129913994
+
+let () =
+ eq __LOC__ (Hashtbl.hash "x" |> normalize) 780510073
+
+let () =
+ eq __LOC__ (Hashtbl.hash "xy" |> normalize) 194127723
+
+let () =
+ Mt.from_pair_suites __FILE__ !suites
diff --git a/jscomp/test/test.mllib b/jscomp/test/test.mllib
index 2e77828450..eb2b035b47 100644
--- a/jscomp/test/test.mllib
+++ b/jscomp/test/test.mllib
@@ -246,3 +246,4 @@ mt_global
event_ffi
+hash_test
\ No newline at end of file
diff --git a/package.json b/package.json
index 94e9b2ff9d..83b6924f53 100644
--- a/package.json
+++ b/package.json
@@ -13,7 +13,7 @@
},
"scripts": {
"test":
- "node ./node_modules/mocha/bin/mocha './jscomp/test/**/*_test.js' -R spec",
+ "node ./node_modules/mocha/bin/mocha './jscomp/test/**/*_test.js' ",
"wtest":
"node ./node_modules/mocha/bin/mocha './jscomp/test/**/*_test.js' -R spec -w",
"cover" :