-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathbuffer.go
More file actions
119 lines (99 loc) · 3.13 KB
/
buffer.go
File metadata and controls
119 lines (99 loc) · 3.13 KB
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
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
package devlog
import (
"fmt"
"strconv"
"sync"
"time"
)
type byteBuffer []byte
func (buffer *byteBuffer) write(bytes []byte) {
*buffer = append(*buffer, bytes...)
}
// Always returns nil error (still has error in signature, to satisfy [io.Writer] interface).
func (buffer *byteBuffer) Write(bytes []byte) (bytesWritten int, err error) {
*buffer = append(*buffer, bytes...)
return len(bytes), nil
}
func (buffer *byteBuffer) writeString(str string) {
*buffer = append(*buffer, str...)
}
func (buffer *byteBuffer) writeByte(b byte) {
*buffer = append(*buffer, b)
}
func (buffer *byteBuffer) writeDecimal(decimal int) {
*buffer = strconv.AppendInt(*buffer, int64(decimal), 10)
}
func (buffer *byteBuffer) writeIndent(indent int) {
for i := 0; i <= indent; i++ {
buffer.writeString(" ")
}
}
func (buffer *byteBuffer) writeAny(value any) {
*buffer = fmt.Append(*buffer, value)
}
// Adapted from standard library log package:
// https://github.com/golang/go/blob/ab5bd15941f3cea3695338756d0b8be0ef2321fb/src/log/log.go#L114
func (buffer *byteBuffer) writeTime(t time.Time) {
hour, minute, second := t.Clock()
buffer.writeFixedWidthDecimal(hour, 2)
buffer.writeByte(':')
buffer.writeFixedWidthDecimal(minute, 2)
buffer.writeByte(':')
buffer.writeFixedWidthDecimal(second, 2)
}
// Adapted from standard library log package:
// https://github.com/golang/go/blob/ab5bd15941f3cea3695338756d0b8be0ef2321fb/src/log/log.go#L114
func (buffer *byteBuffer) writeDateTime(t time.Time) {
year, month, day := t.Date()
buffer.writeFixedWidthDecimal(year, 4)
buffer.writeByte('-')
buffer.writeFixedWidthDecimal(int(month), 2)
buffer.writeByte('-')
buffer.writeFixedWidthDecimal(day, 2)
buffer.writeByte(' ')
buffer.writeTime(t)
}
// Adapted from standard library log package:
// https://github.com/golang/go/blob/ab5bd15941f3cea3695338756d0b8be0ef2321fb/src/log/log.go#L93
func (buffer *byteBuffer) writeFixedWidthDecimal(decimal int, width int) {
var bytes [20]byte
index := len(bytes) - 1
for decimal >= 10 || width > 1 {
width--
remainder := decimal / 10
bytes[index] = byte('0' + decimal - remainder*10)
index--
decimal = remainder
}
bytes[index] = byte('0' + decimal)
*buffer = append(*buffer, bytes[index:]...)
}
func (buffer *byteBuffer) join(other byteBuffer) {
*buffer = append(*buffer, other...)
}
func (buffer *byteBuffer) copy() byteBuffer {
oldBuffer := *buffer
newBuffer := make(byteBuffer, len(oldBuffer), cap(oldBuffer))
copy(newBuffer, oldBuffer)
return newBuffer
}
// Inspired by Jonathan Amsterdam's guide to writing structured log handlers:
// https://github.com/golang/example/blob/1d6d2400d4027025cb8edc86a139c9c581d672f7/slog-handler-guide/README.md#speed
var bufferPool = sync.Pool{
New: func() any {
buffer := make(byteBuffer, 0, 1024)
return &buffer
},
}
func newBuffer() *byteBuffer {
//nolint:errcheck // We always pass a *byteBuffer in bufferPool.New
return bufferPool.Get().(*byteBuffer)
}
func (buffer *byteBuffer) free() {
// To reduce peak allocation, return only smaller buffers to the pool.
const maxBufferSize = 16 * 1024
if cap(*buffer) <= maxBufferSize {
*buffer = (*buffer)[:0]
bufferPool.Put(buffer)
}
}