alloc.go 1.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108
  1. package 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(
  22. Allocator,
  23. )
  24. alloc.buffers = make(
  25. []sync.Pool,
  26. 17,
  27. ) // 1B -> 64K
  28. for k := range alloc.buffers {
  29. i := k
  30. alloc.buffers[k].New = func() interface{} {
  31. return make(
  32. []byte,
  33. 1<<uint32(
  34. i,
  35. ),
  36. )
  37. }
  38. }
  39. return alloc
  40. }
  41. // Get a []byte from pool with most appropriate cap
  42. func (
  43. alloc *Allocator,
  44. ) Get(
  45. size int,
  46. ) []byte {
  47. if size <= 0 || size > 65536 {
  48. return nil
  49. }
  50. bits := Smsb(
  51. size,
  52. )
  53. if size == 1<<bits {
  54. return alloc.buffers[bits].Get().([]byte)[:size]
  55. }
  56. return alloc.buffers[bits+1].Get().([]byte)[:size]
  57. }
  58. // Put returns a []byte to pool for future use,
  59. // which the cap must be exactly 2^n
  60. func (
  61. alloc *Allocator,
  62. ) Put(
  63. buf []byte,
  64. ) error {
  65. bits := Smsb(
  66. cap(
  67. buf,
  68. ),
  69. )
  70. if cap(
  71. buf,
  72. ) == 0 || cap(
  73. buf,
  74. ) > 65536 || cap(
  75. buf,
  76. ) != 1<<bits {
  77. return errors.New(
  78. "allocator Put() incorrect buffer size",
  79. )
  80. }
  81. alloc.buffers[bits].Put(
  82. buf,
  83. )
  84. return nil
  85. }
  86. // Smsb returns the position of most significiant bit
  87. // http://supertech.csail.mit.edu/papers/debruijn.pdf
  88. func Smsb(
  89. size int,
  90. ) byte {
  91. v := uint32(size)
  92. v |= v >> 1
  93. v |= v >> 2
  94. v |= v >> 4
  95. v |= v >> 8
  96. v |= v >> 16
  97. return debruijinPos[(v*0x07C4ACDD)>>27]
  98. }