diff options
Diffstat (limited to 'vendor/github.com/xtaci/smux/alloc.go')
-rw-r--r-- | vendor/github.com/xtaci/smux/alloc.go | 72 |
1 files changed, 72 insertions, 0 deletions
diff --git a/vendor/github.com/xtaci/smux/alloc.go b/vendor/github.com/xtaci/smux/alloc.go new file mode 100644 index 0000000..9e3acf3 --- /dev/null +++ b/vendor/github.com/xtaci/smux/alloc.go @@ -0,0 +1,72 @@ +package smux + +import ( + "errors" + "sync" +) + +var ( + defaultAllocator *Allocator + debruijinPos = [...]byte{0, 9, 1, 10, 13, 21, 2, 29, 11, 14, 16, 18, 22, 25, 3, 30, 8, 12, 20, 28, 15, 17, 24, 7, 19, 27, 23, 6, 26, 5, 4, 31} +) + +func init() { + defaultAllocator = NewAllocator() +} + +// Allocator for incoming frames, optimized to prevent overwriting after zeroing +type Allocator struct { + buffers []sync.Pool +} + +// NewAllocator initiates a []byte allocator for frames less than 65536 bytes, +// the waste(memory fragmentation) of space allocation is guaranteed to be +// no more than 50%. +func NewAllocator() *Allocator { + alloc := new(Allocator) + alloc.buffers = make([]sync.Pool, 17) // 1B -> 64K + for k := range alloc.buffers { + i := k + alloc.buffers[k].New = func() interface{} { + return make([]byte, 1<<uint32(i)) + } + } + return alloc +} + +// Get a []byte from pool with most appropriate cap +func (alloc *Allocator) Get(size int) []byte { + if size <= 0 || size > 65536 { + return nil + } + + bits := msb(size) + if size == 1<<bits { + return alloc.buffers[bits].Get().([]byte)[:size] + } else { + return alloc.buffers[bits+1].Get().([]byte)[:size] + } +} + +// Put returns a []byte to pool for future use, +// which the cap must be exactly 2^n +func (alloc *Allocator) Put(buf []byte) error { + bits := msb(cap(buf)) + if cap(buf) == 0 || cap(buf) > 65536 || cap(buf) != 1<<bits { + return errors.New("allocator Put() incorrect buffer size") + } + alloc.buffers[bits].Put(buf) + return nil +} + +// msb return the pos of most significiant bit +// http://supertech.csail.mit.edu/papers/debruijn.pdf +func msb(size int) byte { + v := uint32(size) + v |= v >> 1 + v |= v >> 2 + v |= v >> 4 + v |= v >> 8 + v |= v >> 16 + return debruijinPos[(v*0x07C4ACDD)>>27] +} |