Source File
	buffer_slice.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 memimport ()const (// 32 KiB is what io.Copy uses.readAllBufSize = 32 * 1024)// BufferSlice offers a means to represent data that spans one or more Buffer// instances. A BufferSlice is meant to be immutable after creation, and methods// like Ref create and return copies of the slice. This is why all methods have// value receivers rather than pointer receivers.//// Note that any of the methods that read the underlying buffers such as Ref,// Len or CopyTo etc., will panic if any underlying buffers have already been// freed. It is recommended to not directly interact with any of the underlying// buffers directly, rather such interactions should be mediated through the// various methods on this type.//// By convention, any APIs that return (mem.BufferSlice, error) should reduce// the burden on the caller by never returning a mem.BufferSlice that needs to// be freed if the error is non-nil, unless explicitly stated.type BufferSlice []Buffer// Len returns the sum of the length of all the Buffers in this slice.//// # Warning//// Invoking the built-in len on a BufferSlice will return the number of buffers// in the slice, and *not* the value returned by this function.func ( BufferSlice) () int {var intfor , := range {+= .Len()}return}// Ref invokes Ref on each buffer in the slice.func ( BufferSlice) () {for , := range {.Ref()}}// Free invokes Buffer.Free() on each Buffer in the slice.func ( BufferSlice) () {for , := range {.Free()}}// CopyTo copies each of the underlying Buffer's data into the given buffer,// returning the number of bytes copied. Has the same semantics as the copy// builtin in that it will copy as many bytes as it can, stopping when either dst// is full or s runs out of data, returning the minimum of s.Len() and len(dst).func ( BufferSlice) ( []byte) int {:= 0for , := range {+= copy([:], .ReadOnlyData())}return}// Materialize concatenates all the underlying Buffer's data into a single// contiguous buffer using CopyTo.func ( BufferSlice) () []byte {:= .Len()if == 0 {return nil}:= make([]byte, ).CopyTo()return}// MaterializeToBuffer functions like Materialize except that it writes the data// to a single Buffer pulled from the given BufferPool.//// As a special case, if the input BufferSlice only actually has one Buffer, this// function simply increases the refcount before returning said Buffer. Freeing this// buffer won't release it until the BufferSlice is itself released.func ( BufferSlice) ( BufferPool) Buffer {if len() == 1 {[0].Ref()return [0]}:= .Len()if == 0 {return emptyBuffer{}}:= .Get().CopyTo(*)return NewBuffer(, )}// Reader returns a new Reader for the input slice after taking references to// each underlying buffer.func ( BufferSlice) () Reader {.Ref()return &sliceReader{data: ,len: .Len(),}}// Reader exposes a BufferSlice's data as an io.Reader, allowing it to interface// with other parts systems. It also provides an additional convenience method// Remaining(), which returns the number of unread bytes remaining in the slice.// Buffers will be freed as they are read.type Reader interface {io.Readerio.ByteReader// Close frees the underlying BufferSlice and never returns an error. Subsequent// calls to Read will return (0, io.EOF).Close() error// Remaining returns the number of unread bytes remaining in the slice.Remaining() int// Reset frees the currently held buffer slice and starts reading from the// provided slice. This allows reusing the reader object.Reset(s BufferSlice)}type sliceReader struct {data BufferSlicelen int// The index into data[0].ReadOnlyData().bufferIdx int}func ( *sliceReader) () int {return .len}func ( *sliceReader) ( BufferSlice) {.data.Free().Ref().data =.len = .Len().bufferIdx = 0}func ( *sliceReader) () error {.data.Free().data = nil.len = 0return nil}func ( *sliceReader) () bool {if len(.data) == 0 || .bufferIdx != len(.data[0].ReadOnlyData()) {return false}.data[0].Free().data = .data[1:].bufferIdx = 0return true}func ( *sliceReader) ( []byte) ( int, error) {if .len == 0 {return 0, io.EOF}for len() != 0 && .len != 0 {// Copy as much as possible from the first Buffer in the slice into the// given byte slice.:= .data[0].ReadOnlyData():= copy(, [.bufferIdx:]).len -= // Reduce len by the number of bytes copied..bufferIdx += // Increment the buffer index.+= // Increment the total number of bytes read.= [:] // Shrink the given byte slice.// If we have copied all the data from the first Buffer, free it and advance to// the next in the slice..freeFirstBufferIfEmpty()}return , nil}func ( *sliceReader) () (byte, error) {if .len == 0 {return 0, io.EOF}// There may be any number of empty buffers in the slice, clear them all until a// non-empty buffer is reached. This is guaranteed to exit since r.len is not 0.for .freeFirstBufferIfEmpty() {}:= .data[0].ReadOnlyData()[.bufferIdx].len--.bufferIdx++// Free the first buffer in the slice if the last byte was read.freeFirstBufferIfEmpty()return , nil}var _ io.Writer = (*writer)(nil)type writer struct {buffers *BufferSlicepool BufferPool}func ( *writer) ( []byte) ( int, error) {:= Copy(, .pool)*.buffers = append(*.buffers, )return .Len(), nil}// NewWriter wraps the given BufferSlice and BufferPool to implement the// io.Writer interface. Every call to Write copies the contents of the given// buffer into a new Buffer pulled from the given pool and the Buffer is// added to the given BufferSlice.func ( *BufferSlice, BufferPool) io.Writer {return &writer{buffers: , pool: }}// ReadAll reads from r until an error or EOF and returns the data it read.// A successful call returns err == nil, not err == EOF. Because ReadAll is// defined to read from src until EOF, it does not treat an EOF from Read// as an error to be reported.//// Important: A failed call returns a non-nil error and may also return// partially read buffers. It is the responsibility of the caller to free the// BufferSlice returned, or its memory will not be reused.func ( io.Reader, BufferPool) (BufferSlice, error) {var BufferSliceif , := .(io.WriterTo); {// This is more optimal since wt knows the size of chunks it wants to// write and, hence, we can allocate buffers of an optimal size to fit// them. E.g. might be a single big chunk, and we wouldn't chop it// into pieces.:= NewWriter(&, ), := .WriteTo()return ,}:for {:= .Get(readAllBufSize)// We asked for 32KiB but may have been given a bigger buffer.// Use all of it if that's the case.* = (*)[:cap(*)]:= 0for {, := .Read((*)[:])+=if != nil {if == 0 {// Nothing in this buf, put it back.Put()} else {* = (*)[:]= append(, NewBuffer(, ))}if == io.EOF {= nil}return ,}if len(*) == {= append(, NewBuffer(, ))continue}}}}
The pages are generated with Golds v0.7.6. (GOOS=linux GOARCH=amd64)