aboutsummaryrefslogtreecommitdiff
path: root/vendor/github.com/jackc/pgx/v5/internal/iobufpool/iobufpool.go
blob: 89e0c22738d7db00c8866d9931908bc6cd0dc147 (plain) (blame)
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
// Package iobufpool implements a global segregated-fit pool of buffers for IO.
//
// It uses *[]byte instead of []byte to avoid the sync.Pool allocation with Put. Unfortunately, using a pointer to avoid
// an allocation is purposely not documented. https://github.com/golang/go/issues/16323
package iobufpool

import "sync"

const minPoolExpOf2 = 8

var pools [18]*sync.Pool

func init() {
	for i := range pools {
		bufLen := 1 << (minPoolExpOf2 + i)
		pools[i] = &sync.Pool{
			New: func() any {
				buf := make([]byte, bufLen)
				return &buf
			},
		}
	}
}

// Get gets a []byte of len size with cap <= size*2.
func Get(size int) *[]byte {
	i := getPoolIdx(size)
	if i >= len(pools) {
		buf := make([]byte, size)
		return &buf
	}

	ptrBuf := (pools[i].Get().(*[]byte))
	*ptrBuf = (*ptrBuf)[:size]

	return ptrBuf
}

func getPoolIdx(size int) int {
	size--
	size >>= minPoolExpOf2
	i := 0
	for size > 0 {
		size >>= 1
		i++
	}

	return i
}

// Put returns buf to the pool.
func Put(buf *[]byte) {
	i := putPoolIdx(cap(*buf))
	if i < 0 {
		return
	}

	pools[i].Put(buf)
}

func putPoolIdx(size int) int {
	minPoolSize := 1 << minPoolExpOf2
	for i := range pools {
		if size == minPoolSize<<i {
			return i
		}
	}

	return -1
}