github.com/m3db/m3@v1.5.0/src/metrics/encoding/protobuf/buffer.go (about)

     1  // Copyright (c) 2018 Uber Technologies, Inc.
     2  //
     3  // Permission is hereby granted, free of charge, to any person obtaining a copy
     4  // of this software and associated documentation files (the "Software"), to deal
     5  // in the Software without restriction, including without limitation the rights
     6  // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
     7  // copies of the Software, and to permit persons to whom the Software is
     8  // furnished to do so, subject to the following conditions:
     9  //
    10  // The above copyright notice and this permission notice shall be included in
    11  // all copies or substantial portions of the Software.
    12  //
    13  // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
    14  // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
    15  // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
    16  // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
    17  // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
    18  // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
    19  // THE SOFTWARE.
    20  
    21  package protobuf
    22  
    23  import (
    24  	"math"
    25  
    26  	"github.com/m3db/m3/src/x/pool"
    27  )
    28  
    29  // PoolReleaseFn is a function used to release underlying slice back to bytes pool.
    30  type PoolReleaseFn func([]byte)
    31  
    32  // Buffer contains a byte slice backed by an optional bytes pool.
    33  type Buffer struct {
    34  	finalizer PoolReleaseFn
    35  	buf       []byte
    36  }
    37  
    38  // NewBuffer create a new buffer.
    39  func NewBuffer(buf []byte, p PoolReleaseFn) Buffer {
    40  	return Buffer{buf: buf, finalizer: p}
    41  }
    42  
    43  // Bytes returns the raw byte slice.
    44  func (b Buffer) Bytes() []byte { return b.buf }
    45  
    46  // Truncate truncates the raw byte slice.
    47  func (b *Buffer) Truncate(n int) { b.buf = b.buf[:n] }
    48  
    49  // Close closes the buffer.
    50  func (b *Buffer) Close() {
    51  	if b.finalizer != nil && b.buf != nil {
    52  		b.finalizer(b.buf)
    53  	}
    54  	b.buf = nil
    55  	b.finalizer = nil
    56  }
    57  
    58  type copyDataMode int
    59  
    60  const (
    61  	dontCopyData copyDataMode = iota
    62  	copyData
    63  )
    64  
    65  // ensureBufferSize returns a buffer with at least the specified target size.
    66  // If the specified buffer has enough capacity, it is returned as is. Otherwise,
    67  // a new buffer is allocated with at least the specified target size, and the
    68  // specified buffer is returned to pool if possible.
    69  func ensureBufferSize(
    70  	buf []byte,
    71  	p pool.BytesPool,
    72  	targetSize int,
    73  	copyDataMode copyDataMode,
    74  ) []byte {
    75  	bufSize := len(buf)
    76  	if bufSize >= targetSize {
    77  		return buf
    78  	}
    79  	newSize := int(math.Max(float64(targetSize), float64(bufSize*2)))
    80  	newBuf := allocate(p, newSize)
    81  	if copyDataMode == copyData {
    82  		copy(newBuf, buf)
    83  	}
    84  	if p != nil && buf != nil {
    85  		p.Put(buf)
    86  	}
    87  	return newBuf
    88  }
    89  
    90  // allocate allocates a byte slice with at least the specified size.
    91  func allocate(p pool.BytesPool, targetSize int) []byte {
    92  	if p == nil {
    93  		return make([]byte, targetSize)
    94  	}
    95  	b := p.Get(targetSize)
    96  	return b[:cap(b)]
    97  }