github.com/zignig/go-ipfs@v0.0.0-20141111235910-c9e5fdf55a52/blocks/bloom/filter.go (about) 1 // package bloom implements a simple bloom filter. 2 package bloom 3 4 import ( 5 "errors" 6 "fmt" 7 "hash" 8 "hash/adler32" 9 "hash/crc32" 10 "hash/fnv" 11 "math/big" 12 ) 13 14 type Filter interface { 15 Add([]byte) 16 Find([]byte) bool 17 Merge(Filter) (Filter, error) 18 } 19 20 func BasicFilter() Filter { 21 // Non crypto hashes, because speed 22 return NewFilter(2048, adler32.New(), fnv.New32(), crc32.NewIEEE()) 23 } 24 25 func NewFilter(size int, hashes ...hash.Hash) Filter { 26 return &filter{ 27 filter: make([]byte, size), 28 hashes: hashes, 29 } 30 } 31 32 type filter struct { 33 filter []byte 34 hashes []hash.Hash 35 } 36 37 func (f *filter) Add(k []byte) { 38 for _, h := range f.hashes { 39 i := bytesMod(h.Sum(k), int64(len(f.filter)*8)) 40 f.setBit(i) 41 } 42 } 43 44 func (f *filter) Find(k []byte) bool { 45 for _, h := range f.hashes { 46 i := bytesMod(h.Sum(k), int64(len(f.filter)*8)) 47 if !f.getBit(i) { 48 return false 49 } 50 } 51 return true 52 } 53 54 func (f *filter) setBit(i int64) { 55 fmt.Printf("setting bit %d\n", i) 56 f.filter[i/8] |= (1 << byte(i%8)) 57 } 58 59 func (f *filter) getBit(i int64) bool { 60 fmt.Printf("getting bit %d\n", i) 61 return f.filter[i/8]&(1<<byte(i%8)) != 0 62 } 63 64 func bytesMod(b []byte, modulo int64) int64 { 65 i := big.NewInt(0) 66 i = i.SetBytes(b) 67 68 bigmod := big.NewInt(int64(modulo)) 69 result := big.NewInt(0) 70 result.Mod(i, bigmod) 71 72 return result.Int64() 73 } 74 75 func (f *filter) Merge(o Filter) (Filter, error) { 76 casfil, ok := o.(*filter) 77 if !ok { 78 return nil, errors.New("Unsupported filter type") 79 } 80 81 if len(casfil.filter) != len(f.filter) { 82 return nil, errors.New("filter lengths must match!") 83 } 84 85 nfilt := new(filter) 86 87 // this bit is sketchy, need a way of comparing hash functions 88 nfilt.hashes = f.hashes 89 90 nfilt.filter = make([]byte, len(f.filter)) 91 for i, v := range f.filter { 92 nfilt.filter[i] = v | casfil.filter[i] 93 } 94 95 return nfilt, nil 96 }