summaryrefslogtreecommitdiff
path: root/vendor/github.com/ulule/limiter/v3/internal/bytebuffer/pool.go
blob: 5e761ad13da2aaffcb62f61355b1ca8ff92a72ff (plain)
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
package bytebuffer

import (
	"sync"
	"unsafe"
)

// ByteBuffer is a wrapper around a slice to reduce memory allocation while handling blob of data.
type ByteBuffer struct {
	blob []byte
}

// New creates a new ByteBuffer instance.
func New() *ByteBuffer {
	entry := bufferPool.Get().(*ByteBuffer)
	entry.blob = entry.blob[:0]
	return entry
}

// Bytes returns the content buffer.
func (buffer *ByteBuffer) Bytes() []byte {
	return buffer.blob
}

// String returns the content buffer.
func (buffer *ByteBuffer) String() string {
	// Copied from strings.(*Builder).String
	return *(*string)(unsafe.Pointer(&buffer.blob)) // nolint: gosec
}

// Concat appends given arguments to blob content
func (buffer *ByteBuffer) Concat(args ...string) {
	for i := range args {
		buffer.blob = append(buffer.blob, args[i]...)
	}
}

// Close recycles underlying resources of encoder.
func (buffer *ByteBuffer) Close() {
	// Proper usage of a sync.Pool requires each entry to have approximately
	// the same memory cost. To obtain this property when the stored type
	// contains a variably-sized buffer, we add a hard limit on the maximum buffer
	// to place back in the pool.
	//
	// See https://golang.org/issue/23199
	if buffer != nil && cap(buffer.blob) < (1<<16) {
		bufferPool.Put(buffer)
	}
}

// A byte buffer pool to reduce memory allocation pressure.
var bufferPool = &sync.Pool{
	New: func() interface{} {
		return &ByteBuffer{
			blob: make([]byte, 0, 1024),
		}
	},
}