alloc.go 1.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172
  1. package gfsmux // import "go.gridfinity.dev/gfsmux"
  2. import (
  3. "errors"
  4. "sync"
  5. )
  6. var (
  7. defaultAllocator *Allocator
  8. 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}
  9. )
  10. func init() {
  11. defaultAllocator = NewAllocator()
  12. }
  13. // Allocator for incoming frames, optimized to prevent overwriting after zeroing
  14. type Allocator struct {
  15. buffers []sync.Pool
  16. }
  17. // NewAllocator initiates a []byte allocator for frames less than 65536 bytes,
  18. // the waste(memory fragmentation) of space allocation is guaranteed to be
  19. // no more than 50%.
  20. func NewAllocator() *Allocator {
  21. alloc := new(Allocator)
  22. alloc.buffers = make([]sync.Pool, 17) // 1B -> 64K
  23. for k := range alloc.buffers {
  24. i := k
  25. alloc.buffers[k].New = func() interface{} {
  26. return make([]byte, 1<<uint32(i))
  27. }
  28. }
  29. return alloc
  30. }
  31. // Get a []byte from pool with most appropriate cap
  32. func (alloc *Allocator) Get(size int) []byte {
  33. if size <= 0 || size > 65536 {
  34. return nil
  35. }
  36. bits := Smsb(size)
  37. if size == 1<<bits {
  38. return alloc.buffers[bits].Get().([]byte)[:size]
  39. }
  40. return alloc.buffers[bits+1].Get().([]byte)[:size]
  41. }
  42. // Put returns a []byte to pool for future use,
  43. // which the cap must be exactly 2^n
  44. func (alloc *Allocator) Put(buf []byte) error {
  45. bits := Smsb(cap(buf))
  46. if cap(buf) == 0 || cap(buf) > 65536 || cap(buf) != 1<<bits {
  47. return errors.New("allocator Put() incorrect buffer size")
  48. }
  49. alloc.buffers[bits].Put(buf)
  50. return nil
  51. }
  52. // Smsb returns the position of most significiant bit
  53. // http://supertech.csail.mit.edu/papers/debruijn.pdf
  54. func Smsb(size int) byte {
  55. v := uint32(size)
  56. v |= v >> 1
  57. v |= v >> 2
  58. v |= v >> 4
  59. v |= v >> 8
  60. v |= v >> 16
  61. return debruijinPos[(v*0x07C4ACDD)>>27]
  62. }