Source file src/strings/builder.go

     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/bytealg"
     9  	"unicode/utf8"
    10  	"unsafe"
    11  )
    12  
    13  // A Builder is used to efficiently build a string using [Builder.Write] methods.
    14  // It minimizes memory copying. The zero value is ready to use.
    15  // Do not copy a non-zero Builder.
    16  type Builder struct {
    17  	addr *Builder // of receiver, to detect copies by value
    18  	buf  []byte
    19  }
    20  
    21  // noescape hides a pointer from escape analysis. It is the identity function
    22  // but escape analysis doesn't think the output depends on the input.
    23  // noescape is inlined and currently compiles down to zero instructions.
    24  // USE CAREFULLY!
    25  // This was copied from the runtime; see issues 23382 and 7921.
    26  //
    27  //go:nosplit
    28  //go:nocheckptr
    29  func noescape(p unsafe.Pointer) unsafe.Pointer {
    30  	x := uintptr(p)
    31  	return unsafe.Pointer(x ^ 0)
    32  }
    33  
    34  func (b *Builder) copyCheck() {
    35  	if b.addr == nil {
    36  		// This hack works around a failing of Go's escape analysis
    37  		// that was causing b to escape and be heap allocated.
    38  		// See issue 23382.
    39  		// TODO: once issue 7921 is fixed, this should be reverted to
    40  		// just "b.addr = b".
    41  		b.addr = (*Builder)(noescape(unsafe.Pointer(b)))
    42  	} else if b.addr != b {
    43  		panic("strings: illegal use of non-zero Builder copied by value")
    44  	}
    45  }
    46  
    47  // String returns the accumulated string.
    48  func (b *Builder) String() string {
    49  	return unsafe.String(unsafe.SliceData(b.buf), len(b.buf))
    50  }
    51  
    52  // Len returns the number of accumulated bytes; b.Len() == len(b.String()).
    53  func (b *Builder) Len() int { return len(b.buf) }
    54  
    55  // Cap returns the capacity of the builder's underlying byte slice. It is the
    56  // total space allocated for the string being built and includes any bytes
    57  // already written.
    58  func (b *Builder) Cap() int { return cap(b.buf) }
    59  
    60  // Reset resets the [Builder] to be empty.
    61  func (b *Builder) Reset() {
    62  	b.addr = nil
    63  	b.buf = nil
    64  }
    65  
    66  // grow copies the buffer to a new, larger buffer so that there are at least n
    67  // bytes of capacity beyond len(b.buf).
    68  func (b *Builder) grow(n int) {
    69  	buf := bytealg.MakeNoZero(2*cap(b.buf) + n)[:len(b.buf)]
    70  	copy(buf, b.buf)
    71  	b.buf = buf
    72  }
    73  
    74  // Grow grows b's capacity, if necessary, to guarantee space for
    75  // another n bytes. After Grow(n), at least n bytes can be written to b
    76  // without another allocation. If n is negative, Grow panics.
    77  func (b *Builder) Grow(n int) {
    78  	b.copyCheck()
    79  	if n < 0 {
    80  		panic("strings.Builder.Grow: negative count")
    81  	}
    82  	if cap(b.buf)-len(b.buf) < n {
    83  		b.grow(n)
    84  	}
    85  }
    86  
    87  // Write appends the contents of p to b's buffer.
    88  // Write always returns len(p), nil.
    89  func (b *Builder) Write(p []byte) (int, error) {
    90  	b.copyCheck()
    91  	b.buf = append(b.buf, p...)
    92  	return len(p), nil
    93  }
    94  
    95  // WriteByte appends the byte c to b's buffer.
    96  // The returned error is always nil.
    97  func (b *Builder) WriteByte(c byte) error {
    98  	b.copyCheck()
    99  	b.buf = append(b.buf, c)
   100  	return nil
   101  }
   102  
   103  // WriteRune appends the UTF-8 encoding of Unicode code point r to b's buffer.
   104  // It returns the length of r and a nil error.
   105  func (b *Builder) WriteRune(r rune) (int, error) {
   106  	b.copyCheck()
   107  	n := len(b.buf)
   108  	b.buf = utf8.AppendRune(b.buf, r)
   109  	return len(b.buf) - n, nil
   110  }
   111  
   112  // WriteString appends the contents of s to b's buffer.
   113  // It returns the length of s and a nil error.
   114  func (b *Builder) WriteString(s string) (int, error) {
   115  	b.copyCheck()
   116  	b.buf = append(b.buf, s...)
   117  	return len(s), nil
   118  }
   119  

View as plain text