func logarithmicRange(min, max int, cb func(int)) {
	if min == 0 {
		min = 1
	}
	for n := ceilToPowerOfTwo(min); n <= max; n <<= 1 {
		cb(n)
	}
}
logarithmicRange iterates from ceil to power of two min to max,
calling cb on each iteration.
package pools
import (
	"google.golang.org/protobuf/proto"
	"io"
	"sync"
)
var TinyBytes = NewByteSlice(4, 128)
var Bytes = NewByteSlice(32, 64<<10)
var Buffer = NewByteBuffer(4, 64<<10)
const (
	bitSize       = 32 << (^uint(0) >> 63)
	maxintHeadBit = 1 << (bitSize - 2)
)
type byteSlicePool struct {
	pool map[int]*sync.Pool
}
func NewByteSlice(min, max int) *byteSlicePool {
	p := &byteSlicePool{
		pool: make(map[int]*sync.Pool),
	}
	logarithmicRange(min, max, func(n int) {
		p.pool[n] = &sync.Pool{}
	})
	return p
}
func (p *byteSlicePool) Get(n, c int) []byte {
	if n > c {
		panic("requested length is greater than capacity")
	}
	size := ceilToPowerOfTwo(c)
	if pool := p.pool[size]; pool != nil {
		v := pool.Get()
		if v != nil {
			bts := v.([]byte)
			bts = bts[:n]
			return bts
		} else {
			return make([]byte, n, size)
		}
	}
	return make([]byte, n, c)
}
func (p *byteSlicePool) Put(bts []byte) {
	if pool := p.pool[cap(bts)]; pool != nil {
		pool.Put(bts)
	}
}
func (p *byteSlicePool) GetCap(c int) []byte {
	return p.Get(0, c)
}
func (p *byteSlicePool) GetLen(n int) []byte {
	return p.Get(n, n)
}
type ByteBuffer struct {
	ri int
	b  []byte
}
func (bb *ByteBuffer) Read(p []byte) (n int, err error) {
	if bb.ri >= len(bb.b)-1 {
		return 0, io.EOF
	}
	n = copy(p, bb.b[bb.ri:])
	bb.ri += n
	return n, nil
}
func newByteBuffer(n, c int) *ByteBuffer {
	if n > c {
		panic("requested length is greater than capacity")
	}
	return &ByteBuffer{b: make([]byte, n, c)}
}
func (bb *ByteBuffer) Reset() {
	bb.ri = 0
	bb.b = bb.b[:bb.ri]
}
func (bb *ByteBuffer) Bytes() *[]byte {
	return &bb.b
}
func (bb *ByteBuffer) SetBytes(b *[]byte) {
	if b == nil {
		return
	}
	bb.b = *b
}
func (bb *ByteBuffer) Fill(data []byte, start, end int) {
	copy(bb.b[start:end], data)
}
func (bb *ByteBuffer) CopyFromWithOffset(data []byte, offset int) {
	copy(bb.b[offset:], data)
}
func (bb *ByteBuffer) CopyFrom(data []byte) {
	copy(bb.b, data)
}
func (bb *ByteBuffer) CopyTo(data []byte) []byte {
	copy(data, bb.b)
	return data
}
func (bb *ByteBuffer) AppendFrom(data []byte) {
	bb.b = append(bb.b, data...)
}
func (bb *ByteBuffer) AppendTo(data []byte) []byte {
	data = append(data, bb.b...)
	return data
}
func (bb *ByteBuffer) Len() int {
	return len(bb.b)
}
func (bb ByteBuffer) Cap() int {
	return cap(bb.b)
}
type byteBufferPool struct {
	pool map[int]*sync.Pool
}
func NewByteBuffer(min, max int) *byteBufferPool {
	p := &byteBufferPool{
		pool: make(map[int]*sync.Pool),
	}
	logarithmicRange(min, max, func(n int) {
		p.pool[n] = &sync.Pool{}
	})
	return p
}
func (p *byteBufferPool) Get(n, c int) *ByteBuffer {
	if n > c {
		panic("requested length is greater than capacity")
	}
	size := ceilToPowerOfTwo(c)
	if pool := p.pool[size]; pool != nil {
		v := pool.Get()
		if v != nil {
			bb := v.(*ByteBuffer)
			bb.b = bb.b[:n]
			return bb
		} else {
			return newByteBuffer(n, size)
		}
	}
	return newByteBuffer(n, c)
}
func (p *byteBufferPool) Put(bb *ByteBuffer) {
	if pool := p.pool[cap(bb.b)]; pool != nil {
		pool.Put(bb)
	}
}
func (p *byteBufferPool) GetCap(c int) *ByteBuffer {
	return p.Get(0, c)
}
func (p *byteBufferPool) GetLen(n int) *ByteBuffer {
	return p.Get(n, n)
}
func (p *byteBufferPool) FromProto(m proto.Message) *ByteBuffer {
	mo := proto.MarshalOptions{UseCachedSize: true}
	buf := p.GetCap(mo.Size(m))
	bb, _ := mo.MarshalAppend(*buf.Bytes(), m)
	buf.SetBytes(&bb)
	return buf
}
func (p *byteBufferPool) FromBytes(b []byte) *ByteBuffer {
	buf := p.GetCap(len(b))
	buf.AppendFrom(b)
	return buf
}