Source File
	buffers.go
Belonging Package
	google.golang.org/grpc/mem
/*** Copyright 2024 gRPC authors.** Licensed under the Apache License, Version 2.0 (the "License");* you may not use this file except in compliance with the License.* You may obtain a copy of the License at** http://www.apache.org/licenses/LICENSE-2.0** Unless required by applicable law or agreed to in writing, software* distributed under the License is distributed on an "AS IS" BASIS,* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.* See the License for the specific language governing permissions and* limitations under the License.**/// Package mem provides utilities that facilitate memory reuse in byte slices// that are used as buffers.//// # Experimental//// Notice: All APIs in this package are EXPERIMENTAL and may be changed or// removed in a later release.package memimport ()// A Buffer represents a reference counted piece of data (in bytes) that can be// acquired by a call to NewBuffer() or Copy(). A reference to a Buffer may be// released by calling Free(), which invokes the free function given at creation// only after all references are released.//// Note that a Buffer is not safe for concurrent access and instead each// goroutine should use its own reference to the data, which can be acquired via// a call to Ref().//// Attempts to access the underlying data after releasing the reference to the// Buffer will panic.type Buffer interface {// ReadOnlyData returns the underlying byte slice. Note that it is undefined// behavior to modify the contents of this slice in any way.ReadOnlyData() []byte// Ref increases the reference counter for this Buffer.Ref()// Free decrements this Buffer's reference counter and frees the underlying// byte slice if the counter reaches 0 as a result of this call.Free()// Len returns the Buffer's size.Len() intsplit(n int) (left, right Buffer)read(buf []byte) (int, Buffer)}var (bufferPoolingThreshold = 1 << 10bufferObjectPool = sync.Pool{New: func() any { return new(buffer) }}refObjectPool = sync.Pool{New: func() any { return new(atomic.Int32) }})// IsBelowBufferPoolingThreshold returns true if the given size is less than or// equal to the threshold for buffer pooling. This is used to determine whether// to pool buffers or allocate them directly.func ( int) bool {return <= bufferPoolingThreshold}type buffer struct {origData *[]bytedata []byterefs *atomic.Int32pool BufferPool}func () *buffer {return bufferObjectPool.Get().(*buffer)}// NewBuffer creates a new Buffer from the given data, initializing the reference// counter to 1. The data will then be returned to the given pool when all// references to the returned Buffer are released. As a special case to avoid// additional allocations, if the given buffer pool is nil, the returned buffer// will be a "no-op" Buffer where invoking Buffer.Free() does nothing and the// underlying data is never freed.//// Note that the backing array of the given data is not copied.func ( *[]byte, BufferPool) Buffer {// Use the buffer's capacity instead of the length, otherwise buffers may// not be reused under certain conditions. For example, if a large buffer// is acquired from the pool, but fewer bytes than the buffering threshold// are written to it, the buffer will not be returned to the pool.if == nil || IsBelowBufferPoolingThreshold(cap(*)) {return (SliceBuffer)(*)}:= newBuffer().origData =.data = *.pool =.refs = refObjectPool.Get().(*atomic.Int32).refs.Add(1)return}// Copy creates a new Buffer from the given data, initializing the reference// counter to 1.//// It acquires a []byte from the given pool and copies over the backing array// of the given data. The []byte acquired from the pool is returned to the// pool when all references to the returned Buffer are released.func ( []byte, BufferPool) Buffer {if IsBelowBufferPoolingThreshold(len()) {:= make(SliceBuffer, len())copy(, )return}:= .Get(len())copy(*, )return NewBuffer(, )}func ( *buffer) () []byte {if .refs == nil {panic("Cannot read freed buffer")}return .data}func ( *buffer) () {if .refs == nil {panic("Cannot ref freed buffer")}.refs.Add(1)}func ( *buffer) () {if .refs == nil {panic("Cannot free freed buffer")}:= .refs.Add(-1)switch {case > 0:returncase == 0:if .pool != nil {.pool.Put(.origData)}refObjectPool.Put(.refs).origData = nil.data = nil.refs = nil.pool = nilbufferObjectPool.Put()default:panic("Cannot free freed buffer")}}func ( *buffer) () int {return len(.ReadOnlyData())}func ( *buffer) ( int) (Buffer, Buffer) {if .refs == nil {panic("Cannot split freed buffer")}.refs.Add(1):= newBuffer().origData = .origData.data = .data[:].refs = .refs.pool = .pool.data = .data[:]return ,}func ( *buffer) ( []byte) (int, Buffer) {if .refs == nil {panic("Cannot read freed buffer")}:= copy(, .data)if == len(.data) {.Free()return , nil}.data = .data[:]return ,}func ( *buffer) () string {return fmt.Sprintf("mem.Buffer(%p, data: %p, length: %d)", , .ReadOnlyData(), len(.ReadOnlyData()))}// ReadUnsafe reads bytes from the given Buffer into the provided slice.// It does not perform safety checks.func ( []byte, Buffer) (int, Buffer) {return .read()}// SplitUnsafe modifies the receiver to point to the first n bytes while it// returns a new reference to the remaining bytes. The returned Buffer// functions just like a normal reference acquired using Ref().func ( Buffer, int) (, Buffer) {return .split()}type emptyBuffer struct{}func ( emptyBuffer) () []byte {return nil}func ( emptyBuffer) () {}func ( emptyBuffer) () {}func ( emptyBuffer) () int {return 0}func ( emptyBuffer) (int) (, Buffer) {return ,}func ( emptyBuffer) ([]byte) (int, Buffer) {return 0,}// SliceBuffer is a Buffer implementation that wraps a byte slice. It provides// methods for reading, splitting, and managing the byte slice.type SliceBuffer []byte// ReadOnlyData returns the byte slice.func ( SliceBuffer) () []byte { return }// Ref is a noop implementation of Ref.func ( SliceBuffer) () {}// Free is a noop implementation of Free.func ( SliceBuffer) () {}// Len is a noop implementation of Len.func ( SliceBuffer) () int { return len() }func ( SliceBuffer) ( int) (, Buffer) {return [:], [:]}func ( SliceBuffer) ( []byte) (int, Buffer) {:= copy(, )if == len() {return , nil}return , [:]}
The pages are generated with Golds v0.7.6. (GOOS=linux GOARCH=amd64)