diff options
author | Russ Cox <rsc@golang.org> | 2009-02-03 14:16:22 -0800 |
---|---|---|
committer | Russ Cox <rsc@golang.org> | 2009-02-03 14:16:22 -0800 |
commit | 5b6d40041f593663c52f574f69d7d6bfc51e9ff5 (patch) | |
tree | 91e8a1f2fd6548d6c9ad61f91f97f19990bbc92e /src/lib/bufio.go | |
parent | ffcd33538f133b407f1187842f94932593d312b1 (diff) | |
download | golang-5b6d40041f593663c52f574f69d7d6bfc51e9ff5.tar.gz |
bufio:
* avoid large copies
* NewBufRead, NewBufWrite never fail
* add BufReadWrite
io:
* add io.Close
http, google/net/rpc:
* add, use http.Conn.Hijack
R=r
DELTA=416 (202 added, 123 deleted, 91 changed)
OCL=24153
CL=24238
Diffstat (limited to 'src/lib/bufio.go')
-rw-r--r-- | src/lib/bufio.go | 72 |
1 files changed, 68 insertions, 4 deletions
diff --git a/src/lib/bufio.go b/src/lib/bufio.go index 6fed9d06e..9f3688588 100644 --- a/src/lib/bufio.go +++ b/src/lib/bufio.go @@ -16,6 +16,8 @@ import ( // - BufRead: ReadRune, UnreadRune ? // could make ReadRune generic if we dropped UnreadRune // - buffered output +// - would like to rename to Read, Write, but breaks +// embedding of these: would lose the Read, Write methods. const ( defaultBufSize = 4096 @@ -44,6 +46,7 @@ type BufRead struct { rd io.Read; r, w int; err *os.Error; + lastbyte int; } func NewBufReadSize(rd io.Read, size int) (b *BufRead, err *os.Error) { @@ -53,11 +56,17 @@ func NewBufReadSize(rd io.Read, size int) (b *BufRead, err *os.Error) { b = new(BufRead); b.buf = make([]byte, size); b.rd = rd; + b.lastbyte = -1; return b, nil } -func NewBufRead(rd io.Read) (b *BufRead, err *os.Error) { - return NewBufReadSize(rd, defaultBufSize); +func NewBufRead(rd io.Read) *BufRead { + b, err := NewBufReadSize(rd, defaultBufSize); + if err != nil { + // cannot happen - defaultBufSize is a valid size + panic("bufio: NewBufRead: ", err.String()); + } + return b; } // Read a new chunk into the buffer. @@ -94,6 +103,23 @@ func (b *BufRead) Read(p []byte) (nn int, err *os.Error) { for len(p) > 0 { n := len(p); if b.w == b.r { + if len(p) >= len(b.buf) { + // Large read, empty buffer. + // Read directly into p to avoid copy. + n, b.err = b.rd.Read(p); + if n > 0 { + b.lastbyte = int(p[n-1]); + } + p = p[n:len(p)]; + nn += n; + if b.err != nil { + return nn, b.err + } + if n == 0 { + return nn, EndOfFile + } + continue; + } b.Fill(); if b.err != nil { return nn, b.err @@ -108,6 +134,7 @@ func (b *BufRead) Read(p []byte) (nn int, err *os.Error) { copySlice(p[0:n], b.buf[b.r:b.r+n]); p = p[n:len(p)]; b.r += n; + b.lastbyte = int(b.buf[b.r-1]); nn += n } return nn, nil @@ -127,6 +154,7 @@ func (b *BufRead) ReadByte() (c byte, err *os.Error) { } c = b.buf[b.r]; b.r++; + b.lastbyte = int(c); return c, nil } @@ -135,10 +163,18 @@ func (b *BufRead) UnreadByte() *os.Error { if b.err != nil { return b.err } + if b.r == b.w && b.lastbyte >= 0 { + b.w = 1; + b.r = 0; + b.buf[0] = byte(b.lastbyte); + b.lastbyte = -1; + return nil; + } if b.r <= 0 { return PhaseError } b.r--; + b.lastbyte = -1; return nil } @@ -163,6 +199,7 @@ func (b *BufRead) ReadRune() (rune int, size int, err *os.Error) { rune, size = utf8.DecodeRune(b.buf[b.r:b.w]); } b.r += size; + b.lastbyte = int(b.buf[b.r-1]); return rune, size, nil } @@ -343,8 +380,13 @@ func NewBufWriteSize(wr io.Write, size int) (b *BufWrite, err *os.Error) { return b, nil } -func NewBufWrite(wr io.Write) (b *BufWrite, err *os.Error) { - return NewBufWriteSize(wr, defaultBufSize); +func NewBufWrite(wr io.Write) *BufWrite { + b, err := NewBufWriteSize(wr, defaultBufSize); + if err != nil { + // cannot happen - defaultBufSize is valid size + panic("bufio: NewBufWrite: ", err.String()); + } + return b; } // Flush the output buffer. @@ -393,6 +435,17 @@ func (b *BufWrite) Write(p []byte) (nn int, err *os.Error) { } n = b.Available() } + if b.Available() == 0 && len(p) >= len(b.buf) { + // Large write, empty buffer. + // Write directly from p to avoid copy. + n, b.err = b.wr.Write(p); + nn += n; + p = p[n:len(p)]; + if b.err != nil { + break; + } + continue; + } if n > len(p) { n = len(p) } @@ -416,3 +469,14 @@ func (b *BufWrite) WriteByte(c byte) *os.Error { return nil } +// buffered input and output + +type BufReadWrite struct { + *BufRead; + *BufWrite; +} + +func NewBufReadWrite(r *BufRead, w *BufWrite) *BufReadWrite { + return &BufReadWrite{r, w} +} + |