| package xxhash |
| |
| import ( |
| "bytes" |
| "encoding/binary" |
| "fmt" |
| "hash" |
| "hash/crc32" |
| "strings" |
| "testing" |
| |
| OneOfOne "github.com/OneOfOne/xxhash" |
| "github.com/spaolacci/murmur3" |
| ) |
| |
| var result uint64 |
| |
| func BenchmarkStringHash(b *testing.B) { |
| const s = "abcdefghijklmnop" |
| var r uint64 |
| b.ReportAllocs() |
| for n := 0; n < b.N; n++ { |
| r = Sum64([]byte(s)) |
| } |
| result = r |
| } |
| |
| func TestSum(t *testing.T) { |
| for i, tt := range []struct { |
| input string |
| want uint64 |
| }{ |
| {"", 0xef46db3751d8e999}, |
| {"a", 0xd24ec4f1a98c6e5b}, |
| {"as", 0x1c330fb2d66be179}, |
| {"asd", 0x631c37ce72a97393}, |
| {"asdf", 0x415872f599cea71e}, |
| { |
| // Exactly 63 characters, which exercises all code paths. |
| "Call me Ishmael. Some years ago--never mind how long precisely-", |
| 0x02a2e85470d6fd96, |
| }, |
| } { |
| for chunkSize := 1; chunkSize <= len(tt.input); chunkSize++ { |
| x := New() |
| for j := 0; j < len(tt.input); j += chunkSize { |
| end := j + chunkSize |
| if end > len(tt.input) { |
| end = len(tt.input) |
| } |
| chunk := []byte(tt.input[j:end]) |
| n, err := x.Write(chunk) |
| if err != nil || n != len(chunk) { |
| t.Fatalf("[i=%d,chunkSize=%d] Write: got (%d, %v); want (%d, nil)", |
| i, chunkSize, n, err, len(chunk)) |
| } |
| } |
| if got := x.Sum64(); got != tt.want { |
| t.Fatalf("[i=%d,chunkSize=%d] got 0x%x; want 0x%x", |
| i, chunkSize, got, tt.want) |
| } |
| var b [8]byte |
| binary.BigEndian.PutUint64(b[:], tt.want) |
| if got := x.Sum(nil); !bytes.Equal(got, b[:]) { |
| t.Fatalf("[i=%d,chunkSize=%d] Sum: got %v; want %v", |
| i, chunkSize, got, b[:]) |
| } |
| } |
| if got := Sum64([]byte(tt.input)); got != tt.want { |
| t.Fatalf("[i=%d] Sum64: got 0x%x; want 0x%x", i, got, tt.want) |
| } |
| if got := Sum64String(tt.input); got != tt.want { |
| t.Fatalf("[i=%d] Sum64String: got 0x%x; want 0x%x", i, got, tt.want) |
| } |
| } |
| } |
| |
| func TestReset(t *testing.T) { |
| parts := []string{"The quic", "k br", "o", "wn fox jumps", " ov", "er the lazy ", "dog."} |
| x := New() |
| for _, part := range parts { |
| x.Write([]byte(part)) |
| } |
| h0 := x.Sum64() |
| |
| x.Reset() |
| x.Write([]byte(strings.Join(parts, ""))) |
| h1 := x.Sum64() |
| |
| if h0 != h1 { |
| t.Errorf("0x%x != 0x%x", h0, h1) |
| } |
| } |
| |
| var ( |
| sink uint64 |
| sinkb []byte |
| ) |
| |
| func sumFunc(h hash.Hash) func(b []byte) uint64 { |
| return func(b []byte) uint64 { |
| h.Reset() |
| h.Write(b) |
| sinkb = h.Sum(nil) |
| return 0 // value doesn't matter |
| } |
| } |
| |
| func BenchmarkHashes(b *testing.B) { |
| for _, ht := range []struct { |
| name string |
| f interface{} |
| }{ |
| {"xxhash", Sum64}, |
| {"xxhash-string", Sum64String}, |
| {"OneOfOne", OneOfOne.Checksum64}, |
| {"murmur3", murmur3.Sum64}, |
| {"CRC-32", sumFunc(crc32.NewIEEE())}, |
| } { |
| for _, nt := range []struct { |
| name string |
| n int |
| }{ |
| {"5 B", 5}, |
| {"100 B", 100}, |
| {"4 KB", 4e3}, |
| {"10 MB", 10e6}, |
| } { |
| input := make([]byte, nt.n) |
| for i := range input { |
| input[i] = byte(i) |
| } |
| benchName := fmt.Sprintf("%s,n=%s", ht.name, nt.name) |
| if ht.name == "xxhash-string" { |
| f := ht.f.(func(string) uint64) |
| s := string(input) |
| b.Run(benchName, func(b *testing.B) { |
| b.SetBytes(int64(len(input))) |
| for i := 0; i < b.N; i++ { |
| sink = f(s) |
| } |
| }) |
| } else { |
| f := ht.f.(func([]byte) uint64) |
| b.Run(benchName, func(b *testing.B) { |
| b.SetBytes(int64(len(input))) |
| for i := 0; i < b.N; i++ { |
| sink = f(input) |
| } |
| }) |
| } |
| } |
| } |
| } |