github.com/clubpay/ronykit/kit@v0.14.4-0.20240515065620-d0dace45cbc7/utils/buf/bytes.go (about) 1 package buf 2 3 import ( 4 "io" 5 "sync" 6 ) 7 8 const ( 9 bitSize = 32 << (^uint(0) >> 63) 10 maxIntHeadBit = 1 << (bitSize - 2) 11 ) 12 13 type Bytes struct { 14 p *BytesPool 15 ri int 16 b []byte 17 } 18 19 func (bb *Bytes) Write(p []byte) (n int, err error) { 20 bb.b = append(bb.b, p...) 21 22 return len(p), nil 23 } 24 25 func (bb *Bytes) Read(p []byte) (n int, err error) { 26 if bb.ri >= len(bb.b)-1 { 27 return 0, io.EOF 28 } 29 n = copy(p, bb.b[bb.ri:]) 30 bb.ri += n 31 32 return n, nil 33 } 34 35 func newBytes(p *BytesPool, n, c int) *Bytes { 36 if n > c { 37 panic("requested length is greater than capacity") 38 } 39 40 return &Bytes{p: p, b: make([]byte, n, c)} 41 } 42 43 func (bb *Bytes) Reset() { 44 bb.ri = 0 45 bb.b = bb.b[:bb.ri] 46 } 47 48 func (bb *Bytes) Bytes() *[]byte { 49 return &bb.b 50 } 51 52 func (bb *Bytes) SetBytes(b *[]byte) { 53 if b == nil { 54 return 55 } 56 bb.b = *b 57 } 58 59 func (bb *Bytes) Fill(data []byte, start, end int) { 60 copy(bb.b[start:end], data) 61 } 62 63 func (bb *Bytes) CopyFromWithOffset(data []byte, offset int) { 64 copy(bb.b[offset:], data) 65 } 66 67 func (bb *Bytes) CopyFrom(data []byte) { 68 copy(bb.b, data) 69 } 70 71 func (bb *Bytes) CopyTo(data []byte) []byte { 72 copy(data, bb.b) 73 74 return data 75 } 76 77 func (bb *Bytes) AppendFrom(data []byte) { 78 bb.b = append(bb.b, data...) 79 } 80 81 func (bb *Bytes) AppendTo(data []byte) []byte { 82 data = append(data, bb.b...) 83 84 return data 85 } 86 87 func (bb *Bytes) AppendByte(b byte) { 88 bb.b = append(bb.b, b) 89 } 90 91 func (bb *Bytes) AppendString(s string) { 92 bb.b = append(bb.b, s...) 93 } 94 95 func (bb *Bytes) Len() int { 96 return len(bb.b) 97 } 98 99 func (bb Bytes) Cap() int { 100 return cap(bb.b) 101 } 102 103 func (bb *Bytes) Release() { 104 bb.p.put(bb) 105 } 106 107 // BytesPool contains the logic of reusing objects distinguishable by size in generic 108 // way. 109 type BytesPool struct { 110 pool map[int]*sync.Pool 111 } 112 113 var defaultPool = NewBytesPool(32, 1<<20) 114 115 // NewBytesPool creates new BytesPool that reuses objects which size is in logarithmic range 116 // [min, max]. 117 func NewBytesPool(min, max int) *BytesPool { 118 p := &BytesPool{ 119 pool: make(map[int]*sync.Pool), 120 } 121 logarithmicRange(min, max, func(n int) { 122 p.pool[n] = &sync.Pool{} 123 }) 124 125 return p 126 } 127 128 // Get returns probably reused slice of bytes with at least capacity of c and 129 // exactly len of n. 130 func (p *BytesPool) Get(n, c int) *Bytes { 131 if n > c { 132 panic("requested length is greater than capacity") 133 } 134 135 size := ceilToPowerOfTwo(c) 136 if pool := p.pool[size]; pool != nil { 137 v := pool.Get() 138 if v != nil { 139 bb := v.(*Bytes) //nolint:forcetypeassert 140 bb.b = bb.b[:n] 141 142 return bb 143 } else { 144 return newBytes(p, n, size) 145 } 146 } 147 148 return newBytes(p, n, c) 149 } 150 151 func Get(n, c int) *Bytes { 152 return defaultPool.Get(n, c) 153 } 154 155 // GetCap returns probably reused slice of bytes with at least capacity of n. 156 func (p *BytesPool) GetCap(c int) *Bytes { 157 return p.Get(0, c) 158 } 159 160 func GetCap(c int) *Bytes { 161 return defaultPool.Get(0, c) 162 } 163 164 // GetLen returns probably reused slice of bytes with at least capacity of n 165 // and exactly len of n. 166 func (p *BytesPool) GetLen(n int) *Bytes { 167 return p.Get(n, n) 168 } 169 170 func GetLen(n int) *Bytes { 171 return defaultPool.Get(n, n) 172 } 173 174 func FromBytes(in []byte) *Bytes { 175 b := defaultPool.GetCap(len(in)) 176 b.AppendFrom(in) 177 178 return b 179 } 180 181 // put returns given Bytes to reuse pool. 182 // It does not reuse bytes whose size is not power of two or is out of pool 183 // min/max range. 184 func (p *BytesPool) put(bb *Bytes) { 185 if pool := p.pool[cap(bb.b)]; pool != nil { 186 pool.Put(bb) 187 } 188 } 189 190 // logarithmicRange iterates from ceil to power of two min to max, 191 // calling cb on each iteration. 192 func logarithmicRange(min, max int, cb func(int)) { 193 if min == 0 { 194 min = 1 195 } 196 for n := ceilToPowerOfTwo(min); n <= max; n <<= 1 { 197 cb(n) 198 } 199 } 200 201 // ceilToPowerOfTwo returns the least power of two integer value greater than 202 // or equal to n. 203 func ceilToPowerOfTwo(n int) int { 204 if n&maxIntHeadBit != 0 && n > maxIntHeadBit { 205 panic("argument is too large") 206 } 207 if n <= 2 { 208 return n 209 } 210 n-- 211 n = fillBits(n) 212 n++ 213 214 return n 215 } 216 217 func fillBits(n int) int { 218 n |= n >> 1 219 n |= n >> 2 220 n |= n >> 4 221 n |= n >> 8 222 n |= n >> 16 223 n |= n >> 32 224 225 return n 226 }