package net.varkhan.base.containers.set;
import net.varkhan.base.containers.Hashes;
import net.varkhan.base.containers.HashingStrategy;
import net.varkhan.base.containers.Iterator;
import net.varkhan.base.containers.array.BitArrays;
import java.io.Serializable;
/**
* <b></b>.
* <p/>
*
* @author varkhan
* @date 2/11/12
* @time 3:45 PM
*/
public class BloomCountingSet<Key> implements CountingSet<Key>, Serializable, Cloneable {
protected final HashingStrategy<Key> hash;
protected long size = 0;
protected long count = 0;
protected final int num;
protected final int len;
protected final long msk;
protected /*final*/ int[] filter;
@SuppressWarnings("unchecked")
public BloomCountingSet(int num, int len) {
this((HashingStrategy<Key>) Hashes.DefaultHashingStrategy,num,len);
}
public BloomCountingSet(HashingStrategy<Key> hash, int num, int len) {
this.hash=hash;
this.num = num>512?512:num;
this.len = (1<<BitArrays.lsb(len));
this.msk = (1<<BitArrays.lsb(len))-1;
this.filter = new int[this.len];
}
protected int hash(long h, int i) {
return (int) (Hashes.mix(h+i) & msk);
}
public long size() {
return size;
}
public boolean isEmpty() {
return count==0;
}
public long count() {
return count;
}
public void clear() {
size = 0;
count = 0;
for(int i=0; i<filter.length; i++) filter[i] = 0;
}
public boolean add(Key key) {
long h = hash.hash(key);
boolean a = false;
for(int i=0; i<num; i++) {
int p = hash(h, i);
// Mark as add if count is 0, then increment count
if(filter[p]++ == 0) a = true;
}
if(a) size++;
count ++;
return a;
}
public boolean del(Key key) {
long h = hash.hash(key);
for(int i=0; i<num; i++) {
int p = hash(h, i);
int x = filter[p];
if(x==0) return false;
}
boolean d = false;
for(int i=0; i<num; i++) {
int p = hash(h, i);
// Decrement count, then mark as del if count is 0
if(--filter[p] == 0) d = true;
}
if(d) size--;
count --;
return d;
}
public boolean has(Key key) {
long h = hash.hash(key);
for(int i=0; i<num; i++) {
int p = hash(h, i);
int x = filter[p];
if(x==0) return false;
}
return true;
}
public long count(Key key) {
long h = hash.hash(key);
long c = Long.MAX_VALUE;
for(int i=0; i<num; i++) {
int p = hash(h, i);
int x = filter[p];
if(c>x) c=x;
}
return c;
}
@SuppressWarnings({ "unchecked" })
public Iterator<? extends Key> iterator() {
return Iterator.EMPTY;
}
public <Par> long visit(Visitor<Key,Par> vis, Par par) {
return 0;
}
public String toString() {
StringBuilder buf = new StringBuilder();
for(int i=0; i<this.filter.length; i++) {
if(i>0) buf.append('|');
buf.append(filter[i]>0 ? String.format("%3d", filter[i]) : " ");
}
return buf.toString();
}
@SuppressWarnings("unchecked")
public BloomCountingSet<Key> clone() {
BloomCountingSet<Key> c;
try {
c=(BloomCountingSet<Key>) super.clone();
}
catch(CloneNotSupportedException e) {
throw new InternalError();
}
c.filter = this.filter.clone();
return c;
}
}