github.com/influx6/npkg@v0.8.8/nbytes/pbytes/pbytes.go (about) 1 package pbytes 2 3 import ( 4 "bytes" 5 "sync" 6 ) 7 8 type bufferHandler interface { 9 Put(*Buffer) 10 } 11 12 //************************************************************************ 13 // Buffer 14 //************************************************************************ 15 16 // Buffer holds a allocated memory which will be used by 17 // receiver and discard once done with byte slice to 18 // allow re-use. 19 type Buffer struct { 20 bit int 21 Data []byte 22 pool bufferHandler 23 } 24 25 func (b *Buffer) Discard() { 26 b.pool.Put(b) 27 } 28 29 //************************************************************************ 30 // BitsBoot 31 //************************************************************************ 32 33 type bitsBoot struct { 34 max int 35 pl sync.Mutex 36 free []*Buffer 37 } 38 39 func (b *bitsBoot) Put(br *Buffer) { 40 b.pl.Lock() 41 defer b.pl.Unlock() 42 43 br.pool = nil 44 b.free = append(b.free, br) 45 } 46 47 func (b *bitsBoot) Get(n int) *Buffer { 48 b.pl.Lock() 49 defer b.pl.Unlock() 50 51 free := len(b.free) 52 if free == 0 { 53 mem := make([]byte, b.max) 54 br := &Buffer{ 55 pool: b, 56 Data: mem[:n], 57 } 58 return br 59 } 60 61 item := b.free[0] 62 item.pool = b 63 64 if free == 0 { 65 b.free = b.free[:0] 66 return item 67 } 68 69 b.free = b.free[1:] 70 return item 71 } 72 73 // BitsBoot implements a custom pool for issue Buffers, 74 // but uses a internal []Buffer slice instead of the sync.Pool. 75 type BitsBoot struct { 76 distance int 77 pl sync.Mutex 78 pools []*bitsBoot 79 indexes map[int]int 80 } 81 82 // NewBitsBoot returns a new instance of a BitsBoot which returns 83 // allocated and managed Buffer. 84 func NewBitsBoot(distance int, initialAmount int) *BitsBoot { 85 initials := make([]*bitsBoot, 0) 86 indexes := make(map[int]int) 87 88 for i := 1; i <= initialAmount; i++ { 89 sizeDist := distance * i 90 91 indexes[sizeDist] = len(initials) 92 initials = append(initials, &bitsBoot{ 93 max: sizeDist, 94 free: make([]*Buffer, 0, 100), 95 }) 96 } 97 98 return &BitsBoot{ 99 indexes: indexes, 100 distance: distance, 101 pools: initials, 102 } 103 } 104 105 // Put returns the []byte by using the capacity of the slice to find its pool. 106 func (bp *BitsBoot) Put(bu *Buffer) { 107 bu.pool = nil 108 109 bp.pl.Lock() 110 index, ok := bp.indexes[bu.bit] 111 if !ok { 112 bp.pl.Unlock() 113 return 114 } 115 pool := bp.pools[index] 116 bp.pl.Unlock() 117 118 pool.Put(bu) 119 } 120 121 // Get returns a new or existing []byte from it's internal size RangePool. 122 // It gets a RangePool or creates one if non exists for the size + it's distance value 123 // then gets a []byte from that RangePool. 124 func (bp *BitsBoot) Get(size int) *Buffer { 125 bp.pl.Lock() 126 127 if poolIndex, ok := bp.indexes[size]; ok { 128 pool := bp.pools[poolIndex] 129 bp.pl.Unlock() 130 131 return pool.Get(size) 132 } 133 134 // loop through RangePool till we find the distance where size is no more 135 // greater, which means that pool will be suitable as the size provider for 136 // this size need. 137 for _, pool := range bp.pools { 138 if pool.max < size { 139 continue 140 } 141 142 bp.pl.Unlock() 143 return pool.Get(size) 144 } 145 146 // We dont have any pool within size range, so create new RangePool suited for this size. 147 newDistance := ((size / bp.distance) + 1) * bp.distance 148 newPool := &bitsBoot{ 149 max: newDistance, 150 free: make([]*Buffer, 0, 100), 151 } 152 153 bp.indexes[newDistance] = len(bp.pools) 154 bp.pools = append(bp.pools, newPool) 155 bp.pl.Unlock() 156 157 return newPool.Get(size) 158 } 159 160 //************************************************************************ 161 // BitsBoot 162 //************************************************************************ 163 164 type bitsPool struct { 165 max int 166 pool *sync.Pool 167 source bufferHandler 168 } 169 170 func (b *bitsPool) Put(bu *Buffer) { 171 bu.pool = nil 172 b.pool.Put(bu) 173 } 174 175 func (b *bitsPool) Get(n int) *Buffer { 176 br := b.pool.Get().(*Buffer) 177 br.Data = br.Data[:n] 178 br.pool = b 179 return br 180 } 181 182 // BitsPool implements a custom pool for issue Buffers, 183 // using the sync.Pool. 184 type BitsPool struct { 185 distance int 186 pl sync.Mutex 187 pools []*bitsPool 188 indexes map[int]int 189 } 190 191 // NewBitsPool returns a new instance of a BitsPool which returns 192 // allocated and managed Buffer. 193 func NewBitsPool(distance int, initialAmount int) *BitsPool { 194 initials := make([]*bitsPool, 0) 195 indexes := make(map[int]int) 196 197 for i := 1; i <= initialAmount; i++ { 198 sizeDist := distance * i 199 200 indexes[sizeDist] = len(initials) 201 initials = append(initials, &bitsPool{ 202 max: sizeDist, 203 pool: &sync.Pool{ 204 New: func() interface{} { 205 return &Buffer{ 206 bit: sizeDist, 207 Data: make([]byte, sizeDist), 208 } 209 }, 210 }, 211 }) 212 } 213 214 return &BitsPool{ 215 indexes: indexes, 216 distance: distance, 217 pools: initials, 218 } 219 } 220 221 // Get returns a new or existing []byte from it's internal size RangePool. 222 // It gets a RangePool or creates one if non exists for the size + it's distance value 223 // then gets a []byte from that RangePool. 224 func (bp *BitsPool) Get(size int) *Buffer { 225 bp.pl.Lock() 226 defer bp.pl.Unlock() 227 228 if poolIndex, ok := bp.indexes[size]; ok { 229 pool := bp.pools[poolIndex] 230 return pool.Get(size) 231 } 232 233 // loop through RangePool till we find the distance where size is no more 234 // greater, which means that pool will be suitable as the size provider for 235 // this size need. 236 for _, pool := range bp.pools { 237 if pool.max < size { 238 continue 239 } 240 241 return pool.Get(size) 242 } 243 244 // We dont have any pool within size range, so create new RangePool suited for this size. 245 newDistance := ((size / bp.distance) + 1) * bp.distance 246 newPool := &bitsPool{ 247 max: newDistance, 248 pool: &sync.Pool{ 249 New: func() interface{} { 250 return &Buffer{ 251 bit: newDistance, 252 Data: make([]byte, newDistance), 253 } 254 }, 255 }, 256 } 257 258 bp.indexes[newDistance] = len(bp.pools) 259 bp.pools = append(bp.pools, newPool) 260 return newPool.Get(size) 261 } 262 263 //************************************************************************ 264 // BytesPool 265 //************************************************************************ 266 267 type rangePool struct { 268 max int 269 pool *sync.Pool 270 } 271 272 // BytesPool exists to contain multiple RangePool that lies within giving distance range. 273 // It creates a internal array of BytesPool which are distanced between each other by 274 // provided distance. Whenever giving call to get a []byte for a giving size is 275 // within existing pool distances, it calls that RangePool responsible for that size and 276 // retrieves giving []byte from that pool. If no range as such exists, it creates 277 // a new RangePool for the size + BytesPool.Distance set an instantiation, then retrieves 278 // a []byte from that. 279 type BytesPool struct { 280 distance int 281 pl sync.Mutex 282 pools []*rangePool 283 indexes map[int]int 284 } 285 286 // NewBytesPool returns a new instance of a BytesPool with size distance used for new npools 287 // and creates as many as the initialAmount of RangePools internally to service those size 288 // requests. 289 func NewBytesPool(distance int, initialAmount int) *BytesPool { 290 initials := make([]*rangePool, 0) 291 indexes := make(map[int]int) 292 293 for i := 1; i <= initialAmount; i++ { 294 sizeDist := distance * i 295 296 indexes[sizeDist] = len(initials) 297 initials = append(initials, &rangePool{ 298 max: sizeDist, 299 pool: &sync.Pool{ 300 New: func() interface{} { 301 return bytes.NewBuffer(make([]byte, 0, sizeDist)) 302 }, 303 }, 304 }) 305 } 306 307 return &BytesPool{ 308 distance: distance, 309 pools: initials, 310 indexes: indexes, 311 } 312 } 313 314 // Put returns the []byte by using the capacity of the slice to find its pool. 315 func (bp *BytesPool) Put(bu *bytes.Buffer) { 316 bp.pl.Lock() 317 defer bp.pl.Unlock() 318 319 if index, ok := bp.indexes[bu.Cap()]; ok { 320 pool := bp.pools[index] 321 pool.pool.Put(bu) 322 } 323 } 324 325 // Get returns a new or existing []byte from it's internal size RangePool. 326 // It gets a RangePool or creates one if non exists for the size + it's distance value 327 // then gets a []byte from that RangePool. 328 func (bp *BytesPool) Get(size int) *bytes.Buffer { 329 bp.pl.Lock() 330 defer bp.pl.Unlock() 331 332 // loop through RangePool till we find the distance where size is no more 333 // greater, which means that pool will be suitable as the size provider for 334 // this size need. 335 for _, pool := range bp.pools { 336 if pool.max < size { 337 continue 338 } 339 340 return pool.pool.Get().(*bytes.Buffer) 341 } 342 343 // We dont have any pool within size range, so create new RangePool suited for this size. 344 newDistance := ((size / bp.distance) + 1) * bp.distance 345 newPool := &rangePool{ 346 max: newDistance, 347 pool: &sync.Pool{ 348 New: func() interface{} { 349 return bytes.NewBuffer(make([]byte, 0, newDistance)) 350 }, 351 }, 352 } 353 354 bp.indexes[newDistance] = len(bp.pools) 355 bp.pools = append(bp.pools, newPool) 356 357 return newPool.pool.Get().(*bytes.Buffer) 358 } 359 360 //************************************************************************ 361 // BytePool 362 //************************************************************************ 363 364 // BytePool implements a leaky pool of []byte in the form of a bounded 365 // channel. 366 type BytePool struct { 367 c chan []byte 368 w int 369 } 370 371 // NewBytePool creates a new BytePool bounded to the given maxSize, with new 372 // byte arrays sized based on width. 373 func NewBytePool(maxSize int, width int) (bp *BytePool) { 374 return &BytePool{ 375 c: make(chan []byte, maxSize), 376 w: width, 377 } 378 } 379 380 // Get gets a []byte from the BytePool, or creates a new one if none are 381 // available in the pool. 382 func (bp *BytePool) Get() (b []byte) { 383 select { 384 case b = <-bp.c: 385 // reuse existing buffer 386 default: 387 // create new buffer 388 b = make([]byte, bp.w) 389 } 390 return 391 } 392 393 // Put returns the given Buffer to the BytePool. 394 func (bp *BytePool) Put(b []byte) { 395 select { 396 case bp.c <- b: 397 // buffer went back into pool 398 default: 399 // buffer didn't go back into pool, just discard 400 } 401 } 402 403 // Width returns the width of the byte arrays in this pool. 404 func (bp *BytePool) Width() (n int) { 405 return bp.w 406 }