class MultistageFilter {
constructor({
hash_fns = [create_hash_fn(0.146713, 0.452342), create_hash_fn(0.234412, 0.341343)],
num_counters = 500,
conservative_update = false,
} = {}) {
this.hash_fns = hash_fns
this.num_counters = num_counters
this.conservative_update = conservative_update
this.clear()
}
process(elem) {
const hashes = this._indexes(elem)
if (this.conservative_update) {
const counts = this.counts(elem)
const smallestCount = Math.min.apply(null, counts)
hashes.forEach((hash, fi) => {
this.filters[fi][hash] = Math.max(smallestCount + 1, counts[fi])
})
return this
}
else {
hashes.forEach((hash, fi) => {
this.filters[fi][hash] = this.filters[fi][hash] + 1
})
return this
}
}
counts(elem) {
return this._indexes(elem).map((hash, fi) => this.filters[fi][hash])
}
count(elem) {
return Math.min.apply(null, this.counts(elem))
}
clear() {
this.filters = this.hash_fns.map(hash_fn => new Uint32Array(this.num_counters))
}
clone() {
const cloned = new MultistageFilter({
hash_fns: this.hash_fns,
num_counters: this.num_counters,
conservative_update: this.conservative_update
})
cloned.filters = this.filters.map(f => f.slice())
return cloned
}
_indexes(elem) {
return this.hash_fns.map(f => f(elem) % this.num_counters)
}
}