func (tp *BytePool) Drain() {
	for o := 0; o < len(tp.list_of_pools); o++ {
		p := &tp.list_of_pools[o]
		p.mu.Lock()
		p.list = make([][]byte, 0, cap(p.list)/2)
		p.mu.Unlock()
	}
}
Drain removes all items from the pool and make them availabe for garbage
collection.
package bytepool
import (
	"math"
	"sync"
	"time"
)
type pool struct {
	list [][]byte
	mu   sync.Mutex
}
type BytePool struct {
	list_of_pools []pool
	drainTicker   *time.Ticker
	maxSize       int
}
func (tp *BytePool) Init(drainPeriod time.Duration, maxSize uint32) {
	maxSizeLog := log2Ceil(maxSize)
	tp.maxSize = (1 << maxSizeLog) - 1
	if tp.maxSize <= 0 {
		tp.maxSize = math.MaxInt32
		maxSizeLog = log2Ceil(math.MaxInt32)
	}
	tp.list_of_pools = make([]pool, maxSizeLog+1)
	if drainPeriod > 0 {
		tp.drainTicker = time.NewTicker(drainPeriod)
		go func() {
			for _ = range tp.drainTicker.C {
				tp.Drain()
			}
		}()
	}
}
func (tp *BytePool) Put(el []byte) {
	if cap(el) < 1 || cap(el) > tp.maxSize {
		return
	}
	el = el[:cap(el)]
	o := log2Floor(uint32(cap(el)))
	p := &tp.list_of_pools[o]
	p.mu.Lock()
	p.list = append(p.list, el)
	p.mu.Unlock()
}
func (tp *BytePool) Get(size int) []byte {
	if size < 1 || size > tp.maxSize {
		return make([]byte, size)
	}
	var x []byte
	o := log2Ceil(uint32(size))
	p := &tp.list_of_pools[o]
	p.mu.Lock()
	if n := len(p.list); n > 0 {
		x = p.list[n-1]
		p.list[n-1] = nil
		p.list = p.list[:n-1]
	}
	p.mu.Unlock()
	if x == nil {
		x = make([]byte, 1<<o)
	}
	return x[:size]
}