...

Source file src/pkg/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		"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	// 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 := make([]byte, len(b.buf), 2*cap(b.buf)+n)
    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		if r < utf8.RuneSelf {
   106			b.buf = append(b.buf, byte(r))
   107			return 1, nil
   108		}
   109		l := len(b.buf)
   110		if cap(b.buf)-l < utf8.UTFMax {
   111			b.grow(utf8.UTFMax)
   112		}
   113		n := utf8.EncodeRune(b.buf[l:l+utf8.UTFMax], r)
   114		b.buf = b.buf[:l+n]
   115		return n, nil
   116	}
   117	
   118	// WriteString appends the contents of s to b's buffer.
   119	// It returns the length of s and a nil error.
   120	func (b *Builder) WriteString(s string) (int, error) {
   121		b.copyCheck()
   122		b.buf = append(b.buf, s...)
   123		return len(s), nil
   124	}
   125	

View as plain text