pool.go 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173
  1. // Copyright 2016 The Internal Authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style
  3. // license that can be found in the LICENSE file.
  4. // Package slice implements pools of pointers to slices.
  5. package slice
  6. import (
  7. "sync"
  8. "github.com/cznic/mathutil"
  9. )
  10. var (
  11. // Bytes is a ready to use *[]byte Pool.
  12. Bytes *Pool
  13. // Ints is a ready to use *[]int Pool.
  14. Ints *Pool
  15. )
  16. func init() {
  17. Bytes = newBytes()
  18. Ints = NewPool(
  19. func(size int) interface{} { // create
  20. b := make([]int, size)
  21. return &b
  22. },
  23. func(s interface{}) { // clear
  24. b := *s.(*[]int)
  25. b = b[:cap(b)]
  26. for i := range b {
  27. b[i] = 0
  28. }
  29. },
  30. func(s interface{}, size int) { // setSize
  31. p := s.(*[]int)
  32. *p = (*p)[:size]
  33. },
  34. func(s interface{}) int { return cap(*s.(*[]int)) }, // cap
  35. )
  36. }
  37. func newBytes() *Pool {
  38. return NewPool(
  39. func(size int) interface{} { // create
  40. b := make([]byte, size)
  41. return &b
  42. },
  43. func(s interface{}) { // clear
  44. b := *s.(*[]byte)
  45. b = b[:cap(b)]
  46. for i := range b {
  47. b[i] = 0
  48. }
  49. },
  50. func(s interface{}, size int) { // setSize
  51. p := s.(*[]byte)
  52. *p = (*p)[:size]
  53. },
  54. func(s interface{}) int { return cap(*s.(*[]byte)) }, // cap
  55. )
  56. }
  57. // Pool implements a pool of pointers to slices.
  58. //
  59. // Example usage pattern (assuming pool is, for example, a *[]byte Pool)
  60. //
  61. // p := pool.Get(size).(*[]byte)
  62. // b := *p // Now you can use b in any way you need.
  63. // ...
  64. // // When b will not be used anymore
  65. // pool.Put(p)
  66. // ...
  67. // // If b or p are not going out of scope soon, optionally
  68. // b = nil
  69. // p = nil
  70. //
  71. // Otherwise the pool cannot release the slice on garbage collection.
  72. //
  73. // Do not do
  74. //
  75. // p := pool.Get(size).(*[]byte)
  76. // b := *p
  77. // ...
  78. // pool.Put(&b)
  79. //
  80. // or
  81. //
  82. // b := *pool.Get(size).(*[]byte)
  83. // ...
  84. // pool.Put(&b)
  85. type Pool struct {
  86. cap func(interface{}) int
  87. clear func(interface{})
  88. m [63]sync.Pool
  89. null interface{}
  90. setSize func(interface{}, int)
  91. }
  92. // NewPool returns a newly created Pool. Assuming the desired slice type is
  93. // []T:
  94. //
  95. // The create function returns a *[]T of len == cap == size.
  96. //
  97. // The argument of clear is *[]T and the function sets all the slice elements
  98. // to the respective zero value.
  99. //
  100. // The setSize function gets a *[]T and sets its len to size.
  101. //
  102. // The cap function gets a *[]T and returns its capacity.
  103. func NewPool(
  104. create func(size int) interface{},
  105. clear func(interface{}),
  106. setSize func(p interface{}, size int),
  107. cap func(p interface{}) int,
  108. ) *Pool {
  109. p := &Pool{clear: clear, setSize: setSize, cap: cap, null: create(0)}
  110. for i := range p.m {
  111. size := 1 << uint(i)
  112. p.m[i] = sync.Pool{New: func() interface{} {
  113. // 0: 1 - 1
  114. // 1: 10 - 10
  115. // 2: 11 - 100
  116. // 3: 101 - 1000
  117. // 4: 1001 - 10000
  118. // 5: 10001 - 100000
  119. return create(size)
  120. }}
  121. }
  122. return p
  123. }
  124. // CGet returns a *[]T of len size. The pointed to slice is zeroed up to its
  125. // cap. CGet panics for size < 0.
  126. //
  127. // CGet is safe for concurrent use by multiple goroutines.
  128. func (p *Pool) CGet(size int) interface{} {
  129. s := p.Get(size)
  130. p.clear(s)
  131. return s
  132. }
  133. // Get returns a *[]T of len size. The pointed to slice is not zeroed. Get
  134. // panics for size < 0.
  135. //
  136. // Get is safe for concurrent use by multiple goroutines.
  137. func (p *Pool) Get(size int) interface{} {
  138. var index int
  139. switch {
  140. case size < 0:
  141. panic("Pool.Get: negative size")
  142. case size == 0:
  143. return p.null
  144. case size > 1:
  145. index = mathutil.Log2Uint64(uint64(size-1)) + 1
  146. }
  147. s := p.m[index].Get()
  148. p.setSize(s, size)
  149. return s
  150. }
  151. // Put puts a *[]T into a pool for possible later reuse by CGet or Get. Put
  152. // panics is its argument is not of type *[]T.
  153. //
  154. // Put is safe for concurrent use by multiple goroutines.
  155. func (p *Pool) Put(b interface{}) {
  156. size := p.cap(b)
  157. if size == 0 {
  158. return
  159. }
  160. p.m[mathutil.Log2Uint64(uint64(size))].Put(b)
  161. }