1
0
mirror of https://github.com/golang/go synced 2024-11-25 06:57:58 -07:00

net/textproto: avoid 1 copy in ReadLine, ReadContinuedLine

Fixes #2083.

R=msolo, bradfitz
CC=golang-dev
https://golang.org/cl/4812042
This commit is contained in:
Russ Cox 2011-07-20 11:11:57 -04:00
parent df07b6d14a
commit 27a3dcd0d2

View File

@ -33,22 +33,25 @@ func NewReader(r *bufio.Reader) *Reader {
// ReadLine reads a single line from r, // ReadLine reads a single line from r,
// eliding the final \n or \r\n from the returned string. // eliding the final \n or \r\n from the returned string.
func (r *Reader) ReadLine() (string, os.Error) { func (r *Reader) ReadLine() (string, os.Error) {
line, err := r.ReadLineBytes() line, err := r.readLineSlice()
return string(line), err return string(line), err
} }
// ReadLineBytes is like ReadLine but returns a []byte instead of a string. // ReadLineBytes is like ReadLine but returns a []byte instead of a string.
func (r *Reader) ReadLineBytes() ([]byte, os.Error) { func (r *Reader) ReadLineBytes() ([]byte, os.Error) {
r.closeDot() line, err := r.readLineSlice()
line, err := r.R.ReadBytes('\n') if line != nil {
n := len(line) buf := make([]byte, len(line))
if n > 0 && line[n-1] == '\n' { copy(buf, line)
n-- line = buf
if n > 0 && line[n-1] == '\r' {
n--
}
} }
return line[0:n], err return line, err
}
func (r *Reader) readLineSlice() ([]byte, os.Error) {
r.closeDot()
line, _, err := r.R.ReadLine()
return line, err
} }
// ReadContinuedLine reads a possibly continued line from r, // ReadContinuedLine reads a possibly continued line from r,
@ -71,7 +74,7 @@ func (r *Reader) ReadLineBytes() ([]byte, os.Error) {
// A line consisting of only white space is never continued. // A line consisting of only white space is never continued.
// //
func (r *Reader) ReadContinuedLine() (string, os.Error) { func (r *Reader) ReadContinuedLine() (string, os.Error) {
line, err := r.ReadContinuedLineBytes() line, err := r.readContinuedLineSlice()
return string(line), err return string(line), err
} }
@ -92,8 +95,18 @@ func trim(s []byte) []byte {
// ReadContinuedLineBytes is like ReadContinuedLine but // ReadContinuedLineBytes is like ReadContinuedLine but
// returns a []byte instead of a string. // returns a []byte instead of a string.
func (r *Reader) ReadContinuedLineBytes() ([]byte, os.Error) { func (r *Reader) ReadContinuedLineBytes() ([]byte, os.Error) {
line, err := r.readContinuedLineSlice()
if line != nil {
buf := make([]byte, len(line))
copy(buf, line)
line = buf
}
return line, err
}
func (r *Reader) readContinuedLineSlice() ([]byte, os.Error) {
// Read the first line. // Read the first line.
line, err := r.ReadLineBytes() line, err := r.readLineSlice()
if err != nil { if err != nil {
return line, err return line, err
} }
@ -127,8 +140,11 @@ func (r *Reader) ReadContinuedLineBytes() ([]byte, os.Error) {
break break
} }
} }
// copy now since the next call to read a slice invalidates line
line = append(make([]byte, 0, len(line)*2), line...)
var cont []byte var cont []byte
cont, err = r.ReadLineBytes() cont, err = r.readLineSlice()
cont = trim(cont) cont = trim(cont)
line = append(line, ' ') line = append(line, ' ')
line = append(line, cont...) line = append(line, cont...)
@ -422,7 +438,7 @@ func (r *Reader) ReadDotLines() ([]string, os.Error) {
func (r *Reader) ReadMIMEHeader() (MIMEHeader, os.Error) { func (r *Reader) ReadMIMEHeader() (MIMEHeader, os.Error) {
m := make(MIMEHeader) m := make(MIMEHeader)
for { for {
kv, err := r.ReadContinuedLineBytes() kv, err := r.readContinuedLineSlice()
if len(kv) == 0 { if len(kv) == 0 {
return m, err return m, err
} }