xref: /aosp_15_r20/external/golang-protobuf/internal/strs/strings_unsafe.go (revision 1c12ee1efe575feb122dbf939ff15148a3b3e8f2)
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