123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172 |
- package gfsmux // import "go.gridfinity.dev/gfsmux"
- 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 := Smsb(size)
- if size == 1<<bits {
- return alloc.buffers[bits].Get().([]byte)[:size]
- }
- 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 := Smsb(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
- }
- // Smsb returns the position of most significiant bit
- // http://supertech.csail.mit.edu/papers/debruijn.pdf
- func Smsb(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]
- }
|