github.com/cockroachdb/cockroachdb-parser@v0.23.3-0.20240213214944-911057d40c9a/pkg/util/json/tokenizer/buffer.go (about)

     1  // Copyright 2022 The Cockroach Authors.
     2  //
     3  // Use of this software is governed by the Business Source License
     4  // included in the file licenses/BSL.txt.
     5  //
     6  // As of the Change Date specified in that file, in accordance with
     7  // the Business Source License, use of this software will be governed
     8  // by the Apache License, Version 2.0, included in the file
     9  // licenses/APL.txt.
    10  
    11  package tokenizer
    12  
    13  import "unicode/utf8"
    14  
    15  // buffer, is very much like bytes.Buffer, but is simpler. In particular,
    16  // because we don't need to support entirety of bytes.Buffer interface, the
    17  // functions (s.a. AppendByte) are simpler, and as a result can be inlined.
    18  type buffer struct {
    19  	buf []byte // We maintain an invariant that len(buf) == cap(buf).
    20  	l   int    // Current length.
    21  }
    22  
    23  // Reset resets the buffer for next use.
    24  func (b *buffer) Reset() {
    25  	b.l = 0
    26  }
    27  
    28  // Bytes returns byte slice previously written.
    29  // NB: We do not make a copy here.  Returned buffer valid
    30  // until next call to buffer.
    31  func (b *buffer) Bytes() []byte {
    32  	return b.buf[:b.l]
    33  }
    34  
    35  // AppendByte appends byte to this buffer
    36  func (b *buffer) AppendByte(c byte) {
    37  	if cap(b.buf)-b.l <= 1 {
    38  		b.buf = grow(b.buf, 1)
    39  	}
    40  	b.buf[b.l] = c
    41  	b.l++
    42  }
    43  
    44  // Append appends buf to this buffer.
    45  func (b *buffer) Append(buf []byte) {
    46  	if cap(b.buf)-b.l <= len(buf) {
    47  		b.buf = grow(b.buf, len(buf))
    48  	}
    49  	copy(b.buf[b.l:], buf)
    50  	b.l += len(buf)
    51  }
    52  
    53  // AppendRune writes rune to this buffer.
    54  func (b *buffer) AppendRune(r rune) {
    55  	// Compare as uint32 to correctly handle negative runes.
    56  	if uint32(r) < utf8.RuneSelf {
    57  		b.AppendByte(byte(r))
    58  		return
    59  	}
    60  
    61  	if cap(b.buf)-b.l <= utf8.UTFMax {
    62  		b.buf = grow(b.buf, utf8.UTFMax)
    63  	}
    64  
    65  	n := utf8.EncodeRune(b.buf[b.l:b.l+utf8.UTFMax], r)
    66  	b.l += n
    67  }
    68  
    69  // smallBufferSize is an initial allocation minimal capacity.
    70  const smallBufferSize = 64
    71  
    72  // grow increases capacity of buf by at least n, and returns new buffer,
    73  // containing a copy of buf.
    74  func grow(buf []byte, n int) []byte {
    75  	if n < smallBufferSize {
    76  		n = smallBufferSize
    77  	}
    78  
    79  	if buf == nil {
    80  		return make([]byte, n)
    81  	}
    82  
    83  	// Cribbed from bytes.Buffer.
    84  	c := len(buf) + n // ensure enough space for n elements
    85  	if c < 2*cap(buf) {
    86  		c = 2 * cap(buf)
    87  	}
    88  
    89  	nb := append([]byte(nil), make([]byte, c)...)
    90  	copy(nb, buf)
    91  	// Make whole cap available since append may produce larger slice.
    92  	return nb[:cap(nb)]
    93  }