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" :