Skip to content

Instantly share code, notes, and snippets.

@19h
Last active March 22, 2022 12:04
Show Gist options
  • Save 19h/8047372 to your computer and use it in GitHub Desktop.
Save 19h/8047372 to your computer and use it in GitHub Desktop.
bloomFilter in Javascript.
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