syncthing/vendor/github.com/cznic/internal/buffer/buffer.go
2017-04-05 14:34:41 +00:00

147 lines
3.1 KiB
Go

// Copyright 2016 The Internal Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// Package buffer implements a pool of pointers to byte slices.
//
// Example usage pattern
//
// p := buffer.Get(size)
// b := *p // Now you can use b in any way you need.
// ...
// // When b will not be used anymore
// buffer.Put(p)
// ...
// // If b or p are not going out of scope soon, optionally
// b = nil
// p = nil
//
// Otherwise the pool cannot release the buffer on garbage collection.
//
// Do not do
//
// p := buffer.Get(size)
// b := *p
// ...
// buffer.Put(&b)
//
// or
//
// b := *buffer.Get(size)
// ...
// buffer.Put(&b)
package buffer
import (
"github.com/cznic/internal/slice"
"io"
)
// CGet returns a pointer to a byte slice of len size. The pointed to byte
// slice is zeroed up to its cap. CGet panics for size < 0.
//
// CGet is safe for concurrent use by multiple goroutines.
func CGet(size int) *[]byte { return slice.Bytes.CGet(size).(*[]byte) }
// Get returns a pointer to a byte slice of len size. The pointed to byte slice
// is not zeroed. Get panics for size < 0.
//
// Get is safe for concurrent use by multiple goroutines.
func Get(size int) *[]byte { return slice.Bytes.Get(size).(*[]byte) }
// Put puts a pointer to a byte slice into a pool for possible later reuse by
// CGet or Get.
//
// Put is safe for concurrent use by multiple goroutines.
func Put(p *[]byte) { slice.Bytes.Put(p) }
// Bytes is similar to bytes.Buffer but may generate less garbage when properly
// Closed. Zero value is ready to use.
type Bytes struct {
p *[]byte
}
// Bytes return the content of b. The result is R/O.
func (b *Bytes) Bytes() []byte {
if b.p != nil {
return *b.p
}
return nil
}
// Close will recycle the underlying storage, if any. After Close, b is again
// the zero value.
func (b *Bytes) Close() error {
if b.p != nil {
Put(b.p)
b.p = nil
}
return nil
}
// Len returns the size of content in b.
func (b *Bytes) Len() int {
if b.p != nil {
return len(*b.p)
}
return 0
}
// Reset discard the content of Bytes while keeping the internal storage, if any.
func (b *Bytes) Reset() {
if b.p != nil {
*b.p = (*b.p)[:0]
}
}
// Write writes p into b and returns (len(p), nil).
func (b *Bytes) Write(p []byte) (int, error) {
n := b.Len()
b.grow(n + len(p))
copy((*b.p)[n:], p)
return len(p), nil
}
// WriteByte writes p into b and returns nil.
func (b *Bytes) WriteByte(p byte) error {
n := b.Len()
b.grow(n + 1)
(*b.p)[n] = p
return nil
}
// WriteTo writes b's content to w and returns the number of bytes written to w
// and an error, if any.
func (b *Bytes) WriteTo(w io.Writer) (int64, error) {
n, err := w.Write(b.Bytes())
return int64(n), err
}
// WriteString writes s to b and returns (len(s), nil).
func (b *Bytes) WriteString(s string) (int, error) {
n := b.Len()
b.grow(n + len(s))
copy((*b.p)[n:], s)
return len(s), nil
}
func (b *Bytes) grow(n int) {
if b.p != nil {
if n <= cap(*b.p) {
*b.p = (*b.p)[:n]
return
}
np := Get(2 * n)
*np = (*np)[:n]
copy(*np, *b.p)
Put(b.p)
b.p = np
return
}
b.p = Get(n)
}