Skip to content

Commit

Permalink
Grow buffer instead of using a tmp slice
Browse files Browse the repository at this point in the history
  • Loading branch information
julienschmidt committed Apr 24, 2013
1 parent de021f9 commit a602069
Showing 1 changed file with 30 additions and 45 deletions.
75 changes: 30 additions & 45 deletions buffer.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,9 @@

package mysql

import (
"io"
)
import "io"

const (
defaultBufSize = 4096
)
const defaultBufSize = 4096

type buffer struct {
buf []byte
Expand All @@ -38,6 +34,11 @@ func (b *buffer) fill(need int) (err error) {
copy(b.buf[0:b.length], b.buf[b.idx:])
}

// grow buffer if necessary
if need > len(b.buf) {
b.grow(need)
}

b.idx = 0

var n int
Expand All @@ -54,48 +55,32 @@ func (b *buffer) fill(need int) (err error) {
return
}

// returns next N bytes from buffer.
// The returned slice is only guaranteed to be valid until the next read
func (b *buffer) readNext(need int) (p []byte, err error) {
// return slice from buffer if possible
if b.length >= need {
p = b.buf[b.idx : b.idx+need]
b.idx += need
b.length -= need
// credit for this code snippet goes to Maxim Khitrov
// https://groups.google.com/forum/#!topic/golang-nuts/ETbw1ECDgRs
func (b *buffer) grow(size int) {
if size > 2*cap(b.buf) {
newBuf := make([]byte, size)
copy(newBuf, b.buf)
b.buf = newBuf
return

} else {

// does the data fit into the buffer?
if need < len(b.buf) {
// refill
err = b.fill(need) // err deferred
p = b.buf[:need]
b.idx += need
b.length -= need
return

} else {
p = make([]byte, need)
has := 0

// copy data that is already in the buffer
if b.length > 0 {
copy(p[0:b.length], b.buf[b.idx:])
has = b.length
need -= has
b.idx = 0
b.length = 0
}

// read rest directly into the new slice
var n int
for err == nil && need > 0 {
n, err = b.rd.Read(p[has:])
has += n
need -= n
}
for cap(b.buf) < size {
b.buf = append(b.buf[:cap(b.buf)], 0)
}
b.buf = b.buf[:cap(b.buf)]
}
}

// returns next N bytes from buffer.
// The returned slice is only guaranteed to be valid until the next read
func (b *buffer) readNext(need int) (p []byte, err error) {
if b.length < need {
// refill
err = b.fill(need) // err deferred
}

p = b.buf[b.idx : b.idx+need]
b.idx += need
b.length -= need
return
}

0 comments on commit a602069

Please sign in to comment.