// This is a derivitive work of Go's bytes.Buffer implementation. // // Originally copyright 2009 The Go Authors. All rights reserved. // // Modifications copyright 2018 Steven Allen. All rights reserved. // // Use of this source code is governed by both a BSD-style and an MIT-style // license that can be found in the LICENSE_BSD and LICENSE files. package pool import ( "io" ) // Buffer is a buffer like bytes.Buffer that: // // 1. Uses a buffer pool. // 2. Frees memory on read. // // If you only have a few buffers and read/write at a steady rate, *don't* use // this package, it'll be slower. // // However: // // 1. If you frequently create/destroy buffers, this implementation will be // significantly nicer to the allocator. // 2. If you have many buffers with bursty traffic, this implementation will use // significantly less memory. type Buffer struct { // Pool is the buffer pool to use. If nil, this Buffer will use the // global buffer pool. Pool *BufferPool buf []byte rOff int // Preallocated slice for samll reads/writes. // This is *really* important for performance and only costs 8 words. bootstrap [64]byte } // NewBuffer constructs a new buffer initialized to `buf`. // Unlike `bytes.Buffer`, we *copy* the buffer but don't reuse it (to ensure // that we *only* use buffers from the pool). func NewBuffer(buf []byte) *Buffer { b := new(Buffer) if len(buf) > 0 { b.buf = b.getBuf(len(buf)) copy(b.buf, buf) } return b } // NewBufferString is identical to NewBuffer *except* that it allows one to // initialize the buffer from a string (without having to allocate an // intermediate bytes slice). func NewBufferString(buf string) *Buffer { b := new(Buffer) if len(buf) > 0 { b.buf = b.getBuf(len(buf)) copy(b.buf, buf) } return b } func (b *Buffer) grow(n int) int { wOff := len(b.buf) bCap := cap(b.buf) if bCap >= wOff+n { b.buf = b.buf[:wOff+n] return wOff } bSize := b.Len() minCap := 2*bSize + n // Slide if cap >= minCap. // Reallocate otherwise. if bCap >= minCap { copy(b.buf, b.buf[b.rOff:]) } else { // Needs new buffer. newBuf := b.getBuf(minCap) copy(newBuf, b.buf[b.rOff:]) b.returnBuf() b.buf = newBuf } b.rOff = 0 b.buf = b.buf[:bSize+n] return bSize } func (b *Buffer) getPool() *BufferPool { if b.Pool == nil { return GlobalPool } return b.Pool } func (b *Buffer) returnBuf() { if cap(b.buf) > 0 && &b.buf[:1][0] != &b.bootstrap[0] { b.getPool().Put(b.buf) } b.buf = nil } func (b *Buffer) getBuf(n int) []byte { if n <= len(b.bootstrap) { return b.bootstrap[:n] } return b.getPool().Get(n) } // Len returns the number of bytes that can be read from this buffer. func (b *Buffer) Len() int { return len(b.buf) - b.rOff } // Cap returns the current capacity of the buffer. // // Note: Buffer *may* re-allocate when writing (or growing by) `n` bytes even if // `Cap() < Len() + n` to avoid excessive copying. func (b *Buffer) Cap() int { return cap(b.buf) } // Bytes returns the slice of bytes currently buffered in the Buffer. // // The buffer returned by Bytes is valid until the next call grow, truncate, // read, or write. Really, just don't touch the Buffer until you're done with // the return value of this function. func (b *Buffer) Bytes() []byte { return b.buf[b.rOff:] } // String returns the string representation of the buffer. // // It returns `` the buffer is a nil pointer. func (b *Buffer) String() string { if b == nil { return "" } return string(b.buf[b.rOff:]) } // WriteString writes a string to the buffer. // // This function is identical to Write except that it allows one to write a // string directly without allocating an intermediate byte slice. func (b *Buffer) WriteString(buf string) (int, error) { wOff := b.grow(len(buf)) return copy(b.buf[wOff:], buf), nil } // Truncate truncates the Buffer. // // Panics if `n > b.Len()`. // // This function may free memory by shrinking the internal buffer. func (b *Buffer) Truncate(n int) { if n < 0 || n > b.Len() { panic("truncation out of range") } b.buf = b.buf[:b.rOff+n] b.shrink() } // Reset is equivalent to Truncate(0). func (b *Buffer) Reset() { b.returnBuf() b.rOff = 0 } // ReadByte reads a single byte from the Buffer. func (b *Buffer) ReadByte() (byte, error) { if b.rOff >= len(b.buf) { return 0, io.EOF } c := b.buf[b.rOff] b.rOff++ return c, nil } // WriteByte writes a single byte to the Buffer. func (b *Buffer) WriteByte(c byte) error { wOff := b.grow(1) b.buf[wOff] = c return nil } // Grow grows the internal buffer such that `n` bytes can be written without // reallocating. func (b *Buffer) Grow(n int) { wOff := b.grow(n) b.buf = b.buf[:wOff] } // Next is an alternative to `Read` that returns a byte slice instead of taking // one. // // The returned byte slice is valid until the next read, write, grow, or // truncate. func (b *Buffer) Next(n int) []byte { m := b.Len() if m < n { n = m } data := b.buf[b.rOff : b.rOff+n] b.rOff += n return data } // Write writes the byte slice to the buffer. func (b *Buffer) Write(buf []byte) (int, error) { wOff := b.grow(len(buf)) return copy(b.buf[wOff:], buf), nil } // WriteTo copies from the buffer into the given writer until the buffer is // empty. func (b *Buffer) WriteTo(w io.Writer) (int64, error) { if b.rOff < len(b.buf) { n, err := w.Write(b.buf[b.rOff:]) b.rOff += n if b.rOff > len(b.buf) { panic("invalid write count") } b.shrink() return int64(n), err } return 0, nil } // TODO: implement ReadFrom // Read reads at most `len(buf)` bytes from the internal buffer into the given // buffer. func (b *Buffer) Read(buf []byte) (int, error) { if len(buf) == 0 { return 0, nil } if b.rOff >= len(b.buf) { return 0, io.EOF } n := copy(buf, b.buf[b.rOff:]) b.rOff += n b.shrink() return n, nil } func (b *Buffer) shrink() { l := b.Len() if l == 0 { b.returnBuf() b.rOff = 0 } else if l*8 < b.Cap() { // Only shrink when capacity > 8x length. Avoids shrinking too aggressively. newBuf := b.getBuf(l) copy(newBuf, b.buf[b.rOff:]) b.returnBuf() b.rOff = 0 b.buf = newBuf[:l] } }