You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

138 lines
4.3 KiB

4 years ago
  1. /**
  2. * @preserve
  3. * JS Implementation of incremental MurmurHash3 (r150) (as of May 10, 2013)
  4. *
  5. * @author <a href="mailto:jensyt@gmail.com">Jens Taylor</a>
  6. * @see http://github.com/homebrewing/brauhaus-diff
  7. * @author <a href="mailto:gary.court@gmail.com">Gary Court</a>
  8. * @see http://github.com/garycourt/murmurhash-js
  9. * @author <a href="mailto:aappleby@gmail.com">Austin Appleby</a>
  10. * @see http://sites.google.com/site/murmurhash/
  11. */
  12. (function(){
  13. var cache;
  14. // Call this function without `new` to use the cached object (good for
  15. // single-threaded environments), or with `new` to create a new object.
  16. //
  17. // @param {string} key A UTF-16 or ASCII string
  18. // @param {number} seed An optional positive integer
  19. // @return {object} A MurmurHash3 object for incremental hashing
  20. function MurmurHash3(key, seed) {
  21. var m = this instanceof MurmurHash3 ? this : cache;
  22. m.reset(seed)
  23. if (typeof key === 'string' && key.length > 0) {
  24. m.hash(key);
  25. }
  26. if (m !== this) {
  27. return m;
  28. }
  29. };
  30. // Incrementally add a string to this hash
  31. //
  32. // @param {string} key A UTF-16 or ASCII string
  33. // @return {object} this
  34. MurmurHash3.prototype.hash = function(key) {
  35. var h1, k1, i, top, len;
  36. len = key.length;
  37. this.len += len;
  38. k1 = this.k1;
  39. i = 0;
  40. switch (this.rem) {
  41. case 0: k1 ^= len > i ? (key.charCodeAt(i++) & 0xffff) : 0;
  42. case 1: k1 ^= len > i ? (key.charCodeAt(i++) & 0xffff) << 8 : 0;
  43. case 2: k1 ^= len > i ? (key.charCodeAt(i++) & 0xffff) << 16 : 0;
  44. case 3:
  45. k1 ^= len > i ? (key.charCodeAt(i) & 0xff) << 24 : 0;
  46. k1 ^= len > i ? (key.charCodeAt(i++) & 0xff00) >> 8 : 0;
  47. }
  48. this.rem = (len + this.rem) & 3; // & 3 is same as % 4
  49. len -= this.rem;
  50. if (len > 0) {
  51. h1 = this.h1;
  52. while (1) {
  53. k1 = (k1 * 0x2d51 + (k1 & 0xffff) * 0xcc9e0000) & 0xffffffff;
  54. k1 = (k1 << 15) | (k1 >>> 17);
  55. k1 = (k1 * 0x3593 + (k1 & 0xffff) * 0x1b870000) & 0xffffffff;
  56. h1 ^= k1;
  57. h1 = (h1 << 13) | (h1 >>> 19);
  58. h1 = (h1 * 5 + 0xe6546b64) & 0xffffffff;
  59. if (i >= len) {
  60. break;
  61. }
  62. k1 = ((key.charCodeAt(i++) & 0xffff)) ^
  63. ((key.charCodeAt(i++) & 0xffff) << 8) ^
  64. ((key.charCodeAt(i++) & 0xffff) << 16);
  65. top = key.charCodeAt(i++);
  66. k1 ^= ((top & 0xff) << 24) ^
  67. ((top & 0xff00) >> 8);
  68. }
  69. k1 = 0;
  70. switch (this.rem) {
  71. case 3: k1 ^= (key.charCodeAt(i + 2) & 0xffff) << 16;
  72. case 2: k1 ^= (key.charCodeAt(i + 1) & 0xffff) << 8;
  73. case 1: k1 ^= (key.charCodeAt(i) & 0xffff);
  74. }
  75. this.h1 = h1;
  76. }
  77. this.k1 = k1;
  78. return this;
  79. };
  80. // Get the result of this hash
  81. //
  82. // @return {number} The 32-bit hash
  83. MurmurHash3.prototype.result = function() {
  84. var k1, h1;
  85. k1 = this.k1;
  86. h1 = this.h1;
  87. if (k1 > 0) {
  88. k1 = (k1 * 0x2d51 + (k1 & 0xffff) * 0xcc9e0000) & 0xffffffff;
  89. k1 = (k1 << 15) | (k1 >>> 17);
  90. k1 = (k1 * 0x3593 + (k1 & 0xffff) * 0x1b870000) & 0xffffffff;
  91. h1 ^= k1;
  92. }
  93. h1 ^= this.len;
  94. h1 ^= h1 >>> 16;
  95. h1 = (h1 * 0xca6b + (h1 & 0xffff) * 0x85eb0000) & 0xffffffff;
  96. h1 ^= h1 >>> 13;
  97. h1 = (h1 * 0xae35 + (h1 & 0xffff) * 0xc2b20000) & 0xffffffff;
  98. h1 ^= h1 >>> 16;
  99. return h1 >>> 0;
  100. };
  101. // Reset the hash object for reuse
  102. //
  103. // @param {number} seed An optional positive integer
  104. MurmurHash3.prototype.reset = function(seed) {
  105. this.h1 = typeof seed === 'number' ? seed : 0;
  106. this.rem = this.k1 = this.len = 0;
  107. return this;
  108. };
  109. // A cached object to use. This can be safely used if you're in a single-
  110. // threaded environment, otherwise you need to create new hashes to use.
  111. cache = new MurmurHash3();
  112. if (typeof(module) != 'undefined') {
  113. module.exports = MurmurHash3;
  114. } else {
  115. this.MurmurHash3 = MurmurHash3;
  116. }
  117. }());