| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173 |
- // Copyright 2016 The Internal Authors. All rights reserved.
- // Use of this source code is governed by a BSD-style
- // license that can be found in the LICENSE file.
- // Package slice implements pools of pointers to slices.
- package slice
- import (
- "sync"
- "github.com/cznic/mathutil"
- )
- var (
- // Bytes is a ready to use *[]byte Pool.
- Bytes *Pool
- // Ints is a ready to use *[]int Pool.
- Ints *Pool
- )
- func init() {
- Bytes = newBytes()
- Ints = NewPool(
- func(size int) interface{} { // create
- b := make([]int, size)
- return &b
- },
- func(s interface{}) { // clear
- b := *s.(*[]int)
- b = b[:cap(b)]
- for i := range b {
- b[i] = 0
- }
- },
- func(s interface{}, size int) { // setSize
- p := s.(*[]int)
- *p = (*p)[:size]
- },
- func(s interface{}) int { return cap(*s.(*[]int)) }, // cap
- )
- }
- func newBytes() *Pool {
- return NewPool(
- func(size int) interface{} { // create
- b := make([]byte, size)
- return &b
- },
- func(s interface{}) { // clear
- b := *s.(*[]byte)
- b = b[:cap(b)]
- for i := range b {
- b[i] = 0
- }
- },
- func(s interface{}, size int) { // setSize
- p := s.(*[]byte)
- *p = (*p)[:size]
- },
- func(s interface{}) int { return cap(*s.(*[]byte)) }, // cap
- )
- }
- // Pool implements a pool of pointers to slices.
- //
- // Example usage pattern (assuming pool is, for example, a *[]byte Pool)
- //
- // p := pool.Get(size).(*[]byte)
- // b := *p // Now you can use b in any way you need.
- // ...
- // // When b will not be used anymore
- // pool.Put(p)
- // ...
- // // If b or p are not going out of scope soon, optionally
- // b = nil
- // p = nil
- //
- // Otherwise the pool cannot release the slice on garbage collection.
- //
- // Do not do
- //
- // p := pool.Get(size).(*[]byte)
- // b := *p
- // ...
- // pool.Put(&b)
- //
- // or
- //
- // b := *pool.Get(size).(*[]byte)
- // ...
- // pool.Put(&b)
- type Pool struct {
- cap func(interface{}) int
- clear func(interface{})
- m [63]sync.Pool
- null interface{}
- setSize func(interface{}, int)
- }
- // NewPool returns a newly created Pool. Assuming the desired slice type is
- // []T:
- //
- // The create function returns a *[]T of len == cap == size.
- //
- // The argument of clear is *[]T and the function sets all the slice elements
- // to the respective zero value.
- //
- // The setSize function gets a *[]T and sets its len to size.
- //
- // The cap function gets a *[]T and returns its capacity.
- func NewPool(
- create func(size int) interface{},
- clear func(interface{}),
- setSize func(p interface{}, size int),
- cap func(p interface{}) int,
- ) *Pool {
- p := &Pool{clear: clear, setSize: setSize, cap: cap, null: create(0)}
- for i := range p.m {
- size := 1 << uint(i)
- p.m[i] = sync.Pool{New: func() interface{} {
- // 0: 1 - 1
- // 1: 10 - 10
- // 2: 11 - 100
- // 3: 101 - 1000
- // 4: 1001 - 10000
- // 5: 10001 - 100000
- return create(size)
- }}
- }
- return p
- }
- // CGet returns a *[]T of len size. The pointed to slice is zeroed up to its
- // cap. CGet panics for size < 0.
- //
- // CGet is safe for concurrent use by multiple goroutines.
- func (p *Pool) CGet(size int) interface{} {
- s := p.Get(size)
- p.clear(s)
- return s
- }
- // Get returns a *[]T of len size. The pointed to slice is not zeroed. Get
- // panics for size < 0.
- //
- // Get is safe for concurrent use by multiple goroutines.
- func (p *Pool) Get(size int) interface{} {
- var index int
- switch {
- case size < 0:
- panic("Pool.Get: negative size")
- case size == 0:
- return p.null
- case size > 1:
- index = mathutil.Log2Uint64(uint64(size-1)) + 1
- }
- s := p.m[index].Get()
- p.setSize(s, size)
- return s
- }
- // Put puts a *[]T into a pool for possible later reuse by CGet or Get. Put
- // panics is its argument is not of type *[]T.
- //
- // Put is safe for concurrent use by multiple goroutines.
- func (p *Pool) Put(b interface{}) {
- size := p.cap(b)
- if size == 0 {
- return
- }
- p.m[mathutil.Log2Uint64(uint64(size))].Put(b)
- }
|