Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
48 changes: 48 additions & 0 deletions binary.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
package bloom

import (
"bytes"
"encoding/gob"
)

const binVer0 = 0

// Data to be included in binary representation of Filter.
type marshalFilter struct {
Version int
Data []uint64
Lookups int
Count int64
}

// MarshalBinary returns a binary representation of the filter.
//
// This method implements the encoding.BinaryMarshaler interface.
// The packages encoding/gob, encoding/json, and encoding/xml
// all check for this interface.
func (f *Filter) MarshalBinary() ([]byte, error) {
mf := marshalFilter{
Version: binVer0,
Data: f.data,
Lookups: f.lookups,
Count: f.count,
}
var b bytes.Buffer
err := gob.NewEncoder(&b).Encode(mf)
return b.Bytes(), err
}

// UnmarshalBinary imports binary data created by MarshalBinary
// into an empty filter. If the filter is not empty, all previous
// entries are overwritten.
func (f *Filter) UnmarshalBinary(data []byte) error {
var mf marshalFilter
err := gob.NewDecoder(bytes.NewBuffer(data)).Decode(&mf)
if err != nil {
return err
}
f.data = mf.Data
f.lookups = mf.Lookups
f.count = mf.Count
return nil
}
30 changes: 30 additions & 0 deletions example_test.go
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
package bloom_test

import (
"bytes"
"encoding/gob"
"fmt"
"github.com/yourbasic/bloom"
"log"
"math/rand"
"strconv"
)
Expand Down Expand Up @@ -72,3 +75,30 @@ func ExampleFilter_Union() {
fmt.Println("f1 ∪ f2:", f1.Union(f2).Count())
// Output: f1 ∪ f2: 505
}

// Send a filter over a network using the encoding/gob package.
func ExampleFilter_MarshalBinary_network() {
// Create a mock network and a new Filter.
var network bytes.Buffer
f1 := bloom.New(1000, 100)
f1.Add("Hello, filter!")

// Create an encoder and send the filter to the network.
enc := gob.NewEncoder(&network)
if err := enc.Encode(f1); err != nil {
log.Fatal("encode error:", err)
}

// Create a decoder and receive the filter from the network.
dec := gob.NewDecoder(&network)
var f2 bloom.Filter
if err := dec.Decode(&f2); err != nil {
log.Fatal("decode error:", err)
}

// Check that we got the same filter back.
if f2.Test("Hello, filter!") {
fmt.Println("Filter arrived safely.")
}
// Output: Filter arrived safely.
}
9 changes: 5 additions & 4 deletions filter.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,9 @@
// A Bloom filter is a fast and space-efficient probabilistic data structure
// used to test set membership.
//
// A membership test returns either
// ”likely member” or ”definitely not a member”. Only false positives
// can occur: an element that has been added to the filter
// will be identified as ”likely member”.
// A membership test returns either ”likely member” or ”definitely not
// a member”. Only false positives can occur: an element that has been added
// to the filter will always be identified as ”likely member”.
//
// Elements can be added, but not removed. With more elements in the filter,
// the probability of false positives increases.
Expand Down Expand Up @@ -97,11 +96,13 @@ func (f *Filter) add(h1, h2 uint64) bool {
}

// TestByte tells if b is a likely member of the filter.
// If true, b is probably a member; if false, b is definitely not a member.
func (f *Filter) TestByte(b []byte) bool {
return f.test(hash(b))
}

// Test tells if s is a likely member of the filter.
// If true, s is probably a member; if false, s is definitely not a member.
func (f *Filter) Test(s string) bool {
return f.test(hashString(s))
}
Expand Down
24 changes: 24 additions & 0 deletions filter_test.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
package bloom

import (
"bytes"
"encoding/gob"
"reflect"
"testing"
)

Expand Down Expand Up @@ -140,6 +143,27 @@ func TestUnion(t *testing.T) {
}
}

func TestMarshal(t *testing.T) {
var network bytes.Buffer
f1 := New(10000, 100)
f1.Add("Hello, filter!")

enc := gob.NewEncoder(&network)
if err := enc.Encode(f1); err != nil {
t.Errorf("Encode->err = %v; want nil\n", err)
}

dec := gob.NewDecoder(&network)
var f2 *Filter
if err := dec.Decode(&f2); err != nil {
t.Errorf("Decode->err = %v; want nil\n", err)
}

if !reflect.DeepEqual(f1, f2) {
t.Errorf("Encode(Code(f)) = %v; want %v\n", f1, f2)
}
}

var fox string = "The quick brown fox jumps over the lazy dog."

func BenchmarkAdd(b *testing.B) {
Expand Down