/
buffer.go
93 lines (78 loc) · 2.29 KB
/
buffer.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
// Copyright 2022 The Cockroach Authors.
//
// Use of this software is governed by the Business Source License
// included in the file licenses/BSL.txt.
//
// As of the Change Date specified in that file, in accordance with
// the Business Source License, use of this software will be governed
// by the Apache License, Version 2.0, included in the file
// licenses/APL.txt.
package tokenizer
import "unicode/utf8"
// buffer, is very much like bytes.Buffer, but is simpler. In particular,
// because we don't need to support entirety of bytes.Buffer interface, the
// functions (s.a. AppendByte) are simpler, and as a result can be inlined.
type buffer struct {
buf []byte // We maintain an invariant that len(buf) == cap(buf).
l int // Current length.
}
// Reset resets the buffer for next use.
func (b *buffer) Reset() {
b.l = 0
}
// Bytes returns byte slice previously written.
// NB: We do not make a copy here. Returned buffer valid
// until next call to buffer.
func (b *buffer) Bytes() []byte {
return b.buf[:b.l]
}
// AppendByte appends byte to this buffer
func (b *buffer) AppendByte(c byte) {
if cap(b.buf)-b.l <= 1 {
b.buf = grow(b.buf, 1)
}
b.buf[b.l] = c
b.l++
}
// Append appends buf to this buffer.
func (b *buffer) Append(buf []byte) {
if cap(b.buf)-b.l <= len(buf) {
b.buf = grow(b.buf, len(buf))
}
copy(b.buf[b.l:], buf)
b.l += len(buf)
}
// AppendRune writes rune to this buffer.
func (b *buffer) AppendRune(r rune) {
// Compare as uint32 to correctly handle negative runes.
if uint32(r) < utf8.RuneSelf {
b.AppendByte(byte(r))
return
}
if cap(b.buf)-b.l <= utf8.UTFMax {
b.buf = grow(b.buf, utf8.UTFMax)
}
n := utf8.EncodeRune(b.buf[b.l:b.l+utf8.UTFMax], r)
b.l += n
}
// smallBufferSize is an initial allocation minimal capacity.
const smallBufferSize = 64
// grow increases capacity of buf by at least n, and returns new buffer,
// containing a copy of buf.
func grow(buf []byte, n int) []byte {
if n < smallBufferSize {
n = smallBufferSize
}
if buf == nil {
return make([]byte, n)
}
// Cribbed from bytes.Buffer.
c := len(buf) + n // ensure enough space for n elements
if c < 2*cap(buf) {
c = 2 * cap(buf)
}
nb := append([]byte(nil), make([]byte, c)...)
copy(nb, buf)
// Make whole cap available since append may produce larger slice.
return nb[:cap(nb)]
}