gtsocial-umbx

Unnamed repository; edit this file 'description' to name the repository.
Log | Files | Refs | README | LICENSE

strings_unsafe.go (2541B)


      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 //go:build !purego && !appengine
      6 // +build !purego,!appengine
      7 
      8 package strs
      9 
     10 import (
     11 	"unsafe"
     12 
     13 	"google.golang.org/protobuf/reflect/protoreflect"
     14 )
     15 
     16 type (
     17 	stringHeader struct {
     18 		Data unsafe.Pointer
     19 		Len  int
     20 	}
     21 	sliceHeader struct {
     22 		Data unsafe.Pointer
     23 		Len  int
     24 		Cap  int
     25 	}
     26 )
     27 
     28 // UnsafeString returns an unsafe string reference of b.
     29 // The caller must treat the input slice as immutable.
     30 //
     31 // WARNING: Use carefully. The returned result must not leak to the end user
     32 // unless the input slice is provably immutable.
     33 func UnsafeString(b []byte) (s string) {
     34 	src := (*sliceHeader)(unsafe.Pointer(&b))
     35 	dst := (*stringHeader)(unsafe.Pointer(&s))
     36 	dst.Data = src.Data
     37 	dst.Len = src.Len
     38 	return s
     39 }
     40 
     41 // UnsafeBytes returns an unsafe bytes slice reference of s.
     42 // The caller must treat returned slice as immutable.
     43 //
     44 // WARNING: Use carefully. The returned result must not leak to the end user.
     45 func UnsafeBytes(s string) (b []byte) {
     46 	src := (*stringHeader)(unsafe.Pointer(&s))
     47 	dst := (*sliceHeader)(unsafe.Pointer(&b))
     48 	dst.Data = src.Data
     49 	dst.Len = src.Len
     50 	dst.Cap = src.Len
     51 	return b
     52 }
     53 
     54 // Builder builds a set of strings with shared lifetime.
     55 // This differs from strings.Builder, which is for building a single string.
     56 type Builder struct {
     57 	buf []byte
     58 }
     59 
     60 // AppendFullName is equivalent to protoreflect.FullName.Append,
     61 // but optimized for large batches where each name has a shared lifetime.
     62 func (sb *Builder) AppendFullName(prefix protoreflect.FullName, name protoreflect.Name) protoreflect.FullName {
     63 	n := len(prefix) + len(".") + len(name)
     64 	if len(prefix) == 0 {
     65 		n -= len(".")
     66 	}
     67 	sb.grow(n)
     68 	sb.buf = append(sb.buf, prefix...)
     69 	sb.buf = append(sb.buf, '.')
     70 	sb.buf = append(sb.buf, name...)
     71 	return protoreflect.FullName(sb.last(n))
     72 }
     73 
     74 // MakeString is equivalent to string(b), but optimized for large batches
     75 // with a shared lifetime.
     76 func (sb *Builder) MakeString(b []byte) string {
     77 	sb.grow(len(b))
     78 	sb.buf = append(sb.buf, b...)
     79 	return sb.last(len(b))
     80 }
     81 
     82 func (sb *Builder) grow(n int) {
     83 	if cap(sb.buf)-len(sb.buf) >= n {
     84 		return
     85 	}
     86 
     87 	// Unlike strings.Builder, we do not need to copy over the contents
     88 	// of the old buffer since our builder provides no API for
     89 	// retrieving previously created strings.
     90 	sb.buf = make([]byte, 0, 2*(cap(sb.buf)+n))
     91 }
     92 
     93 func (sb *Builder) last(n int) string {
     94 	return UnsafeString(sb.buf[len(sb.buf)-n:])
     95 }