Skip to content

Commit 25de947

Browse files
committed
Add a fast path for string inputs
``` │ master.bench │ perf-string.bench │ │ sec/op │ sec/op vs base │ String/default-10 86.98n ± 3% 77.57n ± 1% -10.82% (p=0.002 n=6) String/xxhash-10 40.10n ± 0% 34.82n ± 4% -13.19% (p=0.002 n=6) geomean 59.06n 51.97n -12.01% │ master.bench │ perf-string.bench │ │ B/op │ B/op vs base │ String/default-10 56.00 ± 0% 56.00 ± 0% ~ (p=1.000 n=6) ¹ String/xxhash-10 16.00 ± 0% 16.00 ± 0% ~ (p=1.000 n=6) ¹ geomean 29.93 29.93 +0.00% ¹ all samples are equal │ master.bench │ perf-string.bench │ │ allocs/op │ allocs/op vs base │ String/default-10 3.000 ± 0% 3.000 ± 0% ~ (p=1.000 n=6) ¹ String/xxhash-10 1.000 ± 0% 1.000 ± 0% ~ (p=1.000 n=6) ¹ geomean 1.732 1.732 +0.00% ```
1 parent 72666c8 commit 25de947

File tree

1 file changed

+21
-8
lines changed

1 file changed

+21
-8
lines changed

hashstructure.go

+21-8
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,11 @@ func Hash(v interface{}, opts *HashOptions) (uint64, error) {
9191
// Reset the hash
9292
opts.Hasher.Reset()
9393

94+
// Fast path for strings.
95+
if s, ok := v.(string); ok {
96+
return hashString(opts.Hasher, s)
97+
}
98+
9499
// Create our walker and walk the structure
95100
w := &walker{
96101
h: opts.Hasher,
@@ -130,6 +135,21 @@ func (w *walker) hashDirect(v any) (uint64, error) {
130135
return w.h.Sum64(), err
131136
}
132137

138+
// A direct hash calculation used for strings.
139+
func (w *walker) hashString(s string) (uint64, error) {
140+
return hashString(w.h, s)
141+
}
142+
143+
// A direct hash calculation used for strings.
144+
func hashString(h hash.Hash64, s string) (uint64, error) {
145+
h.Reset()
146+
147+
// io.WriteString uses io.StringWriter if it exists, which is
148+
// implemented by e.g. github.com/cespare/xxhash.
149+
_, err := io.WriteString(h, s)
150+
return h.Sum64(), err
151+
}
152+
133153
func (w *walker) visit(v reflect.Value, opts *visitOpts) (uint64, error) {
134154
t := reflect.TypeOf(0)
135155

@@ -405,14 +425,7 @@ func (w *walker) visit(v reflect.Value, opts *visitOpts) (uint64, error) {
405425
return h, nil
406426

407427
case reflect.String:
408-
// Directly hash
409-
w.h.Reset()
410-
411-
// io.WriteString uses io.StringWriter if it exists, which is
412-
// implemented by e.g. github.com/cespare/xxhash.
413-
_, err := io.WriteString(w.h, v.String())
414-
return w.h.Sum64(), err
415-
428+
return w.hashString(v.String())
416429
default:
417430
return 0, fmt.Errorf("unknown kind to hash: %s", k)
418431
}

0 commit comments

Comments
 (0)