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
5package strings
6
7import (
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.
17type 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
26func (b *Builder) copyCheck() {
27	if b.addr == nil {
28		// This hack works around a failing of Go's escape analysis
29		// that was causing b to escape and be heap allocated.
30		// See issue 23382.
31		// TODO: once issue 7921 is fixed, this should be reverted to
32		// just "b.addr = b".
33		b.addr = (*Builder)(abi.NoEscape(unsafe.Pointer(b)))
34	} else if b.addr != b {
35		panic("strings: illegal use of non-zero Builder copied by value")
36	}
37}
38
39// String returns the accumulated string.
40func (b *Builder) String() string {
41	return unsafe.String(unsafe.SliceData(b.buf), len(b.buf))
42}
43
44// Len returns the number of accumulated bytes; b.Len() == len(b.String()).
45func (b *Builder) Len() int { return len(b.buf) }
46
47// Cap returns the capacity of the builder's underlying byte slice. It is the
48// total space allocated for the string being built and includes any bytes
49// already written.
50func (b *Builder) Cap() int { return cap(b.buf) }
51
52// Reset resets the [Builder] to be empty.
53func (b *Builder) Reset() {
54	b.addr = nil
55	b.buf = nil
56}
57
58// grow copies the buffer to a new, larger buffer so that there are at least n
59// bytes of capacity beyond len(b.buf).
60func (b *Builder) grow(n int) {
61	buf := bytealg.MakeNoZero(2*cap(b.buf) + n)[:len(b.buf)]
62	copy(buf, b.buf)
63	b.buf = buf
64}
65
66// Grow grows b's capacity, if necessary, to guarantee space for
67// another n bytes. After Grow(n), at least n bytes can be written to b
68// without another allocation. If n is negative, Grow panics.
69func (b *Builder) Grow(n int) {
70	b.copyCheck()
71	if n < 0 {
72		panic("strings.Builder.Grow: negative count")
73	}
74	if cap(b.buf)-len(b.buf) < n {
75		b.grow(n)
76	}
77}
78
79// Write appends the contents of p to b's buffer.
80// Write always returns len(p), nil.
81func (b *Builder) Write(p []byte) (int, error) {
82	b.copyCheck()
83	b.buf = append(b.buf, p...)
84	return len(p), nil
85}
86
87// WriteByte appends the byte c to b's buffer.
88// The returned error is always nil.
89func (b *Builder) WriteByte(c byte) error {
90	b.copyCheck()
91	b.buf = append(b.buf, c)
92	return nil
93}
94
95// WriteRune appends the UTF-8 encoding of Unicode code point r to b's buffer.
96// It returns the length of r and a nil error.
97func (b *Builder) WriteRune(r rune) (int, error) {
98	b.copyCheck()
99	n := len(b.buf)
100	b.buf = utf8.AppendRune(b.buf, r)
101	return len(b.buf) - n, nil
102}
103
104// WriteString appends the contents of s to b's buffer.
105// It returns the length of s and a nil error.
106func (b *Builder) WriteString(s string) (int, error) {
107	b.copyCheck()
108	b.buf = append(b.buf, s...)
109	return len(s), nil
110}
111