github.com/xxf098/lite-proxy@v0.15.1-0.20230422081941-12c69f323218/common/pool/alloc.go (about) 1 package pool 2 3 // Inspired by https://github.com/xtaci/smux/blob/master/alloc.go 4 5 import ( 6 "errors" 7 "math/bits" 8 "sync" 9 ) 10 11 var defaultAllocator *Allocator 12 13 func init() { 14 defaultAllocator = NewAllocator() 15 } 16 17 // Allocator for incoming frames, optimized to prevent overwriting after zeroing 18 type Allocator struct { 19 buffers []sync.Pool 20 } 21 22 // NewAllocator initiates a []byte allocator for frames less than 65536 bytes, 23 // the waste(memory fragmentation) of space allocation is guaranteed to be 24 // no more than 50%. 25 func NewAllocator() *Allocator { 26 alloc := new(Allocator) 27 alloc.buffers = make([]sync.Pool, 17) // 1B -> 64K 28 for k := range alloc.buffers { 29 i := k 30 alloc.buffers[k].New = func() interface{} { 31 return make([]byte, 1<<uint32(i)) 32 } 33 } 34 return alloc 35 } 36 37 // Get a []byte from pool with most appropriate cap 38 func (alloc *Allocator) Get(size int) []byte { 39 if size <= 0 || size > 65536 { 40 return nil 41 } 42 43 bits := msb(size) 44 if size == 1<<bits { 45 return alloc.buffers[bits].Get().([]byte)[:size] 46 } 47 48 return alloc.buffers[bits+1].Get().([]byte)[:size] 49 } 50 51 // Put returns a []byte to pool for future use, 52 // which the cap must be exactly 2^n 53 func (alloc *Allocator) Put(buf []byte) error { 54 bits := msb(cap(buf)) 55 if cap(buf) == 0 || cap(buf) > 65536 || cap(buf) != 1<<bits { 56 return errors.New("allocator Put() incorrect buffer size") 57 } 58 59 //lint:ignore SA6002 ignore temporarily 60 alloc.buffers[bits].Put(buf) 61 return nil 62 } 63 64 // msb return the pos of most significant bit 65 func msb(size int) uint16 { 66 return uint16(bits.Len32(uint32(size)) - 1) 67 }