blob: 5118c889452caef4f865e6b65b4da0200570285d [file]
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)
}
})
}
}
}
}