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