Skip to content

Commit 99df54f

Browse files
martischbradfitz
authored andcommitted
bytes: encode size of rune read by ReadRune into lastRead to speed up UnreadRune
In ReadRune store the size of the rune that was read into lastRead to avoid the need to call DecodeRuneLast in UnreadRune. fmt: name old time/op new time/op delta ScanInts-4 481µs ± 4% 458µs ± 3% -4.64% (p=0.000 n=20+20) Change-Id: I500848e663a975f426402a4b3d27a541e5cac06c Reviewed-on: https://go-review.googlesource.com/28817 Reviewed-by: Russ Cox <[email protected]> Run-TryBot: Russ Cox <[email protected]> Run-TryBot: Martin Möhrmann <[email protected]> TryBot-Result: Gobot Gobot <[email protected]>
1 parent 1e775fe commit 99df54f

File tree

1 file changed

+16
-12
lines changed

1 file changed

+16
-12
lines changed

src/bytes/buffer.go

+16-12
Original file line numberDiff line numberDiff line change
@@ -22,14 +22,18 @@ type Buffer struct {
2222
}
2323

2424
// The readOp constants describe the last action performed on
25-
// the buffer, so that UnreadRune and UnreadByte can
26-
// check for invalid usage.
25+
// the buffer, so that UnreadRune and UnreadByte can check for
26+
// invalid usage. opReadRuneX constants are choosen such that
27+
// converted to int they correspond to the rune size that was read.
2728
type readOp int
2829

2930
const (
30-
opInvalid readOp = iota // Non-read operation.
31-
opReadRune // Read rune.
32-
opRead // Any other read operation.
31+
opRead readOp = -1 // Any other read operation.
32+
opInvalid = 0 // Non-read operation.
33+
opReadRune1 = 1 // Read rune of size 1.
34+
opReadRune2 = 2 // Read rune of size 2.
35+
opReadRune3 = 3 // Read rune of size 3.
36+
opReadRune4 = 4 // Read rune of size 4.
3337
)
3438

3539
// ErrTooLarge is passed to panic if memory cannot be allocated to store data in a buffer.
@@ -319,14 +323,15 @@ func (b *Buffer) ReadRune() (r rune, size int, err error) {
319323
b.Truncate(0)
320324
return 0, 0, io.EOF
321325
}
322-
b.lastRead = opReadRune
323326
c := b.buf[b.off]
324327
if c < utf8.RuneSelf {
325328
b.off++
329+
b.lastRead = opReadRune1
326330
return rune(c), 1, nil
327331
}
328332
r, n := utf8.DecodeRune(b.buf[b.off:])
329333
b.off += n
334+
b.lastRead = readOp(n)
330335
return r, n, nil
331336
}
332337

@@ -336,22 +341,21 @@ func (b *Buffer) ReadRune() (r rune, size int, err error) {
336341
// it is stricter than UnreadByte, which will unread the last byte
337342
// from any read operation.)
338343
func (b *Buffer) UnreadRune() error {
339-
if b.lastRead != opReadRune {
344+
if b.lastRead <= opInvalid {
340345
return errors.New("bytes.Buffer: UnreadRune: previous operation was not ReadRune")
341346
}
342-
b.lastRead = opInvalid
343-
if b.off > 0 {
344-
_, n := utf8.DecodeLastRune(b.buf[0:b.off])
345-
b.off -= n
347+
if b.off >= int(b.lastRead) {
348+
b.off -= int(b.lastRead)
346349
}
350+
b.lastRead = opInvalid
347351
return nil
348352
}
349353

350354
// UnreadByte unreads the last byte returned by the most recent
351355
// read operation. If write has happened since the last read, UnreadByte
352356
// returns an error.
353357
func (b *Buffer) UnreadByte() error {
354-
if b.lastRead != opReadRune && b.lastRead != opRead {
358+
if b.lastRead == opInvalid {
355359
return errors.New("bytes.Buffer: UnreadByte: previous operation was not a read")
356360
}
357361
b.lastRead = opInvalid

0 commit comments

Comments
 (0)