alloc.go 3.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132
  1. package pool
  2. // Inspired by https://github.com/xtaci/smux/blob/master/alloc.go
  3. import (
  4. "errors"
  5. "math/bits"
  6. "sync"
  7. )
  8. var DefaultAllocator = newDefaultAllocator()
  9. type Allocator interface {
  10. Get(size int) []byte
  11. Put(buf []byte) error
  12. }
  13. // defaultAllocator for incoming frames, optimized to prevent overwriting after zeroing
  14. type defaultAllocator struct {
  15. buffers [11]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 newDefaultAllocator() Allocator {
  21. return &defaultAllocator{
  22. buffers: [...]sync.Pool{ // 64B -> 64K
  23. {New: func() any { return new([1 << 6]byte) }},
  24. {New: func() any { return new([1 << 7]byte) }},
  25. {New: func() any { return new([1 << 8]byte) }},
  26. {New: func() any { return new([1 << 9]byte) }},
  27. {New: func() any { return new([1 << 10]byte) }},
  28. {New: func() any { return new([1 << 11]byte) }},
  29. {New: func() any { return new([1 << 12]byte) }},
  30. {New: func() any { return new([1 << 13]byte) }},
  31. {New: func() any { return new([1 << 14]byte) }},
  32. {New: func() any { return new([1 << 15]byte) }},
  33. {New: func() any { return new([1 << 16]byte) }},
  34. },
  35. }
  36. }
  37. // Get a []byte from pool with most appropriate cap
  38. func (alloc *defaultAllocator) Get(size int) []byte {
  39. if size <= 0 || size > 65536 {
  40. return nil
  41. }
  42. var index uint16
  43. if size > 64 {
  44. index = msb(size)
  45. if size != 1<<index {
  46. index += 1
  47. }
  48. index -= 6
  49. }
  50. buffer := alloc.buffers[index].Get()
  51. switch index {
  52. case 0:
  53. return buffer.(*[1 << 6]byte)[:size]
  54. case 1:
  55. return buffer.(*[1 << 7]byte)[:size]
  56. case 2:
  57. return buffer.(*[1 << 8]byte)[:size]
  58. case 3:
  59. return buffer.(*[1 << 9]byte)[:size]
  60. case 4:
  61. return buffer.(*[1 << 10]byte)[:size]
  62. case 5:
  63. return buffer.(*[1 << 11]byte)[:size]
  64. case 6:
  65. return buffer.(*[1 << 12]byte)[:size]
  66. case 7:
  67. return buffer.(*[1 << 13]byte)[:size]
  68. case 8:
  69. return buffer.(*[1 << 14]byte)[:size]
  70. case 9:
  71. return buffer.(*[1 << 15]byte)[:size]
  72. case 10:
  73. return buffer.(*[1 << 16]byte)[:size]
  74. default:
  75. panic("invalid pool index")
  76. }
  77. }
  78. // Put returns a []byte to pool for future use,
  79. // which the cap must be exactly 2^n
  80. func (alloc *defaultAllocator) Put(buf []byte) error {
  81. bits := msb(cap(buf))
  82. if cap(buf) < 64 || cap(buf) > 65536 || cap(buf) != 1<<bits {
  83. return errors.New("allocator Put() incorrect buffer size")
  84. }
  85. bits -= 6
  86. buf = buf[:cap(buf)]
  87. //nolint
  88. //lint:ignore SA6002 ignore temporarily
  89. switch bits {
  90. case 0:
  91. alloc.buffers[bits].Put((*[1 << 6]byte)(buf))
  92. case 1:
  93. alloc.buffers[bits].Put((*[1 << 7]byte)(buf))
  94. case 2:
  95. alloc.buffers[bits].Put((*[1 << 8]byte)(buf))
  96. case 3:
  97. alloc.buffers[bits].Put((*[1 << 9]byte)(buf))
  98. case 4:
  99. alloc.buffers[bits].Put((*[1 << 10]byte)(buf))
  100. case 5:
  101. alloc.buffers[bits].Put((*[1 << 11]byte)(buf))
  102. case 6:
  103. alloc.buffers[bits].Put((*[1 << 12]byte)(buf))
  104. case 7:
  105. alloc.buffers[bits].Put((*[1 << 13]byte)(buf))
  106. case 8:
  107. alloc.buffers[bits].Put((*[1 << 14]byte)(buf))
  108. case 9:
  109. alloc.buffers[bits].Put((*[1 << 15]byte)(buf))
  110. case 10:
  111. alloc.buffers[bits].Put((*[1 << 16]byte)(buf))
  112. default:
  113. panic("invalid pool index")
  114. }
  115. return nil
  116. }
  117. // msb return the pos of most significant bit
  118. func msb(size int) uint16 {
  119. return uint16(bits.Len32(uint32(size)) - 1)
  120. }