...

Source file src/github.com/launchdarkly/go-server-sdk-evaluation/v2/internal/local_buffer.go

Documentation: github.com/launchdarkly/go-server-sdk-evaluation/v2/internal

     1  package internal
     2  
     3  import "strconv"
     4  
     5  // LocalBuffer is a simplified equivalent to bytes.Buffer that allows usage of a preallocated local
     6  // byte slice.
     7  //
     8  // The bytes.Buffer type is very efficient except in one regard: it must always allocate the byte
     9  // slice on the heap, since its internal "buf" field starts out as nil and cannot be directly modified.
    10  // LocalBuffer exports this field so it can be initialized to a slice which, if allowed by Go's escape
    11  // analysis, can remain on the stack as long as its capacity is not exceeded. For example:
    12  //
    13  //	buf := LocalBuffer{Data: make([]byte, 0, 100)}
    14  //	buf.AppendString("some data") // etc.
    15  //	result := buf.Data
    16  //
    17  // In the example, as long as no more than 100 bytes are written to the buffer, there are no heap
    18  // allocations. As soon as the capacity is exceeded, the byte slice is moved to the heap and its
    19  // capacity expands exponentially, similar to bytes.Buffer.
    20  //
    21  // To simplify the API, the LocalBuffer methods return nothing; that's why they're named Append
    22  // rather than Write, because Write has a connotation of imitating the io.Writer API.
    23  type LocalBuffer struct {
    24  	// Data is the current content of the buffer.
    25  	Data []byte
    26  }
    27  
    28  // Append appends a byte slice to the buffer.
    29  func (b *LocalBuffer) Append(data []byte) {
    30  	oldLen := b.grow(len(data))
    31  	copy(b.Data[oldLen:], data)
    32  }
    33  
    34  // AppendByte appends a single byte to the buffer.
    35  func (b *LocalBuffer) AppendByte(ch byte) { //nolint:stdmethods
    36  	oldLen := b.grow(1)
    37  	b.Data[oldLen] = ch
    38  }
    39  
    40  // AppendInt appends the base-10 string representation of an integer to the buffer.
    41  func (b *LocalBuffer) AppendInt(n int) {
    42  	temp := make([]byte, 0, 20)
    43  	temp = strconv.AppendInt(temp, int64(n), 10)
    44  	b.Append(temp)
    45  }
    46  
    47  // AppendString appends the bytes of a string to the buffer.
    48  func (b *LocalBuffer) AppendString(s string) {
    49  	oldLen := b.grow(len(s))
    50  	copy(b.Data[oldLen:], s)
    51  }
    52  
    53  func (b *LocalBuffer) grow(addBytes int) int {
    54  	oldLen := len(b.Data)
    55  	newLen := oldLen + addBytes
    56  	if cap(b.Data) >= newLen {
    57  		b.Data = b.Data[0:newLen]
    58  	} else {
    59  		newCap := cap(b.Data) * 2
    60  		if newCap < newLen {
    61  			newCap = newLen * 2
    62  		}
    63  		newData := make([]byte, newLen, newCap)
    64  		copy(newData[0:oldLen], b.Data)
    65  		b.Data = newData
    66  	}
    67  	return oldLen
    68  }
    69  

View as plain text