// Package pool provides a sync.Pool equivalent that buckets incoming // requests to one of 32 sub-pools, one for each power of 2, 0-32. // // import (pool "github.com/libp2p/go-buffer-pool") // var p pool.BufferPool // // small := make([]byte, 1024) // large := make([]byte, 4194304) // p.Put(small) // p.Put(large) // // small2 := p.Get(1024) // large2 := p.Get(4194304) // fmt.Println("small2 len:", len(small2)) // fmt.Println("large2 len:", len(large2)) // // // Output: // // small2 len: 1024 // // large2 len: 4194304 //
package pool import ( ) // GlobalPool is a static Pool for reusing byteslices of various sizes. var GlobalPool = new(BufferPool) // MaxLength is the maximum length of an element that can be added to the Pool. const MaxLength = math.MaxInt32 // BufferPool is a pool to handle cases of reusing elements of varying sizes. It // maintains 32 internal pools, for each power of 2 in 0-32. // // You should generally just call the package level Get and Put methods or use // the GlobalPool BufferPool instead of constructing your own. // // You MUST NOT copy Pool after using. type BufferPool struct { pools [32]sync.Pool // a list of singlePools ptrs sync.Pool } type bufp struct { buf []byte } // Get retrieves a buffer of the appropriate length from the buffer pool or // allocates a new one. Get may choose to ignore the pool and treat it as empty. // Callers should not assume any relation between values passed to Put and the // values returned by Get. // // If no suitable buffer exists in the pool, Get creates one. func ( *BufferPool) ( int) []byte { if == 0 { return nil } // Calling this function with a negative length is invalid. // make will panic if length is negative, so we don't have to. if > MaxLength || < 0 { return make([]byte, ) } := nextLogBase2(uint32()) if := .pools[].Get(); != nil { := .(*bufp) := .buf[:uint32()] .buf = nil .ptrs.Put() return } return make([]byte, 1<<)[:uint32()] } // Put adds x to the pool. func ( *BufferPool) ( []byte) { := cap() if == 0 || > MaxLength { return // drop it } := prevLogBase2(uint32()) var *bufp if := .ptrs.Get(); != nil { = .(*bufp) } else { = new(bufp) } .buf = .pools[].Put() } // Get retrieves a buffer of the appropriate length from the global buffer pool // (or allocates a new one). func ( int) []byte { return GlobalPool.Get() } // Put returns a buffer to the global buffer pool. func ( []byte) { GlobalPool.Put() } // Log of base two, round up (for v > 0). func nextLogBase2( uint32) uint32 { return uint32(bits.Len32( - 1)) } // Log of base two, round down (for v > 0) func prevLogBase2( uint32) uint32 { := nextLogBase2() if == (1 << uint32()) { return } return - 1 }