Jeff Garzik
12 years ago
1 changed files with 116 additions and 0 deletions
@ -0,0 +1,116 @@ |
|||
require('classtool'); |
|||
|
|||
function ClassSpec(b) { |
|||
var MAX_BLOOM_FILTER_SIZE = 36000; // bytes
|
|||
var MAX_HASH_FUNCS = 50; |
|||
var LN2SQUARED = 0.4804530139182014246671025263266649717305529515945455; |
|||
var LN2 = 0.6931471805599453094172321214581765680755001343602552; |
|||
var bit_mask = [0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80]; |
|||
|
|||
function Bloom() { |
|||
this.data = ''; |
|||
this.hashFuncs = 0; |
|||
}; |
|||
|
|||
function ROTL32(x, r) { |
|||
return (x << r) | (x >> (32 - r)); |
|||
}; |
|||
|
|||
function getBlockU32(blockIdx, data) { |
|||
var idx = blockIdx * 4; |
|||
var v = (data[idx + 0] << (0 * 8)) | |
|||
(data[idx + 1] << (1 * 8)) | |
|||
(data[idx + 2] << (2 * 8)) | |
|||
(data[idx + 3] << (3 * 8)); |
|||
return v; |
|||
}; |
|||
|
|||
Bloom.prototype.hash = function(hashNum, data) { |
|||
var h1 = hashNum * (0xffffffff / (this.hashFuncs - 1)); |
|||
var c1 = 0xcc9e2d51; |
|||
var c2 = 0x1b873593; |
|||
var nBlocks = data.length / 4; |
|||
|
|||
// data body
|
|||
for (var i = -nBlocks; i; i++) { |
|||
var k1 = getBlockU32(i); |
|||
|
|||
k1 *= c1; |
|||
k1 = ROTLF32(k1, 15); |
|||
k1 *= c2; |
|||
|
|||
h1 ^= k1; |
|||
h1 = ROTFL(h1, 13); |
|||
h1 = h1 * 5 + 0xe6546b64; |
|||
} |
|||
|
|||
// tail (trailing 1-3 bytes)
|
|||
var tail = data.slice(nBlocks * 4); |
|||
|
|||
var k1 = 0; |
|||
|
|||
switch (data.length & 3) { |
|||
case 3: k1 ^= tail[2] << 16; |
|||
case 2: k1 ^= tail[1] << 8; |
|||
case 1: k1 ^= tail[0]; |
|||
k1 *= c1; |
|||
k1 = ROTL32(k1, 15); |
|||
k1 *= c2; |
|||
h1 ^= k1; |
|||
} |
|||
|
|||
// finalize
|
|||
h1 ^= data.length; |
|||
h1 ^= h1 >> 16; |
|||
h1 *= 0x85ebca6b; |
|||
h1 ^= h1 >> 13; |
|||
h1 *= 0xc2b2ae35; |
|||
h1 ^= h1 >> 16; |
|||
|
|||
return h1 % (this.data.length * 8); |
|||
}; |
|||
|
|||
Bloom.prototype.insert = function(data) { |
|||
for (var i = 0; i < this.hashFuncs; i++) { |
|||
var index = this.hash(i, data); |
|||
this.data[index >> 3] |= bit_mask[7 & index]; |
|||
} |
|||
}; |
|||
|
|||
Bloom.prototype.contains = function(data) { |
|||
for (var i = 0; i < this.hashFuncs; i++) { |
|||
var index = this.hash(i, data); |
|||
if (!(this.data[index >> 3] & bit_mask[7 & index])) |
|||
return false; |
|||
} |
|||
|
|||
return true; |
|||
}; |
|||
|
|||
Bloom.prototype.sizeOk = function() { |
|||
return this.data.length <= MAX_BLOOM_FILTER_SIZE && |
|||
this.hashFuncs <= MAX_HASH_FUNCS; |
|||
}; |
|||
|
|||
function toInt(v) { |
|||
return ~~v; |
|||
} |
|||
|
|||
function min(a, b) { |
|||
if (a < b) |
|||
return a; |
|||
return b; |
|||
} |
|||
|
|||
Bloom.prototype.init = function(elements, FPRate) { |
|||
var filterSize = min(toInt(-1.0 / LN2SQUARED * elements * Math.log(FPRate)), |
|||
MAX_BLOOM_FILTER_SIZE * 8) / 8; |
|||
this.data[filterSize] = 0; |
|||
this.hashFuncs = min(toInt(this.data.length * 8 / elements * LN2), |
|||
MAX_HASH_FUNCS); |
|||
}; |
|||
|
|||
return Bloom; |
|||
}; |
|||
module.defineClass(ClassSpec); |
|||
|
Loading…
Reference in new issue