github.com/clubpay/ronykit/kit@v0.14.4-0.20240515065620-d0dace45cbc7/utils/buf/bytes.go (about)

     1  package buf
     2  
     3  import (
     4  	"io"
     5  	"sync"
     6  )
     7  
     8  const (
     9  	bitSize       = 32 << (^uint(0) >> 63)
    10  	maxIntHeadBit = 1 << (bitSize - 2)
    11  )
    12  
    13  type Bytes struct {
    14  	p  *BytesPool
    15  	ri int
    16  	b  []byte
    17  }
    18  
    19  func (bb *Bytes) Write(p []byte) (n int, err error) {
    20  	bb.b = append(bb.b, p...)
    21  
    22  	return len(p), nil
    23  }
    24  
    25  func (bb *Bytes) Read(p []byte) (n int, err error) {
    26  	if bb.ri >= len(bb.b)-1 {
    27  		return 0, io.EOF
    28  	}
    29  	n = copy(p, bb.b[bb.ri:])
    30  	bb.ri += n
    31  
    32  	return n, nil
    33  }
    34  
    35  func newBytes(p *BytesPool, n, c int) *Bytes {
    36  	if n > c {
    37  		panic("requested length is greater than capacity")
    38  	}
    39  
    40  	return &Bytes{p: p, b: make([]byte, n, c)}
    41  }
    42  
    43  func (bb *Bytes) Reset() {
    44  	bb.ri = 0
    45  	bb.b = bb.b[:bb.ri]
    46  }
    47  
    48  func (bb *Bytes) Bytes() *[]byte {
    49  	return &bb.b
    50  }
    51  
    52  func (bb *Bytes) SetBytes(b *[]byte) {
    53  	if b == nil {
    54  		return
    55  	}
    56  	bb.b = *b
    57  }
    58  
    59  func (bb *Bytes) Fill(data []byte, start, end int) {
    60  	copy(bb.b[start:end], data)
    61  }
    62  
    63  func (bb *Bytes) CopyFromWithOffset(data []byte, offset int) {
    64  	copy(bb.b[offset:], data)
    65  }
    66  
    67  func (bb *Bytes) CopyFrom(data []byte) {
    68  	copy(bb.b, data)
    69  }
    70  
    71  func (bb *Bytes) CopyTo(data []byte) []byte {
    72  	copy(data, bb.b)
    73  
    74  	return data
    75  }
    76  
    77  func (bb *Bytes) AppendFrom(data []byte) {
    78  	bb.b = append(bb.b, data...)
    79  }
    80  
    81  func (bb *Bytes) AppendTo(data []byte) []byte {
    82  	data = append(data, bb.b...)
    83  
    84  	return data
    85  }
    86  
    87  func (bb *Bytes) AppendByte(b byte) {
    88  	bb.b = append(bb.b, b)
    89  }
    90  
    91  func (bb *Bytes) AppendString(s string) {
    92  	bb.b = append(bb.b, s...)
    93  }
    94  
    95  func (bb *Bytes) Len() int {
    96  	return len(bb.b)
    97  }
    98  
    99  func (bb Bytes) Cap() int {
   100  	return cap(bb.b)
   101  }
   102  
   103  func (bb *Bytes) Release() {
   104  	bb.p.put(bb)
   105  }
   106  
   107  // BytesPool contains the logic of reusing objects distinguishable by size in generic
   108  // way.
   109  type BytesPool struct {
   110  	pool map[int]*sync.Pool
   111  }
   112  
   113  var defaultPool = NewBytesPool(32, 1<<20)
   114  
   115  // NewBytesPool creates new BytesPool that reuses objects which size is in logarithmic range
   116  // [min, max].
   117  func NewBytesPool(min, max int) *BytesPool {
   118  	p := &BytesPool{
   119  		pool: make(map[int]*sync.Pool),
   120  	}
   121  	logarithmicRange(min, max, func(n int) {
   122  		p.pool[n] = &sync.Pool{}
   123  	})
   124  
   125  	return p
   126  }
   127  
   128  // Get returns probably reused slice of bytes with at least capacity of c and
   129  // exactly len of n.
   130  func (p *BytesPool) Get(n, c int) *Bytes {
   131  	if n > c {
   132  		panic("requested length is greater than capacity")
   133  	}
   134  
   135  	size := ceilToPowerOfTwo(c)
   136  	if pool := p.pool[size]; pool != nil {
   137  		v := pool.Get()
   138  		if v != nil {
   139  			bb := v.(*Bytes) //nolint:forcetypeassert
   140  			bb.b = bb.b[:n]
   141  
   142  			return bb
   143  		} else {
   144  			return newBytes(p, n, size)
   145  		}
   146  	}
   147  
   148  	return newBytes(p, n, c)
   149  }
   150  
   151  func Get(n, c int) *Bytes {
   152  	return defaultPool.Get(n, c)
   153  }
   154  
   155  // GetCap returns probably reused slice of bytes with at least capacity of n.
   156  func (p *BytesPool) GetCap(c int) *Bytes {
   157  	return p.Get(0, c)
   158  }
   159  
   160  func GetCap(c int) *Bytes {
   161  	return defaultPool.Get(0, c)
   162  }
   163  
   164  // GetLen returns probably reused slice of bytes with at least capacity of n
   165  // and exactly len of n.
   166  func (p *BytesPool) GetLen(n int) *Bytes {
   167  	return p.Get(n, n)
   168  }
   169  
   170  func GetLen(n int) *Bytes {
   171  	return defaultPool.Get(n, n)
   172  }
   173  
   174  func FromBytes(in []byte) *Bytes {
   175  	b := defaultPool.GetCap(len(in))
   176  	b.AppendFrom(in)
   177  
   178  	return b
   179  }
   180  
   181  // put returns given Bytes to reuse pool.
   182  // It does not reuse bytes whose size is not power of two or is out of pool
   183  // min/max range.
   184  func (p *BytesPool) put(bb *Bytes) {
   185  	if pool := p.pool[cap(bb.b)]; pool != nil {
   186  		pool.Put(bb)
   187  	}
   188  }
   189  
   190  // logarithmicRange iterates from ceil to power of two min to max,
   191  // calling cb on each iteration.
   192  func logarithmicRange(min, max int, cb func(int)) {
   193  	if min == 0 {
   194  		min = 1
   195  	}
   196  	for n := ceilToPowerOfTwo(min); n <= max; n <<= 1 {
   197  		cb(n)
   198  	}
   199  }
   200  
   201  // ceilToPowerOfTwo returns the least power of two integer value greater than
   202  // or equal to n.
   203  func ceilToPowerOfTwo(n int) int {
   204  	if n&maxIntHeadBit != 0 && n > maxIntHeadBit {
   205  		panic("argument is too large")
   206  	}
   207  	if n <= 2 {
   208  		return n
   209  	}
   210  	n--
   211  	n = fillBits(n)
   212  	n++
   213  
   214  	return n
   215  }
   216  
   217  func fillBits(n int) int {
   218  	n |= n >> 1
   219  	n |= n >> 2
   220  	n |= n >> 4
   221  	n |= n >> 8
   222  	n |= n >> 16
   223  	n |= n >> 32
   224  
   225  	return n
   226  }