bufferpool.go 1.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869
  1. package util
  2. import (
  3. "math"
  4. "math/bits"
  5. "sync"
  6. )
  7. type bufferPool struct {
  8. pools [32]sync.Pool
  9. }
  10. func newBufferPool() *bufferPool {
  11. bp := new(bufferPool)
  12. for i := 0; i < 32; i++ {
  13. length := 1 << i
  14. bp.pools[i].New = func() any {
  15. return make([]byte, length)
  16. }
  17. }
  18. return bp
  19. }
  20. // index on the min number of bits required to store the byte data up to 32 bits.
  21. func nextIndex(length int) int {
  22. return bits.Len32(uint32(length))
  23. }
  24. // the previous index for a provided length
  25. func prevIndex(length int) int {
  26. next := nextIndex(length)
  27. if uint32(length) == (1 << uint32(next)) {
  28. return next
  29. }
  30. return next - 1
  31. }
  32. func (bp *bufferPool) Get(length int) []byte {
  33. if length <= 0 {
  34. return nil
  35. }
  36. // if it's beyond our pool bounds, just allocate and return
  37. if length > math.MaxInt32 {
  38. return make([]byte, length)
  39. }
  40. i := nextIndex(length)
  41. if entry := bp.pools[i].Get(); entry != nil {
  42. bytes := entry.([]byte)
  43. bytes = bytes[:length]
  44. return bytes
  45. }
  46. // should never get here, as there should always be an entry
  47. // coming from the pool
  48. return make([]byte, 1<<i)[:length]
  49. }
  50. func (bp *bufferPool) Put(buf []byte) {
  51. capacity := cap(buf)
  52. if capacity == 0 || capacity > math.MaxInt32 {
  53. return
  54. }
  55. i := prevIndex(capacity)
  56. bp.pools[i].Put(buf)
  57. }