github.com/ronaksoft/rony@v0.16.26-0.20230807065236-1743dbfe6959/pools/bytes.go (about)

     1  package pools
     2  
     3  import (
     4  	"sync"
     5  
     6  	"github.com/ronaksoft/rony/pools/buf"
     7  )
     8  
     9  /*
    10     Creation Time: 2020 - Mar - 24
    11     Created by:  (ehsan)
    12     Maintainers:
    13        1.  Ehsan N. Moosa (E2)
    14     Auditor: Ehsan N. Moosa (E2)
    15     Copyright Ronak Software Group 2020
    16  */
    17  
    18  var Bytes = NewByteSlice(32, 64<<10)
    19  var Buffer = buf.NewBytesPool(4, 64<<10)
    20  
    21  const (
    22  	bitSize       = 32 << (^uint(0) >> 63)
    23  	maxintHeadBit = 1 << (bitSize - 2)
    24  )
    25  
    26  // byteSlicePool contains logic of reusing objects distinguishable by size in generic
    27  // way.
    28  type byteSlicePool struct {
    29  	pool map[int]*sync.Pool
    30  }
    31  
    32  // NewByteSlice creates new byteSlicePool that reuses objects which size is in logarithmic range
    33  // [min, max].
    34  //
    35  // Note that it is a shortcut for Custom() constructor with Options provided by
    36  // WithLogSizeMapping() and WithLogSizeRange(min, max) calls.
    37  func NewByteSlice(min, max int) *byteSlicePool {
    38  	p := &byteSlicePool{
    39  		pool: make(map[int]*sync.Pool),
    40  	}
    41  	logarithmicRange(
    42  		min, max,
    43  		func(n int) {
    44  			p.pool[n] = &sync.Pool{}
    45  		},
    46  	)
    47  
    48  	return p
    49  }
    50  
    51  // Get returns probably reused slice of bytes with at least capacity of c and
    52  // exactly len of n.
    53  func (p *byteSlicePool) Get(n, c int) []byte {
    54  	if n > c {
    55  		panic("requested length is greater than capacity")
    56  	}
    57  
    58  	size := ceilToPowerOfTwo(c)
    59  	if pool := p.pool[size]; pool != nil {
    60  		v := pool.Get()
    61  		if v != nil {
    62  			bts := v.([]byte)
    63  			bts = bts[:n]
    64  
    65  			return bts
    66  		} else {
    67  			return make([]byte, n, size)
    68  		}
    69  	}
    70  
    71  	return make([]byte, n, c)
    72  }
    73  
    74  // Put returns given slice to reuse pool.
    75  // It does not reuse bytes whose size is not power of two or is out of pool
    76  // min/max range.
    77  func (p *byteSlicePool) Put(bts []byte) {
    78  	if pool := p.pool[cap(bts)]; pool != nil {
    79  		pool.Put(bts)
    80  	}
    81  }
    82  
    83  // GetCap returns probably reused slice of bytes with at least capacity of n.
    84  func (p *byteSlicePool) GetCap(c int) []byte {
    85  	return p.Get(0, c)
    86  }
    87  
    88  // GetLen returns probably reused slice of bytes with at least capacity of n
    89  // and exactly len of n.
    90  func (p *byteSlicePool) GetLen(n int) []byte {
    91  	return p.Get(n, n)
    92  }
    93  
    94  // logarithmicRange iterates from ceil to power of two min to max,
    95  // calling cb on each iteration.
    96  func logarithmicRange(min, max int, cb func(int)) {
    97  	if min == 0 {
    98  		min = 1
    99  	}
   100  	for n := ceilToPowerOfTwo(min); n <= max; n <<= 1 {
   101  		cb(n)
   102  	}
   103  }
   104  
   105  // ceilToPowerOfTwo returns the least power of two integer value greater than
   106  // or equal to n.
   107  func ceilToPowerOfTwo(n int) int {
   108  	if n&maxintHeadBit != 0 && n > maxintHeadBit {
   109  		panic("argument is too large")
   110  	}
   111  	if n <= 2 {
   112  		return n
   113  	}
   114  	n--
   115  	n = fillBits(n)
   116  	n++
   117  
   118  	return n
   119  }
   120  
   121  func fillBits(n int) int {
   122  	n |= n >> 1
   123  	n |= n >> 2
   124  	n |= n >> 4
   125  	n |= n >> 8
   126  	n |= n >> 16
   127  	n |= n >> 32
   128  
   129  	return n
   130  }