Home | History | Annotate | Download | only in strings
      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 	"unicode/utf8"
      9 	"unsafe"
     10 )
     11 
     12 // A Builder is used to efficiently build a string using Write methods.
     13 // It minimizes memory copying. The zero value is ready to use.
     14 // Do not copy a non-zero Builder.
     15 type Builder struct {
     16 	addr *Builder // of receiver, to detect copies by value
     17 	buf  []byte
     18 }
     19 
     20 // noescape hides a pointer from escape analysis.  noescape is
     21 // the identity function but escape analysis doesn't think the
     22 // output depends on the input. noescape is inlined and currently
     23 // compiles down to zero instructions.
     24 // USE CAREFULLY!
     25 // This was copied from the runtime; see issues 23382 and 7921.
     26 //go:nosplit
     27 func noescape(p unsafe.Pointer) unsafe.Pointer {
     28 	x := uintptr(p)
     29 	return unsafe.Pointer(x ^ 0)
     30 }
     31 
     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)(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 *(*string)(unsafe.Pointer(&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 // Reset resets the Builder to be empty.
     54 func (b *Builder) Reset() {
     55 	b.addr = nil
     56 	b.buf = nil
     57 }
     58 
     59 // grow copies the buffer to a new, larger buffer so that there are at least n
     60 // bytes of capacity beyond len(b.buf).
     61 func (b *Builder) grow(n int) {
     62 	buf := make([]byte, len(b.buf), 2*cap(b.buf)+n)
     63 	copy(buf, b.buf)
     64 	b.buf = buf
     65 }
     66 
     67 // Grow grows b's capacity, if necessary, to guarantee space for
     68 // another n bytes. After Grow(n), at least n bytes can be written to b
     69 // without another allocation. If n is negative, Grow panics.
     70 func (b *Builder) Grow(n int) {
     71 	b.copyCheck()
     72 	if n < 0 {
     73 		panic("strings.Builder.Grow: negative count")
     74 	}
     75 	if cap(b.buf)-len(b.buf) < n {
     76 		b.grow(n)
     77 	}
     78 }
     79 
     80 // Write appends the contents of p to b's buffer.
     81 // Write always returns len(p), nil.
     82 func (b *Builder) Write(p []byte) (int, error) {
     83 	b.copyCheck()
     84 	b.buf = append(b.buf, p...)
     85 	return len(p), nil
     86 }
     87 
     88 // WriteByte appends the byte c to b's buffer.
     89 // The returned error is always nil.
     90 func (b *Builder) WriteByte(c byte) error {
     91 	b.copyCheck()
     92 	b.buf = append(b.buf, c)
     93 	return nil
     94 }
     95 
     96 // WriteRune appends the UTF-8 encoding of Unicode code point r to b's buffer.
     97 // It returns the length of r and a nil error.
     98 func (b *Builder) WriteRune(r rune) (int, error) {
     99 	b.copyCheck()
    100 	if r < utf8.RuneSelf {
    101 		b.buf = append(b.buf, byte(r))
    102 		return 1, nil
    103 	}
    104 	l := len(b.buf)
    105 	if cap(b.buf)-l < utf8.UTFMax {
    106 		b.grow(utf8.UTFMax)
    107 	}
    108 	n := utf8.EncodeRune(b.buf[l:l+utf8.UTFMax], r)
    109 	b.buf = b.buf[:l+n]
    110 	return n, nil
    111 }
    112 
    113 // WriteString appends the contents of s to b's buffer.
    114 // It returns the length of s and a nil error.
    115 func (b *Builder) WriteString(s string) (int, error) {
    116 	b.copyCheck()
    117 	b.buf = append(b.buf, s...)
    118 	return len(s), nil
    119 }
    120