github.com/ronaksoft/rony@v0.16.26-0.20230807065236-1743dbfe6959/pools/bytes.go (about) 1 package pools 2 3 import ( 4 "sync" 5 6 "github.com/ronaksoft/rony/pools/buf" 7 ) 8 9 /* 10 Creation Time: 2020 - Mar - 24 11 Created by: (ehsan) 12 Maintainers: 13 1. Ehsan N. Moosa (E2) 14 Auditor: Ehsan N. Moosa (E2) 15 Copyright Ronak Software Group 2020 16 */ 17 18 var Bytes = NewByteSlice(32, 64<<10) 19 var Buffer = buf.NewBytesPool(4, 64<<10) 20 21 const ( 22 bitSize = 32 << (^uint(0) >> 63) 23 maxintHeadBit = 1 << (bitSize - 2) 24 ) 25 26 // byteSlicePool contains logic of reusing objects distinguishable by size in generic 27 // way. 28 type byteSlicePool struct { 29 pool map[int]*sync.Pool 30 } 31 32 // NewByteSlice creates new byteSlicePool that reuses objects which size is in logarithmic range 33 // [min, max]. 34 // 35 // Note that it is a shortcut for Custom() constructor with Options provided by 36 // WithLogSizeMapping() and WithLogSizeRange(min, max) calls. 37 func NewByteSlice(min, max int) *byteSlicePool { 38 p := &byteSlicePool{ 39 pool: make(map[int]*sync.Pool), 40 } 41 logarithmicRange( 42 min, max, 43 func(n int) { 44 p.pool[n] = &sync.Pool{} 45 }, 46 ) 47 48 return p 49 } 50 51 // Get returns probably reused slice of bytes with at least capacity of c and 52 // exactly len of n. 53 func (p *byteSlicePool) Get(n, c int) []byte { 54 if n > c { 55 panic("requested length is greater than capacity") 56 } 57 58 size := ceilToPowerOfTwo(c) 59 if pool := p.pool[size]; pool != nil { 60 v := pool.Get() 61 if v != nil { 62 bts := v.([]byte) 63 bts = bts[:n] 64 65 return bts 66 } else { 67 return make([]byte, n, size) 68 } 69 } 70 71 return make([]byte, n, c) 72 } 73 74 // Put returns given slice to reuse pool. 75 // It does not reuse bytes whose size is not power of two or is out of pool 76 // min/max range. 77 func (p *byteSlicePool) Put(bts []byte) { 78 if pool := p.pool[cap(bts)]; pool != nil { 79 pool.Put(bts) 80 } 81 } 82 83 // GetCap returns probably reused slice of bytes with at least capacity of n. 84 func (p *byteSlicePool) GetCap(c int) []byte { 85 return p.Get(0, c) 86 } 87 88 // GetLen returns probably reused slice of bytes with at least capacity of n 89 // and exactly len of n. 90 func (p *byteSlicePool) GetLen(n int) []byte { 91 return p.Get(n, n) 92 } 93 94 // logarithmicRange iterates from ceil to power of two min to max, 95 // calling cb on each iteration. 96 func logarithmicRange(min, max int, cb func(int)) { 97 if min == 0 { 98 min = 1 99 } 100 for n := ceilToPowerOfTwo(min); n <= max; n <<= 1 { 101 cb(n) 102 } 103 } 104 105 // ceilToPowerOfTwo returns the least power of two integer value greater than 106 // or equal to n. 107 func ceilToPowerOfTwo(n int) int { 108 if n&maxintHeadBit != 0 && n > maxintHeadBit { 109 panic("argument is too large") 110 } 111 if n <= 2 { 112 return n 113 } 114 n-- 115 n = fillBits(n) 116 n++ 117 118 return n 119 } 120 121 func fillBits(n int) int { 122 n |= n >> 1 123 n |= n >> 2 124 n |= n >> 4 125 n |= n >> 8 126 n |= n >> 16 127 n |= n >> 32 128 129 return n 130 }