xxhash_unsafe.go raw

   1  //go:build !appengine
   2  // +build !appengine
   3  
   4  // This file encapsulates usage of unsafe.
   5  // xxhash_safe.go contains the safe implementations.
   6  
   7  package xxhash
   8  
   9  import (
  10  	"unsafe"
  11  )
  12  
  13  // In the future it's possible that compiler optimizations will make these
  14  // XxxString functions unnecessary by realizing that calls such as
  15  // Sum64([]byte(s)) don't need to copy s. See https://go.dev/issue/2205.
  16  // If that happens, even if we keep these functions they can be replaced with
  17  // the trivial safe code.
  18  
  19  // NOTE: The usual way of doing an unsafe string-to-[]byte conversion is:
  20  //
  21  //   var b []byte
  22  //   bh := (*reflect.SliceHeader)(unsafe.Pointer(&b))
  23  //   bh.Data = (*reflect.StringHeader)(unsafe.Pointer(&s)).Data
  24  //   bh.Len = len(s)
  25  //   bh.Cap = len(s)
  26  //
  27  // Unfortunately, as of Go 1.15.3 the inliner's cost model assigns a high enough
  28  // weight to this sequence of expressions that any function that uses it will
  29  // not be inlined. Instead, the functions below use a different unsafe
  30  // conversion designed to minimize the inliner weight and allow both to be
  31  // inlined. There is also a test (TestInlining) which verifies that these are
  32  // inlined.
  33  //
  34  // See https://github.com/golang/go/issues/42739 for discussion.
  35  
  36  // Sum64String computes the 64-bit xxHash digest of s with a zero seed.
  37  // It may be faster than Sum64([]byte(s)) by avoiding a copy.
  38  func Sum64String(s string) uint64 {
  39  	b := *(*[]byte)(unsafe.Pointer(&sliceHeader{s, len(s)}))
  40  	return Sum64(b)
  41  }
  42  
  43  // WriteString adds more data to d. It always returns len(s), nil.
  44  // It may be faster than Write([]byte(s)) by avoiding a copy.
  45  func (d *Digest) WriteString(s string) (n int, err error) {
  46  	d.Write(*(*[]byte)(unsafe.Pointer(&sliceHeader{s, len(s)})))
  47  	// d.Write always returns len(s), nil.
  48  	// Ignoring the return output and returning these fixed values buys a
  49  	// savings of 6 in the inliner's cost model.
  50  	return len(s), nil
  51  }
  52  
  53  // sliceHeader is similar to reflect.SliceHeader, but it assumes that the layout
  54  // of the first two words is the same as the layout of a string.
  55  type sliceHeader struct {
  56  	s   string
  57  	cap int
  58  }
  59