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

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