1 // Copyright 2017 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 strings
6 7 import (
8 "internal/abi"
9 "internal/bytealg"
10 "unicode/utf8"
11 "unsafe"
12 )
13 14 // A Builder is used to efficiently build a string using [Builder.Write] methods.
15 // It minimizes memory copying. The zero value is ready to use.
16 // Do not copy a non-zero Builder.
17 type Builder struct {
18 addr *Builder // of receiver, to detect copies by value
19 20 // External users should never get direct access to this buffer, since
21 // the slice at some point will be converted to a string using unsafe, also
22 // data between len(buf) and cap(buf) might be uninitialized.
23 buf []byte
24 }
25 26 // copyCheck implements a dynamic check to prevent modification after
27 // copying a non-zero Builder, which would be unsafe (see #25907, #47276).
28 //
29 // We cannot add a noCopy field to Builder, to cause vet's copylocks
30 // check to report copying, because copylocks cannot reliably
31 // discriminate the zero and nonzero cases.
32 func (b *Builder) copyCheck() {
33 if b.addr == nil {
34 // This hack works around a failing of Go's escape analysis
35 // that was causing b to escape and be heap allocated.
36 // See issue 23382.
37 // TODO: once issue 7921 is fixed, this should be reverted to
38 // just "b.addr = b".
39 b.addr = (*Builder)(abi.NoEscape(unsafe.Pointer(b)))
40 } else if b.addr != b {
41 panic("strings: illegal use of non-zero Builder copied by value")
42 }
43 }
44 45 // String returns the accumulated string.
46 func (b *Builder) String() string {
47 return unsafe.String(unsafe.SliceData(b.buf), len(b.buf))
48 }
49 50 // Len returns the number of accumulated bytes; b.Len() == len(b.String()).
51 func (b *Builder) Len() int { return len(b.buf) }
52 53 // Cap returns the capacity of the builder's underlying byte slice. It is the
54 // total space allocated for the string being built and includes any bytes
55 // already written.
56 func (b *Builder) Cap() int { return cap(b.buf) }
57 58 // Reset resets the [Builder] to be empty.
59 func (b *Builder) Reset() {
60 b.addr = nil
61 b.buf = nil
62 }
63 64 // grow copies the buffer to a new, larger buffer so that there are at least n
65 // bytes of capacity beyond len(b.buf).
66 func (b *Builder) grow(n int) {
67 buf := bytealg.MakeNoZero(2*cap(b.buf) + n)[:len(b.buf)]
68 copy(buf, b.buf)
69 b.buf = buf
70 }
71 72 // Grow grows b's capacity, if necessary, to guarantee space for
73 // another n bytes. After Grow(n), at least n bytes can be written to b
74 // without another allocation. If n is negative, Grow panics.
75 func (b *Builder) Grow(n int) {
76 b.copyCheck()
77 if n < 0 {
78 panic("strings.Builder.Grow: negative count")
79 }
80 if cap(b.buf)-len(b.buf) < n {
81 b.grow(n)
82 }
83 }
84 85 // Write appends the contents of p to b's buffer.
86 // Write always returns len(p), nil.
87 func (b *Builder) Write(p []byte) (int, error) {
88 b.copyCheck()
89 b.buf = append(b.buf, p...)
90 return len(p), nil
91 }
92 93 // WriteByte appends the byte c to b's buffer.
94 // The returned error is always nil.
95 func (b *Builder) WriteByte(c byte) error {
96 b.copyCheck()
97 b.buf = append(b.buf, c)
98 return nil
99 }
100 101 // WriteRune appends the UTF-8 encoding of Unicode code point r to b's buffer.
102 // It returns the length of r and a nil error.
103 func (b *Builder) WriteRune(r rune) (int, error) {
104 b.copyCheck()
105 n := len(b.buf)
106 b.buf = utf8.AppendRune(b.buf, r)
107 return len(b.buf) - n, nil
108 }
109 110 // WriteString appends the contents of s to b's buffer.
111 // It returns the length of s and a nil error.
112 func (b *Builder) WriteString(s []byte) (int, error) {
113 b.copyCheck()
114 b.buf = append(b.buf, s...)
115 return len(s), nil
116 }
117