diff options
| author | 2025-11-23 08:00:00 +0800 | |
|---|---|---|
| committer | 2025-11-23 08:00:00 +0800 | |
| commit | 7eaa8614c897a97d241335982f4c04f1f27b0715 (patch) | |
| tree | ab39c63adecab22464b3fa50be7073647bb817d4 /internal | |
| parent | obj: Add ReadObjectTypeRaw (diff) | |
| signature | No signature | |
bufpool: Return bytes.Buffer, rather than a pointer to it
It's silly to allocate a bytes.Buffer struct, however small it is,
every time Borrow is called, since the entire purpose is to reduce
allocations.
Diffstat (limited to 'internal')
| -rw-r--r-- | internal/bufpool/buffers.go | 17 | ||||
| -rw-r--r-- | internal/flatex/decompress_bytes.go | 8 | ||||
| -rw-r--r-- | internal/zlibx/decompress.go | 18 |
3 files changed, 22 insertions, 21 deletions
diff --git a/internal/bufpool/buffers.go b/internal/bufpool/buffers.go index 27c017bd..439e7e04 100644 --- a/internal/bufpool/buffers.go +++ b/internal/bufpool/buffers.go @@ -23,10 +23,11 @@ const ( // pooled buffer, the caller should invoke Release() to return it to the pool. // // Buffers must not be copied after first use; doing so can cause double-returns -// to the pool and data races. A zero-value Buffer is not valid for use. Use -// the pointer type (*Buffer) returned by Borrow/FromOwned to avoid accidental -// copies. +// to the pool and data races. +// +//go:nocopy type Buffer struct { + _ struct{} // for nocopy buf []byte pool poolIndex } @@ -69,28 +70,28 @@ var bufferPools = func() []sync.Pool { // unpooled buffer is allocated. // // The caller must call Release() when finished using the returned Buffer. -func Borrow(capHint int) *Buffer { +func Borrow(capHint int) Buffer { if capHint < DefaultBufferCap { capHint = DefaultBufferCap } classIdx, classCap, pooled := classFor(capHint) if !pooled { newBuf := make([]byte, 0, capHint) - return &Buffer{buf: newBuf, pool: unpooled} + return Buffer{buf: newBuf, pool: unpooled} } buf := bufferPools[classIdx].Get().(*[]byte) if cap(*buf) < classCap { *buf = make([]byte, 0, classCap) } slice := (*buf)[:0] - return &Buffer{buf: slice, pool: poolIndex(classIdx)} + return Buffer{buf: slice, pool: poolIndex(classIdx)} } // FromOwned constructs a Buffer from a caller-owned byte slice. The resulting // Buffer does not participate in pooling and will never be returned to the // internal pool when released. -func FromOwned(buf []byte) *Buffer { - return &Buffer{buf: buf, pool: unpooled} +func FromOwned(buf []byte) Buffer { + return Buffer{buf: buf, pool: unpooled} } // Resize adjusts the length of the buffer to n bytes. If n exceeds the current diff --git a/internal/flatex/decompress_bytes.go b/internal/flatex/decompress_bytes.go index 0d95084c..9f1ffcfd 100644 --- a/internal/flatex/decompress_bytes.go +++ b/internal/flatex/decompress_bytes.go @@ -21,16 +21,16 @@ var bufferDecompressorPool = sync.Pool{ }, } -func Decompress(src []byte) (*bufpool.Buffer, int, error) { +func Decompress(src []byte) (bufpool.Buffer, int, error) { return DecompressSized(src, 0) } -func DecompressSized(src []byte, sizeHint int) (*bufpool.Buffer, int, error) { +func DecompressSized(src []byte, sizeHint int) (bufpool.Buffer, int, error) { d := bufferDecompressorPool.Get().(*bufferDecompressor) defer bufferDecompressorPool.Put(d) if err := d.inflater.reset(src); err != nil { - return nil, 0, err + return bufpool.Buffer{}, 0, err } out := bufpool.Borrow(sizeHint) @@ -47,7 +47,7 @@ func DecompressSized(src []byte, sizeHint int) (*bufpool.Buffer, int, error) { return out, d.inflater.pos, nil } out.Release() - return nil, 0, d.inflater.err + return bufpool.Buffer{}, 0, d.inflater.err } d.inflater.step(&d.inflater) if d.inflater.err != nil && len(d.inflater.toRead) == 0 { diff --git a/internal/zlibx/decompress.go b/internal/zlibx/decompress.go index df4a34be..9d4e5268 100644 --- a/internal/zlibx/decompress.go +++ b/internal/zlibx/decompress.go @@ -9,45 +9,45 @@ import ( "git.sr.ht/~runxiyu/furgit/internal/flatex" ) -func Decompress(src []byte) (*bufpool.Buffer, error) { +func Decompress(src []byte) (bufpool.Buffer, error) { return DecompressSized(src, 0) } -func DecompressSized(src []byte, sizeHint int) (*bufpool.Buffer, error) { +func DecompressSized(src []byte, sizeHint int) (bufpool.Buffer, error) { if len(src) < 6 { - return nil, io.ErrUnexpectedEOF + return bufpool.Buffer{}, io.ErrUnexpectedEOF } cmf := src[0] flg := src[1] if (cmf&0x0f != zlibDeflate) || (cmf>>4 > zlibMaxWindow) || (binary.BigEndian.Uint16(src[:2])%31 != 0) { - return nil, ErrHeader + return bufpool.Buffer{}, ErrHeader } offset := 2 if flg&0x20 != 0 { - return nil, ErrHeader + return bufpool.Buffer{}, ErrHeader } if len(src[offset:]) < 4 { - return nil, io.ErrUnexpectedEOF + return bufpool.Buffer{}, io.ErrUnexpectedEOF } deflateData := src[offset:] out, consumed, err := flatex.DecompressSized(deflateData, sizeHint) if err != nil { - return nil, err + return bufpool.Buffer{}, err } checksumPos := offset + consumed if checksumPos+4 > len(src) { out.Release() - return nil, io.ErrUnexpectedEOF + return bufpool.Buffer{}, io.ErrUnexpectedEOF } expected := binary.BigEndian.Uint32(src[checksumPos : checksumPos+4]) if expected != adler32.Checksum(out.Bytes()) { out.Release() - return nil, ErrChecksum + return bufpool.Buffer{}, ErrChecksum } return out, nil } |
