Last active
March 22, 2022 12:04
-
-
Save 19h/8047372 to your computer and use it in GitHub Desktop.
bloomFilter in Javascript.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
var bloomFilter = (function(exports) { | |
var typedArrays = typeof ArrayBuffer !== "undefined"; | |
var popcnt = function (v) { | |
v -= v >> 1 & 1431655765; | |
v = (v & 858993459) + (v >> 2 & 858993459); | |
return (v + (v >> 4) & 252645135) * 16843009 >> 24 | |
} | |
var fnv_1a = function (v) { | |
var n = v.length, | |
a = 2166136261, | |
c, d, i = -1; | |
while (++i < n) { | |
c = v.charCodeAt(i); | |
if (d = c & 4278190080) { | |
a ^= d >> 24; | |
a += (a << 1) + (a << 4) + (a << 7) + (a << 8) + (a << 24) | |
} | |
if (d = c & 16711680) { | |
a ^= d >> 16; | |
a += (a << 1) + (a << 4) + (a << 7) + (a << 8) + (a << 24) | |
} | |
if (d = c & 65280) { | |
a ^= d >> 8; | |
a += (a << 1) + (a << 4) + (a << 7) + (a << 8) + (a << 24) | |
} | |
a ^= c & 255; | |
a += (a << 1) + (a << 4) + (a << 7) + (a << 8) + (a << 24) | |
} | |
a += a << 13; | |
a ^= a >> 7; | |
a += a << 3; | |
a ^= a >> 17; | |
a += a << 5; | |
return a & 4294967295 | |
} | |
var fnv_1a_b = function (a) { | |
a += (a << 1) + (a << 4) + (a << 7) + (a << 8) + (a << 24); | |
a += a << 13; | |
a ^= a >> 7; | |
a += a << 3; | |
a ^= a >> 17; | |
a += a << 5; | |
return a & 4294967295 | |
} | |
var BloomFilter = function (m, k) { | |
var a; | |
if (typeof m !== "number") a = m, m = a.length * 32; | |
this.m = m; | |
this.k = k; | |
var n = Math.ceil(m / 32), | |
i = -1; | |
if (typedArrays) { | |
var kbytes = 1 << Math.ceil(Math.log(Math.ceil(Math.log(m) / Math.LN2 / 8)) / Math.LN2), | |
array = kbytes === 1 ? Uint8Array : kbytes === 2 ? Uint16Array : Uint32Array, | |
kbuffer = new ArrayBuffer(kbytes * k), | |
buckets = this.buckets = new Int32Array(n); | |
if (a) | |
while (++i < | |
n) buckets[i] = a[i]; | |
this._locations = new array(kbuffer) | |
} else { | |
var buckets = this.buckets = []; | |
if (a) | |
while (++i < n) buckets[i] = a[i]; | |
else | |
while (++i < n) buckets[i] = 0; | |
this._locations = [] | |
} | |
} | |
BloomFilter.prototype.locations = function(v) { | |
var k = this.k, | |
m = this.m, | |
r = this._locations, | |
a = fnv_1a(v), | |
b = fnv_1a_b(a), | |
i = -1, | |
x = a % m; | |
while (++i < k) { | |
r[i] = x < 0 ? x + m : x; | |
x = (x + b) % m | |
} | |
return r | |
}; | |
BloomFilter.prototype.add = function(v) { | |
var l = this.locations(v + ""), | |
i = -1, | |
k = this.k, | |
buckets = this.buckets; | |
while (++i < k) buckets[Math.floor(l[i] / 32)] |= 1 << l[i] % 32 | |
}; | |
BloomFilter.prototype.test = | |
function(v) { | |
var l = this.locations(v + ""), | |
i = -1, | |
k = this.k, | |
b, buckets = this.buckets; | |
while (++i < k) { | |
b = l[i]; | |
if ((buckets[Math.floor(b / 32)] & 1 << b % 32) === 0) return false | |
} | |
return true | |
}; | |
BloomFilter.prototype.size = function() { | |
var buckets = this.buckets, | |
bits = 0; | |
for (var i = 0, n = buckets.length; i < n; ++i) bits += popcnt(buckets[i]); | |
return -this.m * Math.log(1 - bits / this.m) / this.k | |
}; | |
return BloomFilter | |
})(); | |
var bloom = bloomFilter( 32 * 256, 16 ); | |
// Add elements to the filter | |
bloom.add("foo"); | |
bloom.add("bar"); | |
// Will be true if the element is probably in the set | |
// or false if the item is definitely not in the set. | |
bloom.test("foo"); // true | |
bloom.test("bar"); // true | |
bloom.test("\\o//"); // false |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment