strings_unsafe.go raw

   1  // Copyright 2018 The Go Authors. All rights reserved.
   2  // Use of this source code is governed by a BSD-style
   3  // license that can be found in the LICENSE file.
   4  
   5  package strs
   6  
   7  import (
   8  	"unsafe"
   9  
  10  	"google.golang.org/protobuf/reflect/protoreflect"
  11  )
  12  
  13  // UnsafeString returns an unsafe string reference of b.
  14  // The caller must treat the input slice as immutable.
  15  //
  16  // WARNING: Use carefully. The returned result must not leak to the end user
  17  // unless the input slice is provably immutable.
  18  func UnsafeString(b []byte) string {
  19  	return unsafe.String(unsafe.SliceData(b), len(b))
  20  }
  21  
  22  // UnsafeBytes returns an unsafe bytes slice reference of s.
  23  // The caller must treat returned slice as immutable.
  24  //
  25  // WARNING: Use carefully. The returned result must not leak to the end user.
  26  func UnsafeBytes(s string) []byte {
  27  	return unsafe.Slice(unsafe.StringData(s), len(s))
  28  }
  29  
  30  // Builder builds a set of strings with shared lifetime.
  31  // This differs from strings.Builder, which is for building a single string.
  32  type Builder struct {
  33  	buf []byte
  34  }
  35  
  36  // AppendFullName is equivalent to protoreflect.FullName.Append,
  37  // but optimized for large batches where each name has a shared lifetime.
  38  func (sb *Builder) AppendFullName(prefix protoreflect.FullName, name protoreflect.Name) protoreflect.FullName {
  39  	n := len(prefix) + len(".") + len(name)
  40  	if len(prefix) == 0 {
  41  		n -= len(".")
  42  	}
  43  	sb.grow(n)
  44  	sb.buf = append(sb.buf, prefix...)
  45  	sb.buf = append(sb.buf, '.')
  46  	sb.buf = append(sb.buf, name...)
  47  	return protoreflect.FullName(sb.last(n))
  48  }
  49  
  50  // MakeString is equivalent to string(b), but optimized for large batches
  51  // with a shared lifetime.
  52  func (sb *Builder) MakeString(b []byte) string {
  53  	sb.grow(len(b))
  54  	sb.buf = append(sb.buf, b...)
  55  	return sb.last(len(b))
  56  }
  57  
  58  func (sb *Builder) grow(n int) {
  59  	if cap(sb.buf)-len(sb.buf) >= n {
  60  		return
  61  	}
  62  
  63  	// Unlike strings.Builder, we do not need to copy over the contents
  64  	// of the old buffer since our builder provides no API for
  65  	// retrieving previously created strings.
  66  	sb.buf = make([]byte, 0, 2*(cap(sb.buf)+n))
  67  }
  68  
  69  func (sb *Builder) last(n int) string {
  70  	return UnsafeString(sb.buf[len(sb.buf)-n:])
  71  }
  72