forked from mirrors/gotosocial
71 lines
1.2 KiB
Go
71 lines
1.2 KiB
Go
|
// 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
|
||
|
}
|