-
Notifications
You must be signed in to change notification settings - Fork 9
/
bpool.go
81 lines (70 loc) · 1.58 KB
/
bpool.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
package protocol
import (
"io"
"math/bits"
"sync"
)
var (
// Verify ByteBuffer implements io.Writer.
_ io.Writer = &ByteBuffer{}
)
// ByteBuffer implements a simple byte buffer.
type ByteBuffer struct {
// B is the underlying byte slice.
B []byte
}
// Reset resets bb.
func (bb *ByteBuffer) Reset() {
bb.B = bb.B[:0]
}
// Write appends p to bb.
func (bb *ByteBuffer) Write(p []byte) (int, error) {
bb.B = append(bb.B, p...)
return len(p), nil
}
// pools contain pools for byte slices of various capacities.
var pools [19]sync.Pool
// maxBufferLength is the maximum length of an element that can be added to the Pool.
const maxBufferLength = 262144 // 2^18
// Log of base two, round up (for v > 0).
func nextLogBase2(v uint32) uint32 {
return uint32(bits.Len32(v - 1))
}
// Log of base two, round down (for v > 0)
func prevLogBase2(num uint32) uint32 {
next := nextLogBase2(num)
if num == (1 << next) {
return next
}
return next - 1
}
// getByteBuffer returns byte buffer with the given capacity.
func getByteBuffer(length int) *ByteBuffer {
if length == 0 {
return &ByteBuffer{
B: nil,
}
}
if length > maxBufferLength {
return &ByteBuffer{
B: make([]byte, 0, length),
}
}
idx := nextLogBase2(uint32(length))
if v := pools[idx].Get(); v != nil {
return v.(*ByteBuffer)
}
return &ByteBuffer{
B: make([]byte, 0, 1<<idx),
}
}
// putByteBuffer returns bb to the pool.
func putByteBuffer(bb *ByteBuffer) {
capacity := cap(bb.B)
if capacity == 0 || capacity > maxBufferLength {
return // drop.
}
idx := prevLogBase2(uint32(capacity))
bb.Reset()
pools[idx].Put(bb)
}