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