package buffer
import (
"io"
"net"
"sync"
)
type PoolConfig struct {
StartSize int
PooledSize int
MaxSize int
}
var config = PoolConfig {
StartSize : 128 ,
PooledSize : 512 ,
MaxSize : 32768 ,
}
var buffers = map [int ]*sync .Pool {}
func initBuffers() {
for l := config .PooledSize ; l <= config .MaxSize ; l *= 2 {
buffers [l ] = new (sync .Pool )
}
}
func init() {
initBuffers ()
}
func Init (cfg PoolConfig ) {
config = cfg
initBuffers ()
}
func putBuf(buf []byte ) {
size := cap (buf )
if size < config .PooledSize {
return
}
if c := buffers [size ]; c != nil {
c .Put (buf [:0 ])
}
}
func getBuf(size int ) []byte {
if size >= config .PooledSize {
if c := buffers [size ]; c != nil {
v := c .Get ()
if v != nil {
return v .([]byte )
}
}
}
return make ([]byte , 0 , size )
}
type Buffer struct {
Buf []byte
toPool []byte
bufs [][]byte
}
func (b *Buffer ) EnsureSpace (s int ) {
if cap (b .Buf )-len (b .Buf ) < s {
b .ensureSpaceSlow (s )
}
}
func (b *Buffer ) ensureSpaceSlow (s int ) {
l := len (b .Buf )
if l > 0 {
if cap (b .toPool ) != cap (b .Buf ) {
putBuf (b .toPool )
}
if cap (b .bufs ) == 0 {
b .bufs = make ([][]byte , 0 , 8 )
}
b .bufs = append (b .bufs , b .Buf )
l = cap (b .toPool ) * 2
} else {
l = config .StartSize
}
if l > config .MaxSize {
l = config .MaxSize
}
b .Buf = getBuf (l )
b .toPool = b .Buf
}
func (b *Buffer ) AppendByte (data byte ) {
b .EnsureSpace (1 )
b .Buf = append (b .Buf , data )
}
func (b *Buffer ) AppendBytes (data []byte ) {
if len (data ) <= cap (b .Buf )-len (b .Buf ) {
b .Buf = append (b .Buf , data ...)
} else {
b .appendBytesSlow (data )
}
}
func (b *Buffer ) appendBytesSlow (data []byte ) {
for len (data ) > 0 {
b .EnsureSpace (1 )
sz := cap (b .Buf ) - len (b .Buf )
if sz > len (data ) {
sz = len (data )
}
b .Buf = append (b .Buf , data [:sz ]...)
data = data [sz :]
}
}
func (b *Buffer ) AppendString (data string ) {
if len (data ) <= cap (b .Buf )-len (b .Buf ) {
b .Buf = append (b .Buf , data ...)
} else {
b .appendStringSlow (data )
}
}
func (b *Buffer ) appendStringSlow (data string ) {
for len (data ) > 0 {
b .EnsureSpace (1 )
sz := cap (b .Buf ) - len (b .Buf )
if sz > len (data ) {
sz = len (data )
}
b .Buf = append (b .Buf , data [:sz ]...)
data = data [sz :]
}
}
func (b *Buffer ) Size () int {
size := len (b .Buf )
for _ , buf := range b .bufs {
size += len (buf )
}
return size
}
func (b *Buffer ) DumpTo (w io .Writer ) (written int , err error ) {
bufs := net .Buffers (b .bufs )
if len (b .Buf ) > 0 {
bufs = append (bufs , b .Buf )
}
n , err := bufs .WriteTo (w )
for _ , buf := range b .bufs {
putBuf (buf )
}
putBuf (b .toPool )
b .bufs = nil
b .Buf = nil
b .toPool = nil
return int (n ), err
}
func (b *Buffer ) BuildBytes (reuse ...[]byte ) []byte {
if len (b .bufs ) == 0 {
ret := b .Buf
b .toPool = nil
b .Buf = nil
return ret
}
var ret []byte
size := b .Size ()
if len (reuse ) == 1 && cap (reuse [0 ]) >= size {
ret = reuse [0 ][:0 ]
} else {
ret = make ([]byte , 0 , size )
}
for _ , buf := range b .bufs {
ret = append (ret , buf ...)
putBuf (buf )
}
ret = append (ret , b .Buf ...)
putBuf (b .toPool )
b .bufs = nil
b .toPool = nil
b .Buf = nil
return ret
}
type readCloser struct {
offset int
bufs [][]byte
}
func (r *readCloser ) Read (p []byte ) (n int , err error ) {
for _ , buf := range r .bufs {
x := copy (p [n :], buf [r .offset :])
n += x
if r .offset +x == len (buf ) {
r .offset = 0
r .bufs = r .bufs [1 :]
putBuf (buf )
} else {
r .offset += x
}
if n == len (p ) {
break
}
}
if len (r .bufs ) == 0 {
err = io .EOF
}
return
}
func (r *readCloser ) Close () error {
for _ , buf := range r .bufs {
putBuf (buf )
}
r .bufs = nil
return nil
}
func (b *Buffer ) ReadCloser () io .ReadCloser {
ret := &readCloser {0 , append (b .bufs , b .Buf )}
b .bufs = nil
b .toPool = nil
b .Buf = nil
return ret
}
The pages are generated with Golds v0.8.2 . (GOOS=linux GOARCH=amd64)
Golds is a Go 101 project developed by Tapir Liu .
PR and bug reports are welcome and can be submitted to the issue list .
Please follow @zigo_101 (reachable from the left QR code) to get the latest news of Golds .