aboutsummaryrefslogtreecommitdiff
path: root/libgo/go/bytes/buffer.go
diff options
context:
space:
mode:
authorIan Lance Taylor <ian@gcc.gnu.org>2012-02-01 19:26:59 +0000
committerIan Lance Taylor <ian@gcc.gnu.org>2012-02-01 19:26:59 +0000
commit9af4cb9545ce481b8d9d4a13acfe26512032e21b (patch)
tree7e7e6083ebe59999943a211a17f8ef6f07f17c2f /libgo/go/bytes/buffer.go
parent6b6cd722f329a168f98d1f421834cf40bb33a77d (diff)
downloadgcc-9af4cb9545ce481b8d9d4a13acfe26512032e21b.zip
gcc-9af4cb9545ce481b8d9d4a13acfe26512032e21b.tar.gz
gcc-9af4cb9545ce481b8d9d4a13acfe26512032e21b.tar.bz2
libgo: Update to weekly.2012-01-27.
From-SVN: r183810
Diffstat (limited to 'libgo/go/bytes/buffer.go')
-rw-r--r--libgo/go/bytes/buffer.go50
1 files changed, 37 insertions, 13 deletions
diff --git a/libgo/go/bytes/buffer.go b/libgo/go/bytes/buffer.go
index 77757af..2c3eb6a 100644
--- a/libgo/go/bytes/buffer.go
+++ b/libgo/go/bytes/buffer.go
@@ -33,6 +33,9 @@ const (
opRead // Any other read operation.
)
+// ErrTooLarge is passed to panic if memory cannot be allocated to store data in a buffer.
+var ErrTooLarge = errors.New("bytes.Buffer: too large")
+
// Bytes returns a slice of the contents of the unread portion of the buffer;
// len(b.Bytes()) == b.Len(). If the caller changes the contents of the
// returned slice, the contents of the buffer will change provided there
@@ -68,8 +71,9 @@ func (b *Buffer) Truncate(n int) {
// b.Reset() is the same as b.Truncate(0).
func (b *Buffer) Reset() { b.Truncate(0) }
-// Grow buffer to guarantee space for n more bytes.
-// Return index where bytes should be written.
+// grow grows the buffer to guarantee space for n more bytes.
+// It returns the index where bytes should be written.
+// If the buffer can't grow it will panic with ErrTooLarge.
func (b *Buffer) grow(n int) int {
m := b.Len()
// If buffer is empty, reset to recover space.
@@ -82,7 +86,7 @@ func (b *Buffer) grow(n int) int {
buf = b.bootstrap[0:]
} else {
// not enough space anywhere
- buf = make([]byte, 2*cap(b.buf)+n)
+ buf = makeSlice(2*cap(b.buf) + n)
copy(buf, b.buf[b.off:])
}
b.buf = buf
@@ -94,6 +98,8 @@ func (b *Buffer) grow(n int) int {
// Write appends the contents of p to the buffer. The return
// value n is the length of p; err is always nil.
+// If the buffer becomes too large, Write will panic with
+// ErrTooLarge.
func (b *Buffer) Write(p []byte) (n int, err error) {
b.lastRead = opInvalid
m := b.grow(len(p))
@@ -102,6 +108,8 @@ func (b *Buffer) Write(p []byte) (n int, err error) {
// WriteString appends the contents of s to the buffer. The return
// value n is the length of s; err is always nil.
+// If the buffer becomes too large, WriteString will panic with
+// ErrTooLarge.
func (b *Buffer) WriteString(s string) (n int, err error) {
b.lastRead = opInvalid
m := b.grow(len(s))
@@ -118,6 +126,8 @@ const MinRead = 512
// The return value n is the number of bytes read.
// Any error except io.EOF encountered during the read
// is also returned.
+// If the buffer becomes too large, ReadFrom will panic with
+// ErrTooLarge.
func (b *Buffer) ReadFrom(r io.Reader) (n int64, err error) {
b.lastRead = opInvalid
// If buffer is empty, reset to recover space.
@@ -125,18 +135,16 @@ func (b *Buffer) ReadFrom(r io.Reader) (n int64, err error) {
b.Truncate(0)
}
for {
- if cap(b.buf)-len(b.buf) < MinRead {
- var newBuf []byte
- // can we get space without allocation?
- if b.off+cap(b.buf)-len(b.buf) >= MinRead {
- // reuse beginning of buffer
- newBuf = b.buf[0 : len(b.buf)-b.off]
- } else {
- // not enough space at end; put space on end
- newBuf = make([]byte, len(b.buf)-b.off, 2*(cap(b.buf)-b.off)+MinRead)
+ if free := cap(b.buf) - len(b.buf); free < MinRead {
+ // not enough space at end
+ newBuf := b.buf
+ if b.off+free < MinRead {
+ // not enough space using beginning of buffer;
+ // double buffer capacity
+ newBuf = makeSlice(2*cap(b.buf) + MinRead)
}
copy(newBuf, b.buf[b.off:])
- b.buf = newBuf
+ b.buf = newBuf[:len(b.buf)-b.off]
b.off = 0
}
m, e := r.Read(b.buf[len(b.buf):cap(b.buf)])
@@ -152,6 +160,18 @@ func (b *Buffer) ReadFrom(r io.Reader) (n int64, err error) {
return n, nil // err is EOF, so return nil explicitly
}
+// makeSlice allocates a slice of size n. If the allocation fails, it panics
+// with ErrTooLarge.
+func makeSlice(n int) []byte {
+ // If the make fails, give a known error.
+ defer func() {
+ if recover() != nil {
+ panic(ErrTooLarge)
+ }
+ }()
+ return make([]byte, n)
+}
+
// WriteTo writes data to w until the buffer is drained or an error
// occurs. The return value n is the number of bytes written; it always
// fits into an int, but it is int64 to match the io.WriterTo interface.
@@ -176,6 +196,8 @@ func (b *Buffer) WriteTo(w io.Writer) (n int64, err error) {
// WriteByte appends the byte c to the buffer.
// The returned error is always nil, but is included
// to match bufio.Writer's WriteByte.
+// If the buffer becomes too large, WriteByte will panic with
+// ErrTooLarge.
func (b *Buffer) WriteByte(c byte) error {
b.lastRead = opInvalid
m := b.grow(1)
@@ -187,6 +209,8 @@ func (b *Buffer) WriteByte(c byte) error {
// code point r to the buffer, returning its length and
// an error, which is always nil but is included
// to match bufio.Writer's WriteRune.
+// If the buffer becomes too large, WriteRune will panic with
+// ErrTooLarge.
func (b *Buffer) WriteRune(r rune) (n int, err error) {
if r < utf8.RuneSelf {
b.WriteByte(byte(r))