xxhash.js 8.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389
  1. /**
  2. xxHash implementation in pure Javascript
  3. Copyright (C) 2013, Pierre Curto
  4. MIT license
  5. */
  6. var UINT32 = require('cuint').UINT32
  7. /*
  8. Merged this sequence of method calls as it speeds up
  9. the calculations by a factor of 2
  10. */
  11. // this.v1.add( other.multiply(PRIME32_2) ).rotl(13).multiply(PRIME32_1);
  12. UINT32.prototype.xxh_update = function (low, high) {
  13. var b00 = PRIME32_2._low
  14. var b16 = PRIME32_2._high
  15. var c16, c00
  16. c00 = low * b00
  17. c16 = c00 >>> 16
  18. c16 += high * b00
  19. c16 &= 0xFFFF // Not required but improves performance
  20. c16 += low * b16
  21. var a00 = this._low + (c00 & 0xFFFF)
  22. var a16 = a00 >>> 16
  23. a16 += this._high + (c16 & 0xFFFF)
  24. var v = (a16 << 16) | (a00 & 0xFFFF)
  25. v = (v << 13) | (v >>> 19)
  26. a00 = v & 0xFFFF
  27. a16 = v >>> 16
  28. b00 = PRIME32_1._low
  29. b16 = PRIME32_1._high
  30. c00 = a00 * b00
  31. c16 = c00 >>> 16
  32. c16 += a16 * b00
  33. c16 &= 0xFFFF // Not required but improves performance
  34. c16 += a00 * b16
  35. this._low = c00 & 0xFFFF
  36. this._high = c16 & 0xFFFF
  37. }
  38. /*
  39. * Constants
  40. */
  41. var PRIME32_1 = UINT32( '2654435761' )
  42. var PRIME32_2 = UINT32( '2246822519' )
  43. var PRIME32_3 = UINT32( '3266489917' )
  44. var PRIME32_4 = UINT32( '668265263' )
  45. var PRIME32_5 = UINT32( '374761393' )
  46. /**
  47. * Convert string to proper UTF-8 array
  48. * @param str Input string
  49. * @returns {Uint8Array} UTF8 array is returned as uint8 array
  50. */
  51. function toUTF8Array (str) {
  52. var utf8 = []
  53. for (var i=0, n=str.length; i < n; i++) {
  54. var charcode = str.charCodeAt(i)
  55. if (charcode < 0x80) utf8.push(charcode)
  56. else if (charcode < 0x800) {
  57. utf8.push(0xc0 | (charcode >> 6),
  58. 0x80 | (charcode & 0x3f))
  59. }
  60. else if (charcode < 0xd800 || charcode >= 0xe000) {
  61. utf8.push(0xe0 | (charcode >> 12),
  62. 0x80 | ((charcode>>6) & 0x3f),
  63. 0x80 | (charcode & 0x3f))
  64. }
  65. // surrogate pair
  66. else {
  67. i++;
  68. // UTF-16 encodes 0x10000-0x10FFFF by
  69. // subtracting 0x10000 and splitting the
  70. // 20 bits of 0x0-0xFFFFF into two halves
  71. charcode = 0x10000 + (((charcode & 0x3ff)<<10)
  72. | (str.charCodeAt(i) & 0x3ff))
  73. utf8.push(0xf0 | (charcode >>18),
  74. 0x80 | ((charcode>>12) & 0x3f),
  75. 0x80 | ((charcode>>6) & 0x3f),
  76. 0x80 | (charcode & 0x3f))
  77. }
  78. }
  79. return new Uint8Array(utf8)
  80. }
  81. /**
  82. * XXH object used as a constructor or a function
  83. * @constructor
  84. * or
  85. * @param {Object|String} input data
  86. * @param {Number|UINT32} seed
  87. * @return ThisExpression
  88. * or
  89. * @return {UINT32} xxHash
  90. */
  91. function XXH () {
  92. if (arguments.length == 2)
  93. return new XXH( arguments[1] ).update( arguments[0] ).digest()
  94. if (!(this instanceof XXH))
  95. return new XXH( arguments[0] )
  96. init.call(this, arguments[0])
  97. }
  98. /**
  99. * Initialize the XXH instance with the given seed
  100. * @method init
  101. * @param {Number|Object} seed as a number or an unsigned 32 bits integer
  102. * @return ThisExpression
  103. */
  104. function init (seed) {
  105. this.seed = seed instanceof UINT32 ? seed.clone() : UINT32(seed)
  106. this.v1 = this.seed.clone().add(PRIME32_1).add(PRIME32_2)
  107. this.v2 = this.seed.clone().add(PRIME32_2)
  108. this.v3 = this.seed.clone()
  109. this.v4 = this.seed.clone().subtract(PRIME32_1)
  110. this.total_len = 0
  111. this.memsize = 0
  112. this.memory = null
  113. return this
  114. }
  115. XXH.prototype.init = init
  116. /**
  117. * Add data to be computed for the XXH hash
  118. * @method update
  119. * @param {String|Buffer|ArrayBuffer} input as a string or nodejs Buffer or ArrayBuffer
  120. * @return ThisExpression
  121. */
  122. XXH.prototype.update = function (input) {
  123. var isString = typeof input == 'string'
  124. var isArrayBuffer
  125. // Convert all strings to utf-8 first (issue #5)
  126. if (isString) {
  127. input = toUTF8Array(input)
  128. isString = false
  129. isArrayBuffer = true
  130. }
  131. if (typeof ArrayBuffer !== "undefined" && input instanceof ArrayBuffer)
  132. {
  133. isArrayBuffer = true
  134. input = new Uint8Array(input);
  135. }
  136. var p = 0
  137. var len = input.length
  138. var bEnd = p + len
  139. if (len == 0) return this
  140. this.total_len += len
  141. if (this.memsize == 0)
  142. {
  143. if (isString) {
  144. this.memory = ''
  145. } else if (isArrayBuffer) {
  146. this.memory = new Uint8Array(16)
  147. } else {
  148. this.memory = new Buffer(16)
  149. }
  150. }
  151. if (this.memsize + len < 16) // fill in tmp buffer
  152. {
  153. // XXH_memcpy(this.memory + this.memsize, input, len)
  154. if (isString) {
  155. this.memory += input
  156. } else if (isArrayBuffer) {
  157. this.memory.set( input.subarray(0, len), this.memsize )
  158. } else {
  159. input.copy( this.memory, this.memsize, 0, len )
  160. }
  161. this.memsize += len
  162. return this
  163. }
  164. if (this.memsize > 0) // some data left from previous update
  165. {
  166. // XXH_memcpy(this.memory + this.memsize, input, 16-this.memsize);
  167. if (isString) {
  168. this.memory += input.slice(0, 16 - this.memsize)
  169. } else if (isArrayBuffer) {
  170. this.memory.set( input.subarray(0, 16 - this.memsize), this.memsize )
  171. } else {
  172. input.copy( this.memory, this.memsize, 0, 16 - this.memsize )
  173. }
  174. var p32 = 0
  175. if (isString) {
  176. this.v1.xxh_update(
  177. (this.memory.charCodeAt(p32+1) << 8) | this.memory.charCodeAt(p32)
  178. , (this.memory.charCodeAt(p32+3) << 8) | this.memory.charCodeAt(p32+2)
  179. )
  180. p32 += 4
  181. this.v2.xxh_update(
  182. (this.memory.charCodeAt(p32+1) << 8) | this.memory.charCodeAt(p32)
  183. , (this.memory.charCodeAt(p32+3) << 8) | this.memory.charCodeAt(p32+2)
  184. )
  185. p32 += 4
  186. this.v3.xxh_update(
  187. (this.memory.charCodeAt(p32+1) << 8) | this.memory.charCodeAt(p32)
  188. , (this.memory.charCodeAt(p32+3) << 8) | this.memory.charCodeAt(p32+2)
  189. )
  190. p32 += 4
  191. this.v4.xxh_update(
  192. (this.memory.charCodeAt(p32+1) << 8) | this.memory.charCodeAt(p32)
  193. , (this.memory.charCodeAt(p32+3) << 8) | this.memory.charCodeAt(p32+2)
  194. )
  195. } else {
  196. this.v1.xxh_update(
  197. (this.memory[p32+1] << 8) | this.memory[p32]
  198. , (this.memory[p32+3] << 8) | this.memory[p32+2]
  199. )
  200. p32 += 4
  201. this.v2.xxh_update(
  202. (this.memory[p32+1] << 8) | this.memory[p32]
  203. , (this.memory[p32+3] << 8) | this.memory[p32+2]
  204. )
  205. p32 += 4
  206. this.v3.xxh_update(
  207. (this.memory[p32+1] << 8) | this.memory[p32]
  208. , (this.memory[p32+3] << 8) | this.memory[p32+2]
  209. )
  210. p32 += 4
  211. this.v4.xxh_update(
  212. (this.memory[p32+1] << 8) | this.memory[p32]
  213. , (this.memory[p32+3] << 8) | this.memory[p32+2]
  214. )
  215. }
  216. p += 16 - this.memsize
  217. this.memsize = 0
  218. if (isString) this.memory = ''
  219. }
  220. if (p <= bEnd - 16)
  221. {
  222. var limit = bEnd - 16
  223. do
  224. {
  225. if (isString) {
  226. this.v1.xxh_update(
  227. (input.charCodeAt(p+1) << 8) | input.charCodeAt(p)
  228. , (input.charCodeAt(p+3) << 8) | input.charCodeAt(p+2)
  229. )
  230. p += 4
  231. this.v2.xxh_update(
  232. (input.charCodeAt(p+1) << 8) | input.charCodeAt(p)
  233. , (input.charCodeAt(p+3) << 8) | input.charCodeAt(p+2)
  234. )
  235. p += 4
  236. this.v3.xxh_update(
  237. (input.charCodeAt(p+1) << 8) | input.charCodeAt(p)
  238. , (input.charCodeAt(p+3) << 8) | input.charCodeAt(p+2)
  239. )
  240. p += 4
  241. this.v4.xxh_update(
  242. (input.charCodeAt(p+1) << 8) | input.charCodeAt(p)
  243. , (input.charCodeAt(p+3) << 8) | input.charCodeAt(p+2)
  244. )
  245. } else {
  246. this.v1.xxh_update(
  247. (input[p+1] << 8) | input[p]
  248. , (input[p+3] << 8) | input[p+2]
  249. )
  250. p += 4
  251. this.v2.xxh_update(
  252. (input[p+1] << 8) | input[p]
  253. , (input[p+3] << 8) | input[p+2]
  254. )
  255. p += 4
  256. this.v3.xxh_update(
  257. (input[p+1] << 8) | input[p]
  258. , (input[p+3] << 8) | input[p+2]
  259. )
  260. p += 4
  261. this.v4.xxh_update(
  262. (input[p+1] << 8) | input[p]
  263. , (input[p+3] << 8) | input[p+2]
  264. )
  265. }
  266. p += 4
  267. } while (p <= limit)
  268. }
  269. if (p < bEnd)
  270. {
  271. // XXH_memcpy(this.memory, p, bEnd-p);
  272. if (isString) {
  273. this.memory += input.slice(p)
  274. } else if (isArrayBuffer) {
  275. this.memory.set( input.subarray(p, bEnd), this.memsize )
  276. } else {
  277. input.copy( this.memory, this.memsize, p, bEnd )
  278. }
  279. this.memsize = bEnd - p
  280. }
  281. return this
  282. }
  283. /**
  284. * Finalize the XXH computation. The XXH instance is ready for reuse for the given seed
  285. * @method digest
  286. * @return {UINT32} xxHash
  287. */
  288. XXH.prototype.digest = function () {
  289. var input = this.memory
  290. var isString = typeof input == 'string'
  291. var p = 0
  292. var bEnd = this.memsize
  293. var h32, h
  294. var u = new UINT32
  295. if (this.total_len >= 16)
  296. {
  297. h32 = this.v1.rotl(1).add( this.v2.rotl(7).add( this.v3.rotl(12).add( this.v4.rotl(18) ) ) )
  298. }
  299. else
  300. {
  301. h32 = this.seed.clone().add( PRIME32_5 )
  302. }
  303. h32.add( u.fromNumber(this.total_len) )
  304. while (p <= bEnd - 4)
  305. {
  306. if (isString) {
  307. u.fromBits(
  308. (input.charCodeAt(p+1) << 8) | input.charCodeAt(p)
  309. , (input.charCodeAt(p+3) << 8) | input.charCodeAt(p+2)
  310. )
  311. } else {
  312. u.fromBits(
  313. (input[p+1] << 8) | input[p]
  314. , (input[p+3] << 8) | input[p+2]
  315. )
  316. }
  317. h32
  318. .add( u.multiply(PRIME32_3) )
  319. .rotl(17)
  320. .multiply( PRIME32_4 )
  321. p += 4
  322. }
  323. while (p < bEnd)
  324. {
  325. u.fromBits( isString ? input.charCodeAt(p++) : input[p++], 0 )
  326. h32
  327. .add( u.multiply(PRIME32_5) )
  328. .rotl(11)
  329. .multiply(PRIME32_1)
  330. }
  331. h = h32.clone().shiftRight(15)
  332. h32.xor(h).multiply(PRIME32_2)
  333. h = h32.clone().shiftRight(13)
  334. h32.xor(h).multiply(PRIME32_3)
  335. h = h32.clone().shiftRight(16)
  336. h32.xor(h)
  337. // Reset the state
  338. this.init( this.seed )
  339. return h32
  340. }
  341. module.exports = XXH