diff options
author | Ian Lance Taylor <ian@gcc.gnu.org> | 2018-01-17 14:20:29 +0000 |
---|---|---|
committer | Ian Lance Taylor <ian@gcc.gnu.org> | 2018-01-17 14:20:29 +0000 |
commit | c6d6367f848cfd8381aba41e035c5e7e873667c5 (patch) | |
tree | a218e98243463fc27f5053b4444e2544c63cd57a /libgo/go/strings/builder.go | |
parent | 9bff0086915f544fa648ea81131f035cb9ce79a4 (diff) | |
download | gcc-c6d6367f848cfd8381aba41e035c5e7e873667c5.zip gcc-c6d6367f848cfd8381aba41e035c5e7e873667c5.tar.gz gcc-c6d6367f848cfd8381aba41e035c5e7e873667c5.tar.bz2 |
libgo: update to Go1.10beta2 release
Reviewed-on: https://go-review.googlesource.com/87897
From-SVN: r256794
Diffstat (limited to 'libgo/go/strings/builder.go')
-rw-r--r-- | libgo/go/strings/builder.go | 75 |
1 files changed, 37 insertions, 38 deletions
diff --git a/libgo/go/strings/builder.go b/libgo/go/strings/builder.go index 594f3db..ac58f34 100644 --- a/libgo/go/strings/builder.go +++ b/libgo/go/strings/builder.go @@ -5,16 +5,41 @@ package strings import ( - "errors" - "io" "unicode/utf8" "unsafe" ) // A Builder is used to efficiently build a string using Write methods. // It minimizes memory copying. The zero value is ready to use. +// Do not copy a non-zero Builder. type Builder struct { - buf []byte + addr *Builder // of receiver, to detect copies by value + buf []byte +} + +// noescape hides a pointer from escape analysis. noescape is +// the identity function but escape analysis doesn't think the +// output depends on the input. noescape is inlined and currently +// compiles down to zero instructions. +// USE CAREFULLY! +// This was copied from the runtime; see issues 23382 and 7921. +//go:nosplit +func noescape(p unsafe.Pointer) unsafe.Pointer { + x := uintptr(p) + return unsafe.Pointer(x ^ 0) +} + +func (b *Builder) copyCheck() { + if b.addr == nil { + // This hack works around a failing of Go's escape analysis + // that was causing b to escape and be heap allocated. + // See issue 23382. + // TODO: once issue 7921 is fixed, this should be reverted to + // just "b.addr = b". + b.addr = (*Builder)(noescape(unsafe.Pointer(b))) + } else if b.addr != b { + panic("strings: illegal use of non-zero Builder copied by value") + } } // String returns the accumulated string. @@ -26,9 +51,10 @@ func (b *Builder) String() string { func (b *Builder) Len() int { return len(b.buf) } // Reset resets the Builder to be empty. -func (b *Builder) Reset() { b.buf = nil } - -const maxInt = int(^uint(0) >> 1) +func (b *Builder) Reset() { + b.addr = nil + b.buf = nil +} // grow copies the buffer to a new, larger buffer so that there are at least n // bytes of capacity beyond len(b.buf). @@ -42,6 +68,7 @@ func (b *Builder) grow(n int) { // another n bytes. After Grow(n), at least n bytes can be written to b // without another allocation. If n is negative, Grow panics. func (b *Builder) Grow(n int) { + b.copyCheck() if n < 0 { panic("strings.Builder.Grow: negative count") } @@ -53,6 +80,7 @@ func (b *Builder) Grow(n int) { // Write appends the contents of p to b's buffer. // Write always returns len(p), nil. func (b *Builder) Write(p []byte) (int, error) { + b.copyCheck() b.buf = append(b.buf, p...) return len(p), nil } @@ -60,6 +88,7 @@ func (b *Builder) Write(p []byte) (int, error) { // WriteByte appends the byte c to b's buffer. // The returned error is always nil. func (b *Builder) WriteByte(c byte) error { + b.copyCheck() b.buf = append(b.buf, c) return nil } @@ -67,6 +96,7 @@ func (b *Builder) WriteByte(c byte) error { // WriteRune appends the UTF-8 encoding of Unicode code point r to b's buffer. // It returns the length of r and a nil error. func (b *Builder) WriteRune(r rune) (int, error) { + b.copyCheck() if r < utf8.RuneSelf { b.buf = append(b.buf, byte(r)) return 1, nil @@ -83,38 +113,7 @@ func (b *Builder) WriteRune(r rune) (int, error) { // WriteString appends the contents of s to b's buffer. // It returns the length of s and a nil error. func (b *Builder) WriteString(s string) (int, error) { + b.copyCheck() b.buf = append(b.buf, s...) return len(s), nil } - -// minRead is the minimum slice passed to a Read call by Builder.ReadFrom. -// It is the same as bytes.MinRead. -const minRead = 512 - -// errNegativeRead is the panic value if the reader passed to Builder.ReadFrom -// returns a negative count. -var errNegativeRead = errors.New("strings.Builder: reader returned negative count from Read") - -// ReadFrom reads data from r until EOF and appends it to b's buffer. -// The return value n is the number of bytes read. -// Any error except io.EOF encountered during the read is also returned. -func (b *Builder) ReadFrom(r io.Reader) (n int64, err error) { - for { - l := len(b.buf) - if cap(b.buf)-l < minRead { - b.grow(minRead) - } - m, e := r.Read(b.buf[l:cap(b.buf)]) - if m < 0 { - panic(errNegativeRead) - } - b.buf = b.buf[:l+m] - n += int64(m) - if e == io.EOF { - return n, nil - } - if e != nil { - return n, e - } - } -} |