refactor: simplify based on blocking/non-blocking behavior changes; allow initial segment from outside of the used pool
This commit is contained in:
parent
513f9a3585
commit
cdbf48fa2f
198
block_test.go
Normal file
198
block_test.go
Normal file
@ -0,0 +1,198 @@
|
||||
package buffer_test
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"code.squareroundforest.org/arpio/buffer"
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
|
||||
func TestBlock(t *testing.T) {
|
||||
t.Run("read", func(t *testing.T) {
|
||||
segmentSize := 1 << 12
|
||||
blockAfter := segmentSize
|
||||
bc := make(chan struct{})
|
||||
g := &gen{
|
||||
max: 1 << 15,
|
||||
blockAfter: []int{blockAfter},
|
||||
unblock: map[int]<-chan struct{}{blockAfter: bc},
|
||||
}
|
||||
|
||||
r := buffer.BufferedReader(g, buffer.Options{BufferPool: buffer.NoPool(segmentSize)})
|
||||
b := make([]byte, 2*segmentSize)
|
||||
if n, err := r.Read(b); n != segmentSize || err != nil {
|
||||
t.Fatal(n, err)
|
||||
}
|
||||
|
||||
if string(b[:segmentSize]) != string(generate(segmentSize)) {
|
||||
t.Log(string(b))
|
||||
t.Log(string(generate(segmentSize)))
|
||||
t.Fatal("invalid content 1")
|
||||
}
|
||||
|
||||
ubc := make(chan struct{})
|
||||
go func() {
|
||||
if n, err := r.Read(b); n != segmentSize || err != nil {
|
||||
t.Fatal(n, err)
|
||||
}
|
||||
|
||||
if string(b[:segmentSize]) != string(generate(2 * segmentSize)[segmentSize:]) {
|
||||
t.Fatal("invalid content 2")
|
||||
}
|
||||
|
||||
close(ubc)
|
||||
}()
|
||||
|
||||
select {
|
||||
case <-time.After(10 * time.Millisecond):
|
||||
case <-ubc:
|
||||
t.Fatal("unexpected read return")
|
||||
}
|
||||
|
||||
close(bc)
|
||||
select {
|
||||
case <-time.After(10 * time.Millisecond):
|
||||
t.Fatal("timeout")
|
||||
case <-ubc:
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("read bytes", func(t *testing.T) {
|
||||
segmentSize := 1 << 12
|
||||
blockAfter := segmentSize
|
||||
bc := make(chan struct{})
|
||||
g := &gen{
|
||||
max: 1 << 15,
|
||||
blockAfter: []int{blockAfter},
|
||||
unblock: map[int]<-chan struct{}{blockAfter: bc},
|
||||
}
|
||||
|
||||
r := buffer.BufferedReader(g, buffer.Options{BufferPool: buffer.NoPool(segmentSize)})
|
||||
ubc := make(chan struct{})
|
||||
go func() {
|
||||
if b, err := r.ReadBytes([]byte("123"), 2*segmentSize); len(b) != 0 || err != nil {
|
||||
t.Fatal(len(b), err)
|
||||
}
|
||||
|
||||
close(ubc)
|
||||
}()
|
||||
|
||||
select {
|
||||
case <-time.After(10 * time.Millisecond):
|
||||
case <-ubc:
|
||||
t.Fatal("unexpected read return")
|
||||
}
|
||||
|
||||
close(bc)
|
||||
select {
|
||||
case <-time.After(10 * time.Millisecond):
|
||||
t.Fatal("timeout")
|
||||
case <-ubc:
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("read utf8", func(t *testing.T) {
|
||||
segmentSize := 1 << 12
|
||||
blockAfter := segmentSize
|
||||
bc := make(chan struct{})
|
||||
g := &gen{
|
||||
max: 1 << 15,
|
||||
blockAfter: []int{blockAfter},
|
||||
unblock: map[int]<-chan struct{}{blockAfter: bc},
|
||||
}
|
||||
|
||||
r := buffer.BufferedReader(g, buffer.Options{BufferPool: buffer.NoPool(segmentSize)})
|
||||
ubc := make(chan struct{})
|
||||
go func() {
|
||||
if r, n, err := r.ReadUTF8(2 * segmentSize); len(r) != 2*segmentSize ||
|
||||
n != 2*segmentSize ||
|
||||
err != nil {
|
||||
t.Fatal(len(r), err)
|
||||
}
|
||||
|
||||
close(ubc)
|
||||
}()
|
||||
|
||||
select {
|
||||
case <-time.After(10 * time.Millisecond):
|
||||
case <-ubc:
|
||||
t.Fatal("unexpected read return")
|
||||
}
|
||||
|
||||
close(bc)
|
||||
select {
|
||||
case <-time.After(10 * time.Millisecond):
|
||||
t.Fatal("timeout")
|
||||
case <-ubc:
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("peek", func(t *testing.T) {
|
||||
segmentSize := 1 << 12
|
||||
blockAfter := segmentSize
|
||||
bc := make(chan struct{})
|
||||
g := &gen{
|
||||
max: 1 << 15,
|
||||
blockAfter: []int{blockAfter},
|
||||
unblock: map[int]<-chan struct{}{blockAfter: bc},
|
||||
}
|
||||
|
||||
r := buffer.BufferedReader(g, buffer.Options{BufferPool: buffer.NoPool(segmentSize)})
|
||||
ubc := make(chan struct{})
|
||||
go func() {
|
||||
if b, err := r.Peek(2 * segmentSize); len(b) != 2*segmentSize || err != nil {
|
||||
t.Fatal(len(b), err)
|
||||
}
|
||||
|
||||
close(ubc)
|
||||
}()
|
||||
|
||||
select {
|
||||
case <-time.After(10 * time.Millisecond):
|
||||
case <-ubc:
|
||||
t.Fatal("unexpected read return")
|
||||
}
|
||||
|
||||
close(bc)
|
||||
select {
|
||||
case <-time.After(10 * time.Millisecond):
|
||||
t.Fatal("timeout")
|
||||
case <-ubc:
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("write to", func(t *testing.T) {
|
||||
segmentSize := 1 << 12
|
||||
blockAfter := segmentSize
|
||||
bc := make(chan struct{})
|
||||
g := &gen{
|
||||
max: 1 << 15,
|
||||
blockAfter: []int{blockAfter},
|
||||
unblock: map[int]<-chan struct{}{blockAfter: bc},
|
||||
}
|
||||
|
||||
r := buffer.BufferedReader(g, buffer.Options{BufferPool: buffer.NoPool(segmentSize)})
|
||||
ubc := make(chan struct{})
|
||||
go func() {
|
||||
var b bytes.Buffer
|
||||
if n, err := r.WriteTo(&b); n != 1<<15 || err != nil {
|
||||
t.Fatal(b, err)
|
||||
}
|
||||
|
||||
close(ubc)
|
||||
}()
|
||||
|
||||
select {
|
||||
case <-time.After(10 * time.Millisecond):
|
||||
case <-ubc:
|
||||
t.Fatal("unexpected read return")
|
||||
}
|
||||
|
||||
close(bc)
|
||||
select {
|
||||
case <-time.After(10 * time.Millisecond):
|
||||
t.Fatal("timeout")
|
||||
case <-ubc:
|
||||
}
|
||||
})
|
||||
}
|
||||
@ -11,7 +11,7 @@ func TestBuffered(t *testing.T) {
|
||||
t.Run(title, func(t *testing.T) {
|
||||
t.Run("none buffered", func(t *testing.T) {
|
||||
g := &gen{max: 1 << 15}
|
||||
o := buffer.Options{Pool: buffer.NoPool(1 << 12)}
|
||||
o := buffer.Options{BufferPool: buffer.NoPool(1 << 12)}
|
||||
r := cr(g, o)
|
||||
b := r.Buffered()
|
||||
if len(b) != 0 {
|
||||
@ -25,7 +25,7 @@ func TestBuffered(t *testing.T) {
|
||||
fastErr: true,
|
||||
}
|
||||
|
||||
o := buffer.Options{Pool: buffer.NoPool(1 << 12)}
|
||||
o := buffer.Options{BufferPool: buffer.NoPool(1 << 12)}
|
||||
r := cr(g, o)
|
||||
b, err := r.Peek(18)
|
||||
if err != nil {
|
||||
@ -44,7 +44,7 @@ func TestBuffered(t *testing.T) {
|
||||
|
||||
t.Run("all buffered", func(t *testing.T) {
|
||||
g := &gen{max: 1 << 15}
|
||||
o := buffer.Options{Pool: buffer.NoPool(64)}
|
||||
o := buffer.Options{BufferPool: buffer.NoPool(64)}
|
||||
r := cr(g, o)
|
||||
b, err := r.Peek(48)
|
||||
if err != nil {
|
||||
@ -63,7 +63,7 @@ func TestBuffered(t *testing.T) {
|
||||
|
||||
t.Run("buffered across segments", func(t *testing.T) {
|
||||
g := &gen{max: 1 << 15}
|
||||
o := buffer.Options{Pool: buffer.NoPool(64)}
|
||||
o := buffer.Options{BufferPool: buffer.NoPool(64)}
|
||||
r := cr(g, o)
|
||||
b, err := r.Peek(144)
|
||||
if err != nil {
|
||||
@ -82,7 +82,7 @@ func TestBuffered(t *testing.T) {
|
||||
|
||||
t.Run("buffered mid segment", func(t *testing.T) {
|
||||
g := &gen{max: 1 << 15}
|
||||
o := buffer.Options{Pool: buffer.NoPool(128)}
|
||||
o := buffer.Options{BufferPool: buffer.NoPool(128)}
|
||||
r := cr(g, o)
|
||||
b := make([]byte, 32)
|
||||
n, err := r.Read(b)
|
||||
@ -106,7 +106,7 @@ func TestBuffered(t *testing.T) {
|
||||
|
||||
t.Run("buffered mid segment across segments", func(t *testing.T) {
|
||||
g := &gen{max: 1 << 15}
|
||||
o := buffer.Options{Pool: buffer.NoPool(128)}
|
||||
o := buffer.Options{BufferPool: buffer.NoPool(128)}
|
||||
r := cr(g, o)
|
||||
b, err := r.Peek(288)
|
||||
if err != nil {
|
||||
@ -125,7 +125,7 @@ func TestBuffered(t *testing.T) {
|
||||
|
||||
t.Run("zero buffered mid segment", func(t *testing.T) {
|
||||
g := &gen{max: 1 << 15}
|
||||
o := buffer.Options{Pool: buffer.NoPool(64)}
|
||||
o := buffer.Options{BufferPool: buffer.NoPool(64)}
|
||||
r := cr(g, o)
|
||||
b := make([]byte, 64)
|
||||
n, err := r.Read(b)
|
||||
|
||||
@ -63,7 +63,7 @@ func (c *content) writeTo() {
|
||||
return
|
||||
}
|
||||
|
||||
err := fmt.Errorf("panic provided WriterTo: %v", r)
|
||||
err := fmt.Errorf("panic from provided WriterTo: %v", r)
|
||||
w.w <- syncMessage{err: err}
|
||||
close(w.w)
|
||||
}()
|
||||
|
||||
118
content_test.go
118
content_test.go
@ -11,8 +11,8 @@ func TestContent(t *testing.T) {
|
||||
t.Run("eof", func(t *testing.T) {
|
||||
c := buffer.ContentFunc(func(w io.Writer) (int64, error) {
|
||||
var n int64
|
||||
for i := 0; i < 3; i++ {
|
||||
ni, err := w.Write([]byte("123456789")[i*3 : i*3+3])
|
||||
for i := 0; i < 4; i++ {
|
||||
ni, err := w.Write([]byte("123456789012")[i*3 : i*3+3])
|
||||
n += int64(ni)
|
||||
if err != nil {
|
||||
return n, err
|
||||
@ -23,18 +23,21 @@ func TestContent(t *testing.T) {
|
||||
})
|
||||
|
||||
p := &fakePool{allocSize: 2}
|
||||
o := buffer.Options{Pool: p}
|
||||
o := buffer.Options{BufferPool: p}
|
||||
r := buffer.BufferedContent(c, o)
|
||||
b := make([]byte, 3)
|
||||
for i := 0; i < 3; i++ {
|
||||
exp := []byte("123456789012")
|
||||
for i := 0; i < 8; i++ {
|
||||
n, err := r.Read(b)
|
||||
if n != 3 || err != nil {
|
||||
t.Fatal(n, err)
|
||||
if n != 2-i%2 || err != nil {
|
||||
t.Fatal(i, n, err)
|
||||
}
|
||||
|
||||
if string(b) != "123456789"[i*3:i*3+3] {
|
||||
t.Fatal(string(b))
|
||||
if string(b[:n]) != string(exp[:n]) {
|
||||
t.Fatal(i, string(b[:n]), string(exp[:n]))
|
||||
}
|
||||
|
||||
exp = exp[n:]
|
||||
}
|
||||
|
||||
n, err := r.Read(b)
|
||||
@ -49,7 +52,7 @@ func TestContent(t *testing.T) {
|
||||
})
|
||||
|
||||
p := &fakePool{allocSize: 2}
|
||||
o := buffer.Options{Pool: p}
|
||||
o := buffer.Options{BufferPool: p}
|
||||
r := buffer.BufferedContent(c, o)
|
||||
b := make([]byte, 3)
|
||||
n, err := r.Read(b)
|
||||
@ -61,8 +64,8 @@ func TestContent(t *testing.T) {
|
||||
t.Run("writer error", func(t *testing.T) {
|
||||
c := buffer.ContentFunc(func(w io.Writer) (int64, error) {
|
||||
var n int64
|
||||
for i := 0; i < 3; i++ {
|
||||
ni, err := w.Write([]byte("123456789")[i*3 : i*3+3])
|
||||
for i := 0; i < 4; i++ {
|
||||
ni, err := w.Write([]byte("123456789012")[i*3 : i*3+3])
|
||||
n += int64(ni)
|
||||
if err != nil {
|
||||
return n, err
|
||||
@ -73,18 +76,21 @@ func TestContent(t *testing.T) {
|
||||
})
|
||||
|
||||
p := &fakePool{allocSize: 2}
|
||||
o := buffer.Options{Pool: p}
|
||||
o := buffer.Options{BufferPool: p}
|
||||
r := buffer.BufferedContent(c, o)
|
||||
b := make([]byte, 3)
|
||||
for i := 0; i < 3; i++ {
|
||||
exp := []byte("123456789012")
|
||||
for i := 0; i < 8; i++ {
|
||||
n, err := r.Read(b)
|
||||
if n != 3 || err != nil {
|
||||
t.Fatal(n, err)
|
||||
if n != 2-i%2 || err != nil {
|
||||
t.Fatal(i, n, err)
|
||||
}
|
||||
|
||||
if string(b) != "123456789"[i*3:i*3+3] {
|
||||
if string(b[:n]) != string(exp[:n]) {
|
||||
t.Fatal(string(b))
|
||||
}
|
||||
|
||||
exp = exp[n:]
|
||||
}
|
||||
|
||||
n, err := r.Read(b)
|
||||
@ -99,7 +105,7 @@ func TestContent(t *testing.T) {
|
||||
})
|
||||
|
||||
p := &fakePool{allocSize: 2}
|
||||
o := buffer.Options{Pool: p}
|
||||
o := buffer.Options{BufferPool: p}
|
||||
r := buffer.BufferedContent(c, o)
|
||||
b := make([]byte, 3)
|
||||
n, err := r.Read(b)
|
||||
@ -127,16 +133,16 @@ func TestContent(t *testing.T) {
|
||||
errAfter: []int{1},
|
||||
}
|
||||
|
||||
o := buffer.Options{Pool: p}
|
||||
o := buffer.Options{BufferPool: p}
|
||||
r := buffer.BufferedContent(c, o)
|
||||
b, ok, err := r.ReadBytes([]byte("67"), 12)
|
||||
if string(b) != "12" /* segment size og 2 by the pool */ || ok || err != nil {
|
||||
t.Fatal(string(b), ok, err)
|
||||
b, err := r.ReadBytes([]byte("67"), 12)
|
||||
if len(b) != 0 || err != nil {
|
||||
t.Fatal(string(b), err)
|
||||
}
|
||||
|
||||
b, ok, err = r.ReadBytes([]byte("67"), 12)
|
||||
if len(b) != 0 || ok || !errors.Is(err, errTest) {
|
||||
t.Fatal(string(b), ok, err)
|
||||
b, err = r.ReadBytes([]byte("67"), 12)
|
||||
if len(b) != 0 || err != nil {
|
||||
t.Fatal(string(b), err)
|
||||
}
|
||||
})
|
||||
|
||||
@ -159,11 +165,11 @@ func TestContent(t *testing.T) {
|
||||
errAfter: []int{0},
|
||||
}
|
||||
|
||||
o := buffer.Options{Pool: p}
|
||||
o := buffer.Options{BufferPool: p}
|
||||
r := buffer.BufferedContent(c, o)
|
||||
b, ok, err := r.ReadBytes([]byte("67"), 12)
|
||||
if len(b) != 0 || ok || !errors.Is(err, errTest) {
|
||||
t.Fatal(string(b), ok, err)
|
||||
b, err := r.ReadBytes([]byte("67"), 12)
|
||||
if len(b) != 0 || !errors.Is(err, errTest) {
|
||||
t.Fatal(string(b), err)
|
||||
}
|
||||
})
|
||||
|
||||
@ -180,16 +186,16 @@ func TestContent(t *testing.T) {
|
||||
errAfter: []int{1},
|
||||
}
|
||||
|
||||
o := buffer.Options{Pool: p}
|
||||
o := buffer.Options{BufferPool: p}
|
||||
r := buffer.BufferedContent(c, o)
|
||||
b, ok, err := r.ReadBytes([]byte("67"), 12)
|
||||
if string(b) != "12" /* segment size og 2 by the pool */ || ok || err != nil {
|
||||
t.Fatal(string(b), ok, err)
|
||||
b, err := r.ReadBytes([]byte("67"), 12)
|
||||
if len(b) != 0 || err != nil {
|
||||
t.Fatal(string(b), err)
|
||||
}
|
||||
|
||||
b, ok, err = r.ReadBytes([]byte("67"), 12)
|
||||
if len(b) != 0 || ok || !errors.Is(err, errTest) {
|
||||
t.Fatal(string(b), ok, err)
|
||||
b, err = r.ReadBytes([]byte("67"), 12)
|
||||
if len(b) != 0 || err != nil {
|
||||
t.Fatal(string(b), err)
|
||||
}
|
||||
})
|
||||
|
||||
@ -199,22 +205,26 @@ func TestContent(t *testing.T) {
|
||||
w.Write(nil)
|
||||
w.Write([]byte("456"))
|
||||
w.Write([]byte("789"))
|
||||
w.Write([]byte("012"))
|
||||
return 0, nil
|
||||
})
|
||||
|
||||
p := &fakePool{allocSize: 2}
|
||||
o := buffer.Options{Pool: p}
|
||||
o := buffer.Options{BufferPool: p}
|
||||
r := buffer.BufferedContent(c, o)
|
||||
b := make([]byte, 3)
|
||||
for i := 0; i < 3; i++ {
|
||||
exp := []byte("123456789012")
|
||||
for i := 0; i < 8; i++ {
|
||||
n, err := r.Read(b)
|
||||
if n != 3 || err != nil {
|
||||
if n != 2-i%2 || err != nil {
|
||||
t.Fatal(n, err)
|
||||
}
|
||||
|
||||
if string(b) != "123456789"[i*3:i*3+3] {
|
||||
t.Fatal(string(b))
|
||||
if string(b[:n]) != string(exp[:n]) {
|
||||
t.Fatal(string(b[:n]))
|
||||
}
|
||||
|
||||
exp = exp[n:]
|
||||
}
|
||||
|
||||
n, err := r.Read(b)
|
||||
@ -229,22 +239,26 @@ func TestContent(t *testing.T) {
|
||||
w.Write([]byte("123"))
|
||||
w.Write([]byte("456"))
|
||||
w.Write([]byte("789"))
|
||||
w.Write([]byte("012"))
|
||||
return 0, nil
|
||||
})
|
||||
|
||||
p := &fakePool{allocSize: 2}
|
||||
o := buffer.Options{Pool: p}
|
||||
o := buffer.Options{BufferPool: p}
|
||||
r := buffer.BufferedContent(c, o)
|
||||
b := make([]byte, 3)
|
||||
for i := 0; i < 3; i++ {
|
||||
exp := []byte("123456789012")
|
||||
for i := 0; i < 8; i++ {
|
||||
n, err := r.Read(b)
|
||||
if n != 3 || err != nil {
|
||||
if n != 2-i%2 || err != nil {
|
||||
t.Fatal(n, err)
|
||||
}
|
||||
|
||||
if string(b) != "123456789"[i*3:i*3+3] {
|
||||
if string(b[:n]) != string(exp[:n]) {
|
||||
t.Fatal(string(b))
|
||||
}
|
||||
|
||||
exp = exp[n:]
|
||||
}
|
||||
|
||||
n, err := r.Read(b)
|
||||
@ -268,7 +282,7 @@ func TestContent(t *testing.T) {
|
||||
})
|
||||
|
||||
p := &fakePool{allocSize: 3}
|
||||
o := buffer.Options{Pool: p}
|
||||
o := buffer.Options{BufferPool: p}
|
||||
r := buffer.BufferedContent(c, o)
|
||||
b := make([]byte, 3)
|
||||
for i := 0; i < 3; i++ {
|
||||
@ -301,16 +315,16 @@ func TestContent(t *testing.T) {
|
||||
errAfter: []int{1},
|
||||
}
|
||||
|
||||
o := buffer.Options{Pool: p}
|
||||
o := buffer.Options{BufferPool: p}
|
||||
r := buffer.BufferedContent(c, o)
|
||||
b, ok, err := r.ReadBytes([]byte("67"), 12)
|
||||
if string(b) != "12" /* segment size og 2 by the pool */ || ok || err != nil {
|
||||
t.Fatal(string(b), ok, err)
|
||||
b, err := r.ReadBytes([]byte("67"), 12)
|
||||
if len(b) != 0 || err != nil {
|
||||
t.Fatal(string(b), err)
|
||||
}
|
||||
|
||||
b, ok, err = r.ReadBytes([]byte("67"), 12)
|
||||
if len(b) != 0 || ok || !errors.Is(err, errTest) || !errors.Is(err, errTest2) {
|
||||
t.Fatal(string(b), ok, err)
|
||||
b, err = r.ReadBytes([]byte("67"), 12)
|
||||
if len(b) != 0 || err != nil {
|
||||
t.Fatal(string(b), err)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
@ -17,6 +17,8 @@ type gen struct {
|
||||
customContentAfter []int
|
||||
customContent map[int][]byte
|
||||
counter int
|
||||
blockAfter []int
|
||||
unblock map[int]<-chan struct{}
|
||||
}
|
||||
|
||||
type writer struct {
|
||||
@ -39,6 +41,11 @@ func (g *gen) Read(p []byte) (int, error) {
|
||||
return 0, io.EOF
|
||||
}
|
||||
|
||||
if len(g.blockAfter) > 0 && g.counter >= g.blockAfter[0] {
|
||||
<-g.unblock[g.blockAfter[0]]
|
||||
g.blockAfter = g.blockAfter[1:]
|
||||
}
|
||||
|
||||
if len(g.nullReadAfter) > 0 && g.counter >= g.nullReadAfter[0] {
|
||||
g.nullReadAfter = g.nullReadAfter[1:]
|
||||
return 0, nil
|
||||
|
||||
115
lib.go
115
lib.go
@ -1,8 +1,8 @@
|
||||
// Package buffer provides pooled Buffer IO for Go programs.
|
||||
//
|
||||
// It implements a reader similar to bufio.Reader. The underlying memory buffers can be used from a synchronized
|
||||
// pool. It implements a writer that can be used to avoid writing too small number of bytes to an underlying
|
||||
// writer.
|
||||
// pool. It implements a writer that can be used to write data to an underlying writer in larger, buffered,
|
||||
// chunks.
|
||||
package buffer
|
||||
|
||||
import (
|
||||
@ -10,9 +10,9 @@ import (
|
||||
"io"
|
||||
)
|
||||
|
||||
// Pool defines the interface for the used buffer pool. The buffered reader can be used either with the built-in
|
||||
// default pool, noop pool, or with a custom pool implementation.
|
||||
type Pool interface {
|
||||
// BufferPool defines the interface for the used buffer pool. The buffered reader or writer can be used either
|
||||
// with the built-in default pool, noop pool, or with a custom pool implementation.
|
||||
type BufferPool interface {
|
||||
|
||||
// Get should return a non-zero length byte slice. In case it returns a zero length byte slice, or an
|
||||
// explicit error, the read operations will fail.
|
||||
@ -20,35 +20,39 @@ type Pool interface {
|
||||
// It is OK but not recommended to return varying sizes of byte slices.
|
||||
Get() ([]byte, error)
|
||||
|
||||
// The reader always puts back the byte slices taken by Get, using Put.
|
||||
// The reader puts back the byte slices taken by Get, using Put, when it does not use them anymore.
|
||||
Put([]byte)
|
||||
}
|
||||
|
||||
// Options provides options for the Reader.
|
||||
type Options struct {
|
||||
|
||||
// Pool defines the buffer pool to be used. It defaults to the pool created by DefaultPool(). It is
|
||||
// expected to explicitly set the Pool instance, otherwise, not defining any globals, each Reader
|
||||
// BufferPool defines the buffer pool to be used. It defaults to the pool created by DefaultPool(). It
|
||||
// is expected to explicitly set the Pool instance, otherwise, not defining any globals, each Reader
|
||||
// instance will create its own pool.
|
||||
Pool Pool
|
||||
BufferPool BufferPool
|
||||
|
||||
// InitialSegment allows to initialize the buffer with a memory space already available to the user code
|
||||
// without requesting it from the used pool.
|
||||
InitialSegment []byte
|
||||
}
|
||||
|
||||
// ContentFunc wraps a function to implement the io.WriterTo interface. Function implementations should be
|
||||
// reader to be executed in goroutines other than what they were created in.
|
||||
// ready to be executed in goroutines other than what they were created in.
|
||||
type ContentFunc func(io.Writer) (int64, error)
|
||||
|
||||
// Reader wraps an underlying io.Reader or io.WriterTo, and provides buffered io via its methods. Initialize it
|
||||
// Reader wraps an underlying io.Reader or io.WriterTo, and provides buffered IO via its methods. Initialize it
|
||||
// via BufferedReader or BufferedContent.
|
||||
//
|
||||
// It reads from the underlying source until the first error, but only returns an error when the buffer is
|
||||
// empty. Once the underlying reader returned an error, it doesn't attempt to read from it anymore.
|
||||
// empty. Once the underlying reader returned an error, it does not attempt to read from it anymore.
|
||||
//
|
||||
// The reader does not support concurrent access.
|
||||
type Reader struct {
|
||||
reader *reader
|
||||
}
|
||||
|
||||
// Writer wraps an underlying io.Writer, and provides buffered io via its methods. Initialize it via
|
||||
// Writer wraps an underlying io.Writer and provides buffered IO via its methods. Initialize it via
|
||||
// BufferedWriter.
|
||||
//
|
||||
// It writes the input bytes into an internal buffer, and flushes them to the underlying writer only when the
|
||||
@ -63,7 +67,7 @@ var (
|
||||
// ErrZeroAllocation is returned when the used pool returned a zero length byte slice.
|
||||
ErrZeroAllocation = errors.New("zero allocation")
|
||||
|
||||
// ErrAbort is returned to the writer process in case of buffered content, when the reader
|
||||
// ErrAbort is returned to the writer process when using buffered content, when the reader
|
||||
// experienced an error. ErrAbort is returned to the reader process, if Close() was called and no read
|
||||
// error was received before it.
|
||||
ErrAbort = errors.New("read aborted")
|
||||
@ -71,7 +75,7 @@ var (
|
||||
|
||||
// DefultPool initializes a synchronized pool that stores and returns byte slices of allocSize length. It can be
|
||||
// used with multiple readers concurrently.
|
||||
func DefaultPool(allocSize int) Pool {
|
||||
func DefaultPool(allocSize int) BufferPool {
|
||||
if allocSize <= 0 {
|
||||
allocSize = 1 << 12
|
||||
}
|
||||
@ -79,8 +83,8 @@ func DefaultPool(allocSize int) Pool {
|
||||
return newPool(allocSize)
|
||||
}
|
||||
|
||||
// NoPool returns a noop pool.
|
||||
func NoPool(allocSize int) Pool {
|
||||
// NoPool returns a noop pool that allocates memory on every call to Get() and does nothing on Put().
|
||||
func NoPool(allocSize int) BufferPool {
|
||||
if allocSize <= 0 {
|
||||
allocSize = 1 << 12
|
||||
}
|
||||
@ -99,11 +103,16 @@ func BufferedReader(in io.Reader, o Options) Reader {
|
||||
return Reader{}
|
||||
}
|
||||
|
||||
if o.Pool == nil {
|
||||
o.Pool = DefaultPool(1 << 12)
|
||||
if o.BufferPool == nil {
|
||||
o.BufferPool = DefaultPool(1 << 12)
|
||||
}
|
||||
|
||||
return Reader{reader: &reader{options: o, in: in}}
|
||||
r := Reader{reader: &reader{options: o, in: in}}
|
||||
if len(o.InitialSegment) > 0 {
|
||||
r.reader.segments = [][]byte{o.InitialSegment}
|
||||
}
|
||||
|
||||
return r
|
||||
}
|
||||
|
||||
// BufferedContent creates a buffered reader using the input content (io.WriterTo) as the underlying source.
|
||||
@ -111,7 +120,7 @@ func BufferedReader(in io.Reader, o Options) Reader {
|
||||
// It is similar to an io.Pipe, but with dynamic and pooled buffering internally. The individual Write calls are
|
||||
// blocked until the reading side requests more data.
|
||||
//
|
||||
// The provided WriterTo instances need to be safe to call in goroutines other than they were created in. The
|
||||
// The provided WriterTo instances need to be safe to call in goroutines other than they were created in. If the
|
||||
// writer function returns with nil error, it will be interpreted as EOF on the reader side. When the reader
|
||||
// side experiences an error, and the writer still has content to be written, the passed in io.Writer will
|
||||
// return an ErrAbort error.
|
||||
@ -120,8 +129,8 @@ func BufferedContent(c io.WriterTo, o Options) Reader {
|
||||
return Reader{}
|
||||
}
|
||||
|
||||
if o.Pool == nil {
|
||||
o.Pool = DefaultPool(1 << 12)
|
||||
if o.BufferPool == nil {
|
||||
o.BufferPool = DefaultPool(1 << 12)
|
||||
}
|
||||
|
||||
return Reader{reader: &reader{options: o, in: mkcontent(c)}}
|
||||
@ -129,10 +138,14 @@ func BufferedContent(c io.WriterTo, o Options) Reader {
|
||||
|
||||
// Read reads max len(p) copied to p and returns how many bytes were read.
|
||||
//
|
||||
// It only returns an error when the buffer is empty. It only returns an error when the Pool.Get fails or the
|
||||
// underlying reader returns an error.
|
||||
// It only returns an error when the buffer is empty. It only returns an error when the BufferPool.Get fails or
|
||||
// the underlying reader returns an error.
|
||||
//
|
||||
// It may return zero read length and nil error, but only if the underlying reader did so.
|
||||
//
|
||||
// It does not block when the buffer is not empty, even if the underlying reader would block on the next read.
|
||||
//
|
||||
// It only allocates a single segment of memory, or none if one was provided during innitialization.
|
||||
func (r Reader) Read(p []byte) (int, error) {
|
||||
if r.reader == nil {
|
||||
return 0, io.EOF
|
||||
@ -143,22 +156,17 @@ func (r Reader) Read(p []byte) (int, error) {
|
||||
|
||||
// ReadBytes reads until the first occurence of delimiter in the input, within max length.
|
||||
//
|
||||
// It returns the bytes, true and nil error, when the delimiter was found within max. In this case it consumes
|
||||
// It returns the bytes and nil error, when the delimiter was found within max. In this case it consumes
|
||||
// the buffer until and including the delimiter. If the underlying reader returned meanwhile a non-nil error,
|
||||
// including EOF, it will be returned on subsequent reads, but only after the internal buffer was consumed.
|
||||
//
|
||||
// It returns zero length bytes, false and nil error, when the delimiter was not found within max, and the
|
||||
// underlying reader didn't return an error.
|
||||
// It returns zero length bytes and nil error, when the delimiter was not found within max.
|
||||
//
|
||||
// It returns max or less bytes, false and nil error, if the delimiter was not found within max, there are
|
||||
// buffered bytes, the underlying reader returned an error. It consumes the returned bytes from the buffer. The
|
||||
// delimiter may still be found in the remaining buffered bytes during subsequent calls.
|
||||
//
|
||||
// It returns zero length bytes, false and non-nil error, if the buffer is empty and the underlying reader
|
||||
// previously returned an error.
|
||||
func (r Reader) ReadBytes(delimiter []byte, max int) ([]byte, bool, error) {
|
||||
// It blocks only when less data is buffered than max, the delimiter was not found within the range defined by
|
||||
// max, and the underlying reader blocks.
|
||||
func (r Reader) ReadBytes(delimiter []byte, max int) ([]byte, error) {
|
||||
if r.reader == nil {
|
||||
return nil, false, io.EOF
|
||||
return nil, io.EOF
|
||||
}
|
||||
|
||||
return r.reader.readBytes(delimiter, max)
|
||||
@ -175,8 +183,11 @@ func (r Reader) ReadBytes(delimiter []byte, max int) ([]byte, bool, error) {
|
||||
// nil error.
|
||||
//
|
||||
// It supports recovery of UTF8 streams by skipping the invalid characters. In such cases, first it returns the
|
||||
// valid characters with the number of bytes consumed and nil error, then in the subsequent call, it returns
|
||||
// valid characters with the number of bytes consumed and nil error, then in a subsequent call, it returns
|
||||
// zero characters, 1 and nil error.
|
||||
//
|
||||
// It blocks only when there is not enough data buffered to determine the next UTF8 character and the underlying
|
||||
// reader blocks.
|
||||
func (r Reader) ReadUTF8(max int) ([]rune, int, error) {
|
||||
if r.reader == nil {
|
||||
return nil, 0, io.EOF
|
||||
@ -191,6 +202,8 @@ func (r Reader) ReadUTF8(max int) ([]rune, int, error) {
|
||||
// by Read, ReadBytes, ReadUTF8 or WriteTo.
|
||||
//
|
||||
// The returned byte slice is not a copy of the buffered bytes, and therefore should not be modified.
|
||||
//
|
||||
// It blocks when there is less data buffered than the range defined by max and the underlying reader blocks.
|
||||
func (r Reader) Peek(max int) ([]byte, error) {
|
||||
if r.reader == nil {
|
||||
return nil, io.EOF
|
||||
@ -215,6 +228,8 @@ func (r Reader) Buffered() []byte {
|
||||
//
|
||||
// It is important that the provided writer must not modify the slice data, as defined in the io.Writer
|
||||
// interface documentation.
|
||||
//
|
||||
// It blocks when the underlying reader blocks.
|
||||
func (r Reader) WriteTo(w io.Writer) (int64, error) {
|
||||
if r.reader == nil {
|
||||
return 0, nil
|
||||
@ -223,8 +238,11 @@ func (r Reader) WriteTo(w io.Writer) (int64, error) {
|
||||
return r.reader.writeTo(w)
|
||||
}
|
||||
|
||||
// Close releases the resource held by the Reader, and puts back the underlying byte buffers into the used pool.
|
||||
// The reader cannot be used for read operations after Close() was called.
|
||||
// Close releases the resource held by the Reader, and puts the underlying byte buffers, that were
|
||||
// requested from the pool, back into the used pool. The reader cannot be used for read operations after Close()
|
||||
// was called.
|
||||
//
|
||||
// It does not close the underlying reader.
|
||||
func (r Reader) Close() {
|
||||
if r.reader == nil {
|
||||
return
|
||||
@ -239,15 +257,22 @@ func BufferedWriter(out io.Writer, o Options) Writer {
|
||||
return Writer{}
|
||||
}
|
||||
|
||||
if o.Pool == nil {
|
||||
o.Pool = DefaultPool(1 << 12)
|
||||
if o.BufferPool == nil {
|
||||
o.BufferPool = DefaultPool(1 << 12)
|
||||
}
|
||||
|
||||
return Writer{writer: &writer{out: out, options: o}}
|
||||
w := Writer{writer: &writer{out: out, options: o}}
|
||||
if len(o.InitialSegment) > 0 {
|
||||
w.writer.buffer = o.InitialSegment
|
||||
}
|
||||
|
||||
return w
|
||||
}
|
||||
|
||||
// Write writes to the writer's buffer, and if the buffer is full, it causes writing out the buffer's contents
|
||||
// to the underlying writer.
|
||||
//
|
||||
// It blocks when there is not enough buffer space for the data being written and the underlying writer blocks.
|
||||
func (w Writer) Write(p []byte) (int, error) {
|
||||
if w.writer == nil {
|
||||
return 0, errors.New("unitialized writer")
|
||||
@ -270,6 +295,8 @@ func (w Writer) ReadFrom(r io.Reader) (int64, error) {
|
||||
|
||||
// Flush forces the writer to flush the buffered content to the underlying writer. After flushed, the writer
|
||||
// still accepts further writes.
|
||||
//
|
||||
// It blocks when there is buffered data to write out and the underlying writer blocks.
|
||||
func (w Writer) Flush() error {
|
||||
if w.writer == nil {
|
||||
return nil
|
||||
@ -280,6 +307,10 @@ func (w Writer) Flush() error {
|
||||
|
||||
// Close flushes the buffered content if any and closes the writer. After closed, the writer does not accept
|
||||
// further writes.
|
||||
//
|
||||
// It blocks when there is buffered data to write out and the underlying writer blocks.
|
||||
//
|
||||
// It does not close the underlying writer.
|
||||
func (w Writer) Close() error {
|
||||
if w.writer == nil {
|
||||
return nil
|
||||
|
||||
157
lib_test.go
157
lib_test.go
@ -84,15 +84,11 @@ func TestLib(t *testing.T) {
|
||||
|
||||
t.Run("read bytes", func(t *testing.T) {
|
||||
var r buffer.Reader
|
||||
b, ok, err := r.ReadBytes([]byte("123"), 512)
|
||||
b, err := r.ReadBytes([]byte("123"), 512)
|
||||
if !errors.Is(err, io.EOF) {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if ok {
|
||||
t.Fatal(ok)
|
||||
}
|
||||
|
||||
if len(b) != 0 {
|
||||
t.Fatal(len(b))
|
||||
}
|
||||
@ -154,7 +150,7 @@ func TestLib(t *testing.T) {
|
||||
t.Run("abort", func(t *testing.T) {
|
||||
t.Run("from blank state", func(t *testing.T) {
|
||||
p := &fakePool{allocSize: 1 << 6}
|
||||
r := buffer.BufferedReader(&gen{max: 1 << 12}, buffer.Options{Pool: p})
|
||||
r := buffer.BufferedReader(&gen{max: 1 << 12}, buffer.Options{BufferPool: p})
|
||||
r.Close()
|
||||
b := make([]byte, 1<<9)
|
||||
n, err := r.Read(b)
|
||||
@ -169,10 +165,10 @@ func TestLib(t *testing.T) {
|
||||
|
||||
t.Run("with multiple segments", func(t *testing.T) {
|
||||
p := &fakePool{allocSize: 1 << 6}
|
||||
r := buffer.BufferedReader(&gen{max: 1 << 12}, buffer.Options{Pool: p})
|
||||
b, ok, err := r.ReadBytes([]byte("123"), 1<<6+1<<5)
|
||||
if ok || err != nil || p.alloc != 2 {
|
||||
t.Fatal(len(b), ok, err, p.alloc)
|
||||
r := buffer.BufferedReader(&gen{max: 1 << 12}, buffer.Options{BufferPool: p})
|
||||
b, err := r.ReadBytes([]byte("123"), 1<<6+1<<5)
|
||||
if len(b) != 0 || err != nil || p.alloc != 2 {
|
||||
t.Fatal(len(b), err, p.alloc)
|
||||
}
|
||||
|
||||
r.Close()
|
||||
@ -194,7 +190,7 @@ func TestLib(t *testing.T) {
|
||||
errAfter: []int{1 << 6},
|
||||
}
|
||||
|
||||
r := buffer.BufferedReader(g, buffer.Options{Pool: p})
|
||||
r := buffer.BufferedReader(g, buffer.Options{BufferPool: p})
|
||||
b := make([]byte, 1<<9)
|
||||
n, err := r.Read(b)
|
||||
if n != 1<<6 || err != nil {
|
||||
@ -221,8 +217,8 @@ func TestLib(t *testing.T) {
|
||||
t.Run("with content", func(t *testing.T) {
|
||||
c := buffer.ContentFunc(func(w io.Writer) (int64, error) {
|
||||
var n int64
|
||||
for i := 0; i < 3; i++ {
|
||||
ni, err := w.Write([]byte("123456789")[i*3 : i*3+3])
|
||||
for i := 0; i < 4; i++ {
|
||||
ni, err := w.Write([]byte("123456789012")[i*3 : i*3+3])
|
||||
n += int64(ni)
|
||||
if err != nil {
|
||||
return n, err
|
||||
@ -233,18 +229,21 @@ func TestLib(t *testing.T) {
|
||||
})
|
||||
|
||||
p := &fakePool{allocSize: 2}
|
||||
o := buffer.Options{Pool: p}
|
||||
o := buffer.Options{BufferPool: p}
|
||||
r := buffer.BufferedContent(c, o)
|
||||
b := make([]byte, 3)
|
||||
for i := 0; i < 2; i++ {
|
||||
exp := []byte("123456789012")
|
||||
for i := 0; i < 8; i++ {
|
||||
n, err := r.Read(b)
|
||||
if n != 3 || err != nil {
|
||||
if n != 2-i%2 || err != nil {
|
||||
t.Fatal(n, err)
|
||||
}
|
||||
|
||||
if string(b) != "123456789"[i*3:i*3+3] {
|
||||
t.Fatal(string(b))
|
||||
if string(b[:n]) != string(exp[:n]) {
|
||||
t.Fatal(string(b[:n]))
|
||||
}
|
||||
|
||||
exp = exp[n:]
|
||||
}
|
||||
|
||||
r.Close()
|
||||
@ -261,8 +260,8 @@ func TestLib(t *testing.T) {
|
||||
t.Run("with content error", func(t *testing.T) {
|
||||
c := buffer.ContentFunc(func(w io.Writer) (int64, error) {
|
||||
var n int64
|
||||
for i := 0; i < 3; i++ {
|
||||
ni, err := w.Write([]byte("123456789")[i*3 : i*3+3])
|
||||
for i := 0; i < 4; i++ {
|
||||
ni, err := w.Write([]byte("123456789012")[i*3 : i*3+3])
|
||||
n += int64(ni)
|
||||
if err != nil {
|
||||
return n, err
|
||||
@ -273,18 +272,21 @@ func TestLib(t *testing.T) {
|
||||
})
|
||||
|
||||
p := &fakePool{allocSize: 2}
|
||||
o := buffer.Options{Pool: p}
|
||||
o := buffer.Options{BufferPool: p}
|
||||
r := buffer.BufferedContent(c, o)
|
||||
b := make([]byte, 3)
|
||||
for i := 0; i < 3; i++ {
|
||||
exp := []byte("123456789012")
|
||||
for i := 0; i < 8; i++ {
|
||||
n, err := r.Read(b)
|
||||
if n != 3 || err != nil {
|
||||
if n != 2-i%2 || err != nil {
|
||||
t.Fatal(n, err)
|
||||
}
|
||||
|
||||
if string(b) != "123456789"[i*3:i*3+3] {
|
||||
if string(b[:n]) != string(exp[:n]) {
|
||||
t.Fatal(string(b))
|
||||
}
|
||||
|
||||
exp = exp[n:]
|
||||
}
|
||||
|
||||
n, err := r.Read(b)
|
||||
@ -364,7 +366,7 @@ func TestLib(t *testing.T) {
|
||||
t.Run("double closing reader", func(t *testing.T) {
|
||||
g := &gen{max: 1 << 12}
|
||||
p := &fakePool{allocSize: 1 << 9}
|
||||
r := buffer.BufferedReader(g, buffer.Options{Pool: p})
|
||||
r := buffer.BufferedReader(g, buffer.Options{BufferPool: p})
|
||||
b := bytes.NewBuffer(nil)
|
||||
if n, err := io.Copy(b, r); n != 1<<12 || err != nil {
|
||||
t.Fatal(n, err)
|
||||
@ -392,7 +394,7 @@ func TestLib(t *testing.T) {
|
||||
})
|
||||
|
||||
p := &fakePool{allocSize: 1 << 9}
|
||||
r := buffer.BufferedContent(c, buffer.Options{Pool: p})
|
||||
r := buffer.BufferedContent(c, buffer.Options{BufferPool: p})
|
||||
b := bytes.NewBuffer(nil)
|
||||
if n, err := io.Copy(b, r); n != 9 || err != nil {
|
||||
t.Fatal(n, err)
|
||||
@ -420,7 +422,7 @@ func TestLib(t *testing.T) {
|
||||
})
|
||||
|
||||
p := &fakePool{allocSize: 1 << 9}
|
||||
r := buffer.BufferedContent(c, buffer.Options{Pool: p})
|
||||
r := buffer.BufferedContent(c, buffer.Options{BufferPool: p})
|
||||
b := make([]byte, 3)
|
||||
if n, err := r.Read(b); n != 3 || err != nil || string(b) != "123" {
|
||||
t.Fatal(n, err, string(b))
|
||||
@ -437,7 +439,7 @@ func TestLib(t *testing.T) {
|
||||
w := &writer{}
|
||||
r := &gen{max: 1 << 12}
|
||||
p := &fakePool{allocSize: 1 << 9}
|
||||
o := buffer.Options{Pool: p}
|
||||
o := buffer.Options{BufferPool: p}
|
||||
b := buffer.BufferedWriter(w, o)
|
||||
n, err := b.ReadFrom(r)
|
||||
if n != 1<<12 || err != nil {
|
||||
@ -465,7 +467,7 @@ func TestLib(t *testing.T) {
|
||||
}
|
||||
|
||||
p := &fakePool{allocSize: 1 << 9}
|
||||
o := buffer.Options{Pool: p}
|
||||
o := buffer.Options{BufferPool: p}
|
||||
b := buffer.BufferedWriter(w, o)
|
||||
n, err := b.ReadFrom(r)
|
||||
if n != 1<<11 || !errors.Is(err, errTest) {
|
||||
@ -485,6 +487,61 @@ func TestLib(t *testing.T) {
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
t.Run("initial segment", func(t *testing.T) {
|
||||
t.Run("reader", func(t *testing.T) {
|
||||
g := &gen{max: 1 << 12}
|
||||
p := &fakePool{allocSize: 1 << 9}
|
||||
o := buffer.Options{
|
||||
InitialSegment: make([]byte, 1<<9),
|
||||
BufferPool: p,
|
||||
}
|
||||
|
||||
b := buffer.BufferedReader(g, o)
|
||||
|
||||
var n int
|
||||
pp := make([]byte, 1<<12)
|
||||
for {
|
||||
ni, err := b.Read(pp)
|
||||
n += ni
|
||||
if errors.Is(err, io.EOF) {
|
||||
break
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
if n != 1<<12 {
|
||||
t.Fatal(n)
|
||||
}
|
||||
|
||||
if p.alloc != 0 || p.free != 0 {
|
||||
t.Fatal(p.alloc, p.free)
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("writer", func(t *testing.T) {
|
||||
w := &writer{}
|
||||
p := &fakePool{allocSize: 1 << 9}
|
||||
o := buffer.Options{
|
||||
InitialSegment: make([]byte, 1<<9),
|
||||
BufferPool: p,
|
||||
}
|
||||
|
||||
b := buffer.BufferedWriter(w, o)
|
||||
pp := generate(1 << 12)
|
||||
n, err := b.Write(pp)
|
||||
if n != 1<<12 || err != nil {
|
||||
t.Fatal(n, err)
|
||||
}
|
||||
|
||||
if p.alloc != 0 || p.free != 0 {
|
||||
t.Fatal(p.alloc, p.free)
|
||||
}
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
// -- bench
|
||||
@ -509,7 +566,7 @@ func TestBenchmarkThroughput(t *testing.T) {
|
||||
p := buffer.NoPool(0)
|
||||
wo := writerOnly{io.Discard}
|
||||
src := &gen{max: 1 << 18}
|
||||
r := buffer.BufferedReader(src, buffer.Options{Pool: p})
|
||||
r := buffer.BufferedReader(src, buffer.Options{BufferPool: p})
|
||||
ro := readerOnly{r}
|
||||
n, err := io.Copy(wo, ro)
|
||||
if n != 1<<18 || err != nil {
|
||||
@ -533,7 +590,7 @@ func BenchmarkThroughput(b *testing.B) {
|
||||
wo := writerOnly{io.Discard}
|
||||
for i := 0; i < b.N; i++ {
|
||||
src := &gen{max: 1 << 18}
|
||||
r := buffer.BufferedReader(src, buffer.Options{Pool: p})
|
||||
r := buffer.BufferedReader(src, buffer.Options{BufferPool: p})
|
||||
ro := readerOnly{r}
|
||||
io.Copy(wo, ro)
|
||||
}
|
||||
@ -553,7 +610,7 @@ func TestBenchmarkThroughputPooled(t *testing.T) {
|
||||
p := &foreverPool{allocSize: 1 << 12}
|
||||
wo := writerOnly{io.Discard}
|
||||
src := &gen{max: 1 << 18}
|
||||
r := buffer.BufferedReader(src, buffer.Options{Pool: p})
|
||||
r := buffer.BufferedReader(src, buffer.Options{BufferPool: p})
|
||||
ro := readerOnly{r}
|
||||
n, err := io.Copy(wo, ro)
|
||||
if n != 1<<18 || err != nil {
|
||||
@ -578,7 +635,7 @@ func BenchmarkThroughputPooled(b *testing.B) {
|
||||
wo := writerOnly{io.Discard}
|
||||
for i := 0; i < b.N; i++ {
|
||||
src := &gen{max: 1 << 18}
|
||||
r := buffer.BufferedReader(src, buffer.Options{Pool: p})
|
||||
r := buffer.BufferedReader(src, buffer.Options{BufferPool: p})
|
||||
ro := readerOnly{r}
|
||||
io.Copy(wo, ro)
|
||||
}
|
||||
@ -602,7 +659,7 @@ func TestBenchmarkThroughputPooledParallel(t *testing.T) {
|
||||
|
||||
wo := writerOnly{io.Discard}
|
||||
src := &gen{max: 1 << 18}
|
||||
r := buffer.BufferedReader(src, buffer.Options{Pool: p})
|
||||
r := buffer.BufferedReader(src, buffer.Options{BufferPool: p})
|
||||
ro := readerOnly{r}
|
||||
n, err := io.Copy(wo, ro)
|
||||
if n != 1<<18 || err != nil {
|
||||
@ -640,7 +697,7 @@ func BenchmarkThroughputPooledParallel(b *testing.B) {
|
||||
b.RunParallel(func(pb *testing.PB) {
|
||||
for pb.Next() {
|
||||
src := &gen{max: 1 << 18}
|
||||
r := buffer.BufferedReader(src, buffer.Options{Pool: p})
|
||||
r := buffer.BufferedReader(src, buffer.Options{BufferPool: p})
|
||||
ro := readerOnly{r}
|
||||
wo := writerOnly{io.Discard}
|
||||
io.Copy(wo, ro)
|
||||
@ -676,16 +733,12 @@ func TestBenchmarkScan(t *testing.T) {
|
||||
customContent: map[int][]byte{delimiterPosition: []byte("123")},
|
||||
}
|
||||
|
||||
r := buffer.BufferedReader(src, buffer.Options{Pool: p})
|
||||
b, ok, err := r.ReadBytes([]byte{'1'}, 1<<18)
|
||||
r := buffer.BufferedReader(src, buffer.Options{BufferPool: p})
|
||||
b, err := r.ReadBytes([]byte{'1'}, 1<<18)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if !ok {
|
||||
t.Fatal("delimiter")
|
||||
}
|
||||
|
||||
if !bytes.Equal(b, append(generate(delimiterPosition), '1')) {
|
||||
t.Fatal("content")
|
||||
}
|
||||
@ -720,7 +773,7 @@ func BenchmarkScan(b *testing.B) {
|
||||
customContent: map[int][]byte{delimiterPosition: []byte("123")},
|
||||
}
|
||||
|
||||
r := buffer.BufferedReader(src, buffer.Options{Pool: p})
|
||||
r := buffer.BufferedReader(src, buffer.Options{BufferPool: p})
|
||||
r.ReadBytes([]byte{'1'}, 1<<18)
|
||||
}
|
||||
}
|
||||
@ -748,16 +801,12 @@ func TestBenchmarkScanPooled(t *testing.T) {
|
||||
customContent: map[int][]byte{delimiterPosition: []byte("123")},
|
||||
}
|
||||
|
||||
r := buffer.BufferedReader(src, buffer.Options{Pool: p})
|
||||
b, ok, err := r.ReadBytes([]byte{'1'}, 1<<18)
|
||||
r := buffer.BufferedReader(src, buffer.Options{BufferPool: p})
|
||||
b, err := r.ReadBytes([]byte{'1'}, 1<<18)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if !ok {
|
||||
t.Fatal("delimiter")
|
||||
}
|
||||
|
||||
if !bytes.Equal(b, append(generate(delimiterPosition), '1')) {
|
||||
t.Fatal("content")
|
||||
}
|
||||
@ -793,7 +842,7 @@ func BenchmarkScanPooled(b *testing.B) {
|
||||
customContent: map[int][]byte{delimiterPosition: []byte("123")},
|
||||
}
|
||||
|
||||
r := buffer.BufferedReader(src, buffer.Options{Pool: p})
|
||||
r := buffer.BufferedReader(src, buffer.Options{BufferPool: p})
|
||||
r.ReadBytes([]byte{'1'}, 1<<18)
|
||||
}
|
||||
}
|
||||
@ -825,16 +874,12 @@ func TestBenchmarkScanPooledParallel(t *testing.T) {
|
||||
customContent: map[int][]byte{delimiterPosition: []byte("123")},
|
||||
}
|
||||
|
||||
r := buffer.BufferedReader(src, buffer.Options{Pool: p})
|
||||
b, ok, err := r.ReadBytes([]byte{'1'}, 1<<18)
|
||||
r := buffer.BufferedReader(src, buffer.Options{BufferPool: p})
|
||||
b, err := r.ReadBytes([]byte{'1'}, 1<<18)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if !ok {
|
||||
t.Fatal("delimiter")
|
||||
}
|
||||
|
||||
if !bytes.Equal(b, append(generate(delimiterPosition), '1')) {
|
||||
t.Fatal("content")
|
||||
}
|
||||
@ -884,7 +929,7 @@ func BenchmarkScanPooledParallel(b *testing.B) {
|
||||
customContent: map[int][]byte{delimiterPosition: []byte("123")},
|
||||
}
|
||||
|
||||
r := buffer.BufferedReader(src, buffer.Options{Pool: p})
|
||||
r := buffer.BufferedReader(src, buffer.Options{BufferPool: p})
|
||||
r.ReadBytes([]byte{'1'}, 1<<18)
|
||||
}
|
||||
})
|
||||
|
||||
20
peek_test.go
20
peek_test.go
@ -13,7 +13,7 @@ func TestPeek(t *testing.T) {
|
||||
t.Run(title, func(t *testing.T) {
|
||||
t.Run("peek across segments", func(t *testing.T) {
|
||||
g := &gen{max: 1 << 15}
|
||||
o := buffer.Options{Pool: buffer.NoPool(128)}
|
||||
o := buffer.Options{BufferPool: buffer.NoPool(128)}
|
||||
r := cr(g, o)
|
||||
p, err := r.Peek(2*128 + 30)
|
||||
if err != nil {
|
||||
@ -31,7 +31,7 @@ func TestPeek(t *testing.T) {
|
||||
fastErr: true,
|
||||
}
|
||||
|
||||
o := buffer.Options{Pool: buffer.NoPool(1 << 12)}
|
||||
o := buffer.Options{BufferPool: buffer.NoPool(1 << 12)}
|
||||
r := cr(g, o)
|
||||
b, err := r.Peek(18)
|
||||
if err != nil {
|
||||
@ -72,7 +72,7 @@ func TestPeek(t *testing.T) {
|
||||
|
||||
t.Run("err immediately on first try to fill", func(t *testing.T) {
|
||||
g := &gen{}
|
||||
o := buffer.Options{Pool: buffer.NoPool(1 << 12)}
|
||||
o := buffer.Options{BufferPool: buffer.NoPool(1 << 12)}
|
||||
r := cr(g, o)
|
||||
b, err := r.Peek(18)
|
||||
if !errors.Is(err, io.EOF) {
|
||||
@ -86,7 +86,7 @@ func TestPeek(t *testing.T) {
|
||||
|
||||
t.Run("peek on empty", func(t *testing.T) {
|
||||
g := &gen{max: 1 << 15}
|
||||
o := buffer.Options{Pool: buffer.NoPool(1 << 12)}
|
||||
o := buffer.Options{BufferPool: buffer.NoPool(1 << 12)}
|
||||
r := cr(g, o)
|
||||
b, err := r.Peek(18)
|
||||
if err != nil {
|
||||
@ -100,7 +100,7 @@ func TestPeek(t *testing.T) {
|
||||
|
||||
t.Run("peek multiple segments", func(t *testing.T) {
|
||||
g := &gen{max: 1 << 15}
|
||||
o := buffer.Options{Pool: buffer.NoPool(64)}
|
||||
o := buffer.Options{BufferPool: buffer.NoPool(64)}
|
||||
r := cr(g, o)
|
||||
b, err := r.Peek(160)
|
||||
if err != nil {
|
||||
@ -114,7 +114,7 @@ func TestPeek(t *testing.T) {
|
||||
|
||||
t.Run("peek on partially filled", func(t *testing.T) {
|
||||
g := &gen{max: 1 << 15}
|
||||
o := buffer.Options{Pool: buffer.NoPool(64)}
|
||||
o := buffer.Options{BufferPool: buffer.NoPool(64)}
|
||||
r := cr(g, o)
|
||||
b, err := r.Peek(16)
|
||||
if err != nil {
|
||||
@ -137,7 +137,7 @@ func TestPeek(t *testing.T) {
|
||||
|
||||
t.Run("peek on partially filled multiple segments", func(t *testing.T) {
|
||||
g := &gen{max: 1 << 15}
|
||||
o := buffer.Options{Pool: buffer.NoPool(64)}
|
||||
o := buffer.Options{BufferPool: buffer.NoPool(64)}
|
||||
r := cr(g, o)
|
||||
b, err := r.Peek(160)
|
||||
if err != nil {
|
||||
@ -164,7 +164,7 @@ func TestPeek(t *testing.T) {
|
||||
fastErr: true,
|
||||
}
|
||||
|
||||
o := buffer.Options{Pool: buffer.NoPool(1 << 12)}
|
||||
o := buffer.Options{BufferPool: buffer.NoPool(1 << 12)}
|
||||
r := cr(g, o)
|
||||
b, err := r.Peek(18)
|
||||
if err != nil {
|
||||
@ -182,7 +182,7 @@ func TestPeek(t *testing.T) {
|
||||
fastErr: true,
|
||||
}
|
||||
|
||||
o := buffer.Options{Pool: buffer.NoPool(64)}
|
||||
o := buffer.Options{BufferPool: buffer.NoPool(64)}
|
||||
r := cr(g, o)
|
||||
b, err := r.Peek(214)
|
||||
if err != nil {
|
||||
@ -196,7 +196,7 @@ func TestPeek(t *testing.T) {
|
||||
|
||||
t.Run("peek zero", func(t *testing.T) {
|
||||
g := &gen{max: 1 << 15}
|
||||
o := buffer.Options{Pool: buffer.NoPool(1 << 12)}
|
||||
o := buffer.Options{BufferPool: buffer.NoPool(1 << 12)}
|
||||
r := cr(g, o)
|
||||
b, err := r.Peek(0)
|
||||
if err != nil {
|
||||
|
||||
176
pool_test.go
176
pool_test.go
@ -134,7 +134,7 @@ func TestPoolUsage(t *testing.T) {
|
||||
t.Run("read", func(t *testing.T) {
|
||||
g := &gen{max: 1 << 15}
|
||||
p := &fakePool{allocSize: 1 << 12}
|
||||
o := buffer.Options{Pool: p}
|
||||
o := buffer.Options{BufferPool: p}
|
||||
r := cr(g, o)
|
||||
b := make([]byte, 256)
|
||||
n, err := r.Read(b)
|
||||
@ -158,17 +158,13 @@ func TestPoolUsage(t *testing.T) {
|
||||
t.Run("read bytes", func(t *testing.T) {
|
||||
g := &gen{max: 1 << 15}
|
||||
p := &fakePool{allocSize: 1 << 9}
|
||||
o := buffer.Options{Pool: p}
|
||||
o := buffer.Options{BufferPool: p}
|
||||
r := cr(g, o)
|
||||
b, ok, err := r.ReadBytes([]byte("123"), 1<<12)
|
||||
b, err := r.ReadBytes([]byte("123"), 1<<12)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if ok {
|
||||
t.Fatal("unexpected delimiter")
|
||||
}
|
||||
|
||||
if len(b) != 0 {
|
||||
t.Fatal("invalid content")
|
||||
}
|
||||
@ -181,7 +177,7 @@ func TestPoolUsage(t *testing.T) {
|
||||
t.Run("read utf8", func(t *testing.T) {
|
||||
g := &gen{max: 1 << 15}
|
||||
p := &fakePool{allocSize: 1 << 12}
|
||||
o := buffer.Options{Pool: p}
|
||||
o := buffer.Options{BufferPool: p}
|
||||
r := cr(g, o)
|
||||
runes, n, err := r.ReadUTF8(1 << 12)
|
||||
if err != nil {
|
||||
@ -189,7 +185,7 @@ func TestPoolUsage(t *testing.T) {
|
||||
}
|
||||
|
||||
if n != 1<<12 {
|
||||
t.Fatal("unexpected delimiter")
|
||||
t.Fatal("unexpected read length")
|
||||
}
|
||||
|
||||
if len(runes) != 1<<12 {
|
||||
@ -201,10 +197,37 @@ func TestPoolUsage(t *testing.T) {
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("read utf8 off", func(t *testing.T) {
|
||||
g := &gen{
|
||||
max: 1 << 15,
|
||||
rng: utf8Range,
|
||||
}
|
||||
|
||||
p := &fakePool{allocSize: 1 << 12}
|
||||
o := buffer.Options{BufferPool: p}
|
||||
r := cr(g, o)
|
||||
runes, n, err := r.ReadUTF8(1 << 12)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if n < len(runes) {
|
||||
t.Fatal("unexpected read length", n)
|
||||
}
|
||||
|
||||
if len(runes) != 1<<12 {
|
||||
t.Fatal("invalid content")
|
||||
}
|
||||
|
||||
if p.alloc != 2 {
|
||||
t.Fatal("invalid allocation count", p.alloc)
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("peek", func(t *testing.T) {
|
||||
g := &gen{max: 1 << 15}
|
||||
p := &fakePool{allocSize: 1 << 12}
|
||||
o := buffer.Options{Pool: p}
|
||||
o := buffer.Options{BufferPool: p}
|
||||
r := cr(g, o)
|
||||
b, err := r.Peek(3 * 1 << 12)
|
||||
if err != nil {
|
||||
@ -223,7 +246,7 @@ func TestPoolUsage(t *testing.T) {
|
||||
t.Run("buffered", func(t *testing.T) {
|
||||
g := &gen{max: 1 << 15}
|
||||
p := &fakePool{allocSize: 1 << 12}
|
||||
o := buffer.Options{Pool: p}
|
||||
o := buffer.Options{BufferPool: p}
|
||||
r := cr(g, o)
|
||||
b := r.Buffered()
|
||||
if len(b) != 0 {
|
||||
@ -238,7 +261,7 @@ func TestPoolUsage(t *testing.T) {
|
||||
t.Run("write to", func(t *testing.T) {
|
||||
g := &gen{max: 1 << 15}
|
||||
p := &fakePool{allocSize: 1 << 12}
|
||||
o := buffer.Options{Pool: p}
|
||||
o := buffer.Options{BufferPool: p}
|
||||
r := cr(g, o)
|
||||
|
||||
var b bytes.Buffer
|
||||
@ -265,7 +288,7 @@ func TestPoolUsage(t *testing.T) {
|
||||
t.Run("read", func(t *testing.T) {
|
||||
g := &gen{max: 1 << 15}
|
||||
p := &fakePool{allocSize: 1 << 12}
|
||||
o := buffer.Options{Pool: p}
|
||||
o := buffer.Options{BufferPool: p}
|
||||
r := cr(g, o)
|
||||
b := make([]byte, 1<<9)
|
||||
for {
|
||||
@ -291,23 +314,18 @@ func TestPoolUsage(t *testing.T) {
|
||||
t.Run("read bytes", func(t *testing.T) {
|
||||
g := &gen{max: 1 << 15}
|
||||
p := &fakePool{allocSize: 1 << 12}
|
||||
o := buffer.Options{Pool: p}
|
||||
o := buffer.Options{BufferPool: p}
|
||||
r := cr(g, o)
|
||||
_, _, err := r.ReadBytes([]byte("123"), 1<<15+3)
|
||||
_, err := r.ReadBytes([]byte("123"), 1<<15+3)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
_, _, err = r.ReadBytes([]byte("123"), 1<<15+3)
|
||||
if !errors.Is(err, io.EOF) {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if p.alloc != 9 {
|
||||
t.Fatal("invalid allocation count", p.alloc)
|
||||
}
|
||||
|
||||
if p.free != 9 {
|
||||
if p.free != 0 {
|
||||
t.Fatal("invalid free count", p.free)
|
||||
}
|
||||
})
|
||||
@ -315,7 +333,7 @@ func TestPoolUsage(t *testing.T) {
|
||||
t.Run("read utf8", func(t *testing.T) {
|
||||
g := &gen{max: 1 << 15}
|
||||
p := &fakePool{allocSize: 1 << 12}
|
||||
o := buffer.Options{Pool: p}
|
||||
o := buffer.Options{BufferPool: p}
|
||||
r := cr(g, o)
|
||||
for {
|
||||
runes, n, err := r.ReadUTF8(1 << 12)
|
||||
@ -344,7 +362,7 @@ func TestPoolUsage(t *testing.T) {
|
||||
t.Run("peek", func(t *testing.T) {
|
||||
g := &gen{max: 1 << 15}
|
||||
p := &fakePool{allocSize: 1 << 12}
|
||||
o := buffer.Options{Pool: p}
|
||||
o := buffer.Options{BufferPool: p}
|
||||
r := cr(g, o)
|
||||
b, err := r.Peek(3 * 1 << 12)
|
||||
if err != nil {
|
||||
@ -387,7 +405,7 @@ func TestPoolUsage(t *testing.T) {
|
||||
t.Run("buffered", func(t *testing.T) {
|
||||
g := &gen{max: 1 << 15}
|
||||
p := &fakePool{allocSize: 1 << 12}
|
||||
o := buffer.Options{Pool: p}
|
||||
o := buffer.Options{BufferPool: p}
|
||||
r := cr(g, o)
|
||||
b := r.Buffered()
|
||||
if len(b) != 0 {
|
||||
@ -402,7 +420,7 @@ func TestPoolUsage(t *testing.T) {
|
||||
t.Run("write to", func(t *testing.T) {
|
||||
g := &gen{max: 1 << 15}
|
||||
p := &fakePool{allocSize: 1 << 12}
|
||||
o := buffer.Options{Pool: p}
|
||||
o := buffer.Options{BufferPool: p}
|
||||
r := cr(g, o)
|
||||
|
||||
var b bytes.Buffer
|
||||
@ -437,7 +455,7 @@ func TestPoolUsage(t *testing.T) {
|
||||
zeroAfter: []int{0},
|
||||
}
|
||||
|
||||
o := buffer.Options{Pool: p}
|
||||
o := buffer.Options{BufferPool: p}
|
||||
r := cr(g, o)
|
||||
b := make([]byte, 256)
|
||||
_, err := r.Read(b)
|
||||
@ -453,15 +471,15 @@ func TestPoolUsage(t *testing.T) {
|
||||
zeroAfter: []int{1},
|
||||
}
|
||||
|
||||
o := buffer.Options{Pool: p}
|
||||
o := buffer.Options{BufferPool: p}
|
||||
r := cr(g, o)
|
||||
_, _, err := r.ReadBytes([]byte("123"), 1<<12)
|
||||
_, err := r.ReadBytes([]byte("123"), 1<<12)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
_, _, err = r.ReadBytes([]byte("123"), 1<<12)
|
||||
if !errors.Is(err, buffer.ErrZeroAllocation) {
|
||||
_, err = r.ReadBytes([]byte("123"), 1<<12)
|
||||
if err != nil {
|
||||
t.Fatal("failed to fail", err)
|
||||
}
|
||||
})
|
||||
@ -473,7 +491,7 @@ func TestPoolUsage(t *testing.T) {
|
||||
zeroAfter: []int{0},
|
||||
}
|
||||
|
||||
o := buffer.Options{Pool: p}
|
||||
o := buffer.Options{BufferPool: p}
|
||||
r := cr(g, o)
|
||||
_, _, err := r.ReadUTF8(1 << 12)
|
||||
if !errors.Is(err, buffer.ErrZeroAllocation) {
|
||||
@ -488,7 +506,7 @@ func TestPoolUsage(t *testing.T) {
|
||||
zeroAfter: []int{0},
|
||||
}
|
||||
|
||||
o := buffer.Options{Pool: p}
|
||||
o := buffer.Options{BufferPool: p}
|
||||
r := cr(g, o)
|
||||
_, err := r.Peek(3 * 1 << 12)
|
||||
if !errors.Is(err, buffer.ErrZeroAllocation) {
|
||||
@ -503,7 +521,7 @@ func TestPoolUsage(t *testing.T) {
|
||||
zeroAfter: []int{0},
|
||||
}
|
||||
|
||||
o := buffer.Options{Pool: p}
|
||||
o := buffer.Options{BufferPool: p}
|
||||
r := cr(g, o)
|
||||
|
||||
var b bytes.Buffer
|
||||
@ -524,17 +542,13 @@ func TestPoolUsage(t *testing.T) {
|
||||
}
|
||||
|
||||
p := &fakePool{varyingSize: []int{8, 256}}
|
||||
o := buffer.Options{Pool: p}
|
||||
o := buffer.Options{BufferPool: p}
|
||||
r := cr(g, o)
|
||||
b, ok, err := r.ReadBytes([]byte("123"), 1<<15)
|
||||
b, err := r.ReadBytes([]byte("123"), 1<<15)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if !ok {
|
||||
t.Fatal("failed to find delimiter")
|
||||
}
|
||||
|
||||
if !bytes.Equal(b, append(generate(1<<11), []byte("123")...)) {
|
||||
t.Fatal("invalid content")
|
||||
}
|
||||
@ -543,15 +557,15 @@ func TestPoolUsage(t *testing.T) {
|
||||
t.Run("find not", func(t *testing.T) {
|
||||
g := &gen{max: 1 << 15}
|
||||
p := &fakePool{varyingSize: []int{8, 256}}
|
||||
o := buffer.Options{Pool: p}
|
||||
o := buffer.Options{BufferPool: p}
|
||||
r := cr(g, o)
|
||||
b, ok, err := r.ReadBytes([]byte("123"), 1<<15)
|
||||
b, err := r.ReadBytes([]byte("123"), 1<<15)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if ok {
|
||||
t.Fatal("invalid delimiter", len(b))
|
||||
if len(b) != 0 {
|
||||
t.Fatal("invalid read length", len(b))
|
||||
}
|
||||
})
|
||||
})
|
||||
@ -559,7 +573,7 @@ func TestPoolUsage(t *testing.T) {
|
||||
t.Run("peek", func(t *testing.T) {
|
||||
g := &gen{max: 1 << 15}
|
||||
p := &fakePool{varyingSize: []int{8, 256}}
|
||||
o := buffer.Options{Pool: p}
|
||||
o := buffer.Options{BufferPool: p}
|
||||
r := cr(g, o)
|
||||
b, err := r.Peek(1 << 11)
|
||||
if err != nil {
|
||||
@ -576,7 +590,7 @@ func TestPoolUsage(t *testing.T) {
|
||||
t.Run("read", func(t *testing.T) {
|
||||
g := &gen{max: 1 << 15}
|
||||
p := &fakePool{allocSize: 1}
|
||||
o := buffer.Options{Pool: p}
|
||||
o := buffer.Options{BufferPool: p}
|
||||
r := cr(g, o)
|
||||
b, err := io.ReadAll(r)
|
||||
if err != nil {
|
||||
@ -597,17 +611,13 @@ func TestPoolUsage(t *testing.T) {
|
||||
}
|
||||
|
||||
p := &fakePool{allocSize: 1}
|
||||
o := buffer.Options{Pool: p}
|
||||
o := buffer.Options{BufferPool: p}
|
||||
r := cr(g, o)
|
||||
b, ok, err := r.ReadBytes([]byte("123"), 1<<15)
|
||||
b, err := r.ReadBytes([]byte("123"), 1<<15)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if !ok {
|
||||
t.Fatal("failed to find delimiter")
|
||||
}
|
||||
|
||||
if !bytes.Equal(b, append(generate(1<<11), []byte("123")...)) {
|
||||
t.Fatal("invalid content")
|
||||
}
|
||||
@ -616,17 +626,13 @@ func TestPoolUsage(t *testing.T) {
|
||||
t.Run("find not", func(t *testing.T) {
|
||||
g := &gen{max: 1 << 15}
|
||||
p := &fakePool{allocSize: 1}
|
||||
o := buffer.Options{Pool: p}
|
||||
o := buffer.Options{BufferPool: p}
|
||||
r := cr(g, o)
|
||||
b, ok, err := r.ReadBytes([]byte("123"), 1<<15)
|
||||
b, err := r.ReadBytes([]byte("123"), 1<<15)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if ok {
|
||||
t.Fatal("invalid delimiter found")
|
||||
}
|
||||
|
||||
if len(b) != 0 {
|
||||
t.Fatal("invalid content", len(b))
|
||||
}
|
||||
@ -640,7 +646,7 @@ func TestPoolUsage(t *testing.T) {
|
||||
}
|
||||
|
||||
p := &fakePool{allocSize: 1}
|
||||
o := buffer.Options{Pool: p}
|
||||
o := buffer.Options{BufferPool: p}
|
||||
r := cr(g, o)
|
||||
runes, n, err := r.ReadUTF8(1 << 14)
|
||||
if err != nil {
|
||||
@ -659,7 +665,7 @@ func TestPoolUsage(t *testing.T) {
|
||||
t.Run("peek", func(t *testing.T) {
|
||||
g := &gen{max: 1 << 15}
|
||||
p := &fakePool{allocSize: 1}
|
||||
o := buffer.Options{Pool: p}
|
||||
o := buffer.Options{BufferPool: p}
|
||||
r := cr(g, o)
|
||||
b, err := r.Peek(1 << 14)
|
||||
if err != nil {
|
||||
@ -674,7 +680,7 @@ func TestPoolUsage(t *testing.T) {
|
||||
t.Run("write to", func(t *testing.T) {
|
||||
g := &gen{max: 1 << 15}
|
||||
p := &fakePool{allocSize: 1}
|
||||
o := buffer.Options{Pool: p}
|
||||
o := buffer.Options{BufferPool: p}
|
||||
r := cr(g, o)
|
||||
|
||||
var b bytes.Buffer
|
||||
@ -701,7 +707,7 @@ func TestPoolUsage(t *testing.T) {
|
||||
errAfter: []int{0},
|
||||
}
|
||||
|
||||
o := buffer.Options{Pool: p}
|
||||
o := buffer.Options{BufferPool: p}
|
||||
r := cr(g, o)
|
||||
b, err := io.ReadAll(r)
|
||||
if !errors.Is(err, errTest) {
|
||||
@ -721,17 +727,13 @@ func TestPoolUsage(t *testing.T) {
|
||||
errAfter: []int{0},
|
||||
}
|
||||
|
||||
o := buffer.Options{Pool: p}
|
||||
o := buffer.Options{BufferPool: p}
|
||||
r := cr(g, o)
|
||||
b, ok, err := r.ReadBytes([]byte("123"), 1<<12)
|
||||
b, err := r.ReadBytes([]byte("123"), 1<<12)
|
||||
if !errors.Is(err, errTest) {
|
||||
t.Fatal("failed to fail with the right error", err)
|
||||
}
|
||||
|
||||
if ok {
|
||||
t.Fatal("invalid delimiter found")
|
||||
}
|
||||
|
||||
if len(b) != 0 {
|
||||
t.Fatal("invalid content")
|
||||
}
|
||||
@ -744,30 +746,22 @@ func TestPoolUsage(t *testing.T) {
|
||||
errAfter: []int{1},
|
||||
}
|
||||
|
||||
o := buffer.Options{Pool: p}
|
||||
o := buffer.Options{BufferPool: p}
|
||||
r := cr(g, o)
|
||||
b, ok, err := r.ReadBytes([]byte("123"), 1<<15)
|
||||
b, err := r.ReadBytes([]byte("123"), 1<<15)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if ok {
|
||||
t.Fatal("invalid delimiter found")
|
||||
}
|
||||
|
||||
if !bytes.Equal(b, generate(1<<11)) {
|
||||
if len(b) != 0 {
|
||||
t.Fatal("invalid content")
|
||||
}
|
||||
|
||||
b, ok, err = r.ReadBytes([]byte("123"), 1<<15)
|
||||
if !errors.Is(err, errTest) {
|
||||
b, err = r.ReadBytes([]byte("123"), 1<<15)
|
||||
if err != nil {
|
||||
t.Fatal("failed to fail with the right error", err)
|
||||
}
|
||||
|
||||
if ok {
|
||||
t.Fatal("invalid delimiter found")
|
||||
}
|
||||
|
||||
if len(b) != 0 {
|
||||
t.Fatal("invalid content")
|
||||
}
|
||||
@ -785,7 +779,7 @@ func TestPoolUsage(t *testing.T) {
|
||||
errAfter: []int{0},
|
||||
}
|
||||
|
||||
o := buffer.Options{Pool: p}
|
||||
o := buffer.Options{BufferPool: p}
|
||||
r := cr(g, o)
|
||||
runes, n, err := r.ReadUTF8(1 << 14)
|
||||
if !errors.Is(err, errTest) {
|
||||
@ -809,7 +803,7 @@ func TestPoolUsage(t *testing.T) {
|
||||
errAfter: []int{0},
|
||||
}
|
||||
|
||||
o := buffer.Options{Pool: p}
|
||||
o := buffer.Options{BufferPool: p}
|
||||
r := cr(g, o)
|
||||
b, err := r.Peek(1 << 12)
|
||||
if !errors.Is(err, errTest) {
|
||||
@ -828,7 +822,7 @@ func TestPoolUsage(t *testing.T) {
|
||||
errAfter: []int{1},
|
||||
}
|
||||
|
||||
o := buffer.Options{Pool: p}
|
||||
o := buffer.Options{BufferPool: p}
|
||||
r := cr(g, o)
|
||||
b, err := r.Peek(1 << 15)
|
||||
if err != nil {
|
||||
@ -839,26 +833,22 @@ func TestPoolUsage(t *testing.T) {
|
||||
t.Fatal("invalid content")
|
||||
}
|
||||
|
||||
b, ok, err := r.ReadBytes([]byte("123"), 1<<11)
|
||||
b, err = r.ReadBytes([]byte("123"), 1<<11)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if ok {
|
||||
t.Fatal("invalid delimiter found")
|
||||
}
|
||||
|
||||
if !bytes.Equal(b, generate(1<<11)) {
|
||||
if len(b) != 0 {
|
||||
t.Fatal("invalid content")
|
||||
}
|
||||
|
||||
b, err = r.Peek(1 << 15)
|
||||
if !errors.Is(err, errTest) {
|
||||
if err != nil {
|
||||
t.Fatal("failed to fail with the right error")
|
||||
}
|
||||
|
||||
if len(b) != 0 {
|
||||
t.Fatal("invalid content")
|
||||
if !bytes.Equal(b, generate(1<<11)) {
|
||||
t.Fatal("invalid content", len(b))
|
||||
}
|
||||
})
|
||||
})
|
||||
@ -870,7 +860,7 @@ func TestPoolUsage(t *testing.T) {
|
||||
errAfter: []int{0},
|
||||
}
|
||||
|
||||
o := buffer.Options{Pool: p}
|
||||
o := buffer.Options{BufferPool: p}
|
||||
r := cr(g, o)
|
||||
|
||||
var b bytes.Buffer
|
||||
|
||||
30
read_test.go
30
read_test.go
@ -13,7 +13,7 @@ func TestRead(t *testing.T) {
|
||||
t.Run(title, func(t *testing.T) {
|
||||
t.Run("small", func(t *testing.T) {
|
||||
g := &gen{max: 3}
|
||||
r := cr(g, buffer.Options{Pool: buffer.NoPool(1 << 12)})
|
||||
r := cr(g, buffer.Options{BufferPool: buffer.NoPool(1 << 12)})
|
||||
b, err := io.ReadAll(r)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
@ -26,7 +26,7 @@ func TestRead(t *testing.T) {
|
||||
|
||||
t.Run("large", func(t *testing.T) {
|
||||
g := &gen{max: 1 << 18}
|
||||
r := cr(g, buffer.Options{Pool: buffer.NoPool(1 << 12)})
|
||||
r := cr(g, buffer.Options{BufferPool: buffer.NoPool(1 << 12)})
|
||||
b, err := io.ReadAll(r)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
@ -39,7 +39,7 @@ func TestRead(t *testing.T) {
|
||||
|
||||
t.Run("zero first", func(t *testing.T) {
|
||||
g := &gen{max: 1 << 15}
|
||||
o := buffer.Options{Pool: buffer.NoPool(1 << 12)}
|
||||
o := buffer.Options{BufferPool: buffer.NoPool(1 << 12)}
|
||||
r := cr(g, o)
|
||||
|
||||
var p []byte
|
||||
@ -69,7 +69,7 @@ func TestRead(t *testing.T) {
|
||||
|
||||
t.Run("large with non-divisible fragments", func(t *testing.T) {
|
||||
g := &gen{max: 1 << 15}
|
||||
o := buffer.Options{Pool: buffer.NoPool(1 << 12 / 2)}
|
||||
o := buffer.Options{BufferPool: buffer.NoPool(1 << 12 / 2)}
|
||||
r := cr(g, o)
|
||||
b, err := io.ReadAll(r)
|
||||
if err != nil {
|
||||
@ -83,7 +83,7 @@ func TestRead(t *testing.T) {
|
||||
|
||||
t.Run("partial segment", func(t *testing.T) {
|
||||
g := &gen{max: 1 << 15}
|
||||
o := buffer.Options{Pool: buffer.NoPool(128)}
|
||||
o := buffer.Options{BufferPool: buffer.NoPool(128)}
|
||||
r := cr(g, o)
|
||||
r.Peek(30)
|
||||
p := make([]byte, 60)
|
||||
@ -103,7 +103,7 @@ func TestRead(t *testing.T) {
|
||||
|
||||
t.Run("partial segment nth", func(t *testing.T) {
|
||||
g := &gen{max: 1 << 15}
|
||||
o := buffer.Options{Pool: buffer.NoPool(128)}
|
||||
o := buffer.Options{BufferPool: buffer.NoPool(128)}
|
||||
r := cr(g, o)
|
||||
r.Peek(2*128 + 30)
|
||||
p := make([]byte, 2*128+60)
|
||||
@ -123,7 +123,7 @@ func TestRead(t *testing.T) {
|
||||
|
||||
t.Run("read buffer larger than read size", func(t *testing.T) {
|
||||
g := &gen{max: 1 << 15}
|
||||
o := buffer.Options{Pool: buffer.NoPool(128)}
|
||||
o := buffer.Options{BufferPool: buffer.NoPool(128)}
|
||||
r := cr(g, o)
|
||||
p := make([]byte, 12)
|
||||
n, err := r.Read(p)
|
||||
@ -142,11 +142,11 @@ func TestRead(t *testing.T) {
|
||||
|
||||
t.Run("read buffer larger than segment", func(t *testing.T) {
|
||||
g := &gen{max: 1 << 15}
|
||||
o := buffer.Options{Pool: buffer.NoPool(128)}
|
||||
o := buffer.Options{BufferPool: buffer.NoPool(128)}
|
||||
r := cr(g, o)
|
||||
p := make([]byte, 192)
|
||||
n, err := r.Read(p)
|
||||
if n != 192 {
|
||||
if n != 128 {
|
||||
t.Fatal("invalid read size")
|
||||
}
|
||||
|
||||
@ -154,14 +154,14 @@ func TestRead(t *testing.T) {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if !bytes.Equal(p, generate(192)) {
|
||||
if !bytes.Equal(p[:128], generate(128)) {
|
||||
t.Fatal("invalid content")
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("read buffer larger than available data", func(t *testing.T) {
|
||||
g := &gen{max: 256}
|
||||
o := buffer.Options{Pool: buffer.NoPool(128)}
|
||||
o := buffer.Options{BufferPool: buffer.NoPool(512)}
|
||||
r := cr(g, o)
|
||||
p := make([]byte, 384)
|
||||
n, err := r.Read(p)
|
||||
@ -193,7 +193,7 @@ func TestRead(t *testing.T) {
|
||||
nullReadAfter: []int{0, 0},
|
||||
}
|
||||
|
||||
o := buffer.Options{Pool: buffer.NoPool(128)}
|
||||
o := buffer.Options{BufferPool: buffer.NoPool(128)}
|
||||
r := cr(g, o)
|
||||
p := make([]byte, 64)
|
||||
n, err := r.Read(p)
|
||||
@ -213,7 +213,7 @@ func TestRead(t *testing.T) {
|
||||
errAfter: []int{32},
|
||||
}
|
||||
|
||||
o := buffer.Options{Pool: buffer.NoPool(32)}
|
||||
o := buffer.Options{BufferPool: buffer.NoPool(32)}
|
||||
r := cr(g, o)
|
||||
p := make([]byte, 64)
|
||||
n, err := r.Read(p)
|
||||
@ -234,7 +234,7 @@ func TestRead(t *testing.T) {
|
||||
fastErr: true,
|
||||
}
|
||||
|
||||
o := buffer.Options{Pool: buffer.NoPool(32)}
|
||||
o := buffer.Options{BufferPool: buffer.NoPool(32)}
|
||||
r := cr(g, o)
|
||||
p := make([]byte, 64)
|
||||
n, err := r.Read(p)
|
||||
@ -255,7 +255,7 @@ func TestRead(t *testing.T) {
|
||||
fastErr: true,
|
||||
}
|
||||
|
||||
o := buffer.Options{Pool: buffer.NoPool(32)}
|
||||
o := buffer.Options{BufferPool: buffer.NoPool(32)}
|
||||
var result []byte
|
||||
r := cr(g, o)
|
||||
p := make([]byte, 9)
|
||||
|
||||
@ -18,17 +18,13 @@ func TestReadBytes(t *testing.T) {
|
||||
customContent: map[int][]byte{12: []byte("123")},
|
||||
}
|
||||
|
||||
o := buffer.Options{Pool: buffer.NoPool(1 << 12)}
|
||||
o := buffer.Options{BufferPool: buffer.NoPool(1 << 12)}
|
||||
r := cr(g, o)
|
||||
b, ok, err := r.ReadBytes([]byte("123"), 64)
|
||||
b, err := r.ReadBytes([]byte("123"), 64)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if !ok {
|
||||
t.Fatal("delimiter")
|
||||
}
|
||||
|
||||
if !bytes.Equal(b, append(generate(12), []byte("123")...)) {
|
||||
t.Fatal("failed to generate right content")
|
||||
}
|
||||
@ -36,14 +32,14 @@ func TestReadBytes(t *testing.T) {
|
||||
|
||||
t.Run("find not", func(t *testing.T) {
|
||||
g := &gen{max: 1 << 15}
|
||||
o := buffer.Options{Pool: buffer.NoPool(1 << 12)}
|
||||
o := buffer.Options{BufferPool: buffer.NoPool(1 << 12)}
|
||||
r := cr(g, o)
|
||||
b, ok, err := r.ReadBytes([]byte("123"), 64)
|
||||
b, err := r.ReadBytes([]byte("123"), 64)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if ok || len(b) != 0 {
|
||||
if len(b) != 0 {
|
||||
t.Fatal("failed to not find delimiter")
|
||||
}
|
||||
})
|
||||
@ -55,17 +51,13 @@ func TestReadBytes(t *testing.T) {
|
||||
customContent: map[int][]byte{12: []byte("123")},
|
||||
}
|
||||
|
||||
o := buffer.Options{Pool: buffer.NoPool(14)}
|
||||
o := buffer.Options{BufferPool: buffer.NoPool(14)}
|
||||
r := cr(g, o)
|
||||
b, ok, err := r.ReadBytes([]byte("123"), 64)
|
||||
b, err := r.ReadBytes([]byte("123"), 64)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if !ok {
|
||||
t.Fatal("failed to find delimiter")
|
||||
}
|
||||
|
||||
if !bytes.Equal(b, append(generate(12), []byte("123")...)) {
|
||||
t.Fatal("invalid content")
|
||||
}
|
||||
@ -79,17 +71,13 @@ func TestReadBytes(t *testing.T) {
|
||||
customContent: map[int][]byte{6: d},
|
||||
}
|
||||
|
||||
o := buffer.Options{Pool: buffer.NoPool(8)}
|
||||
o := buffer.Options{BufferPool: buffer.NoPool(8)}
|
||||
r := cr(g, o)
|
||||
b, ok, err := r.ReadBytes(d, 64)
|
||||
b, err := r.ReadBytes(d, 64)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if !ok {
|
||||
t.Fatal("failed to find delimiter")
|
||||
}
|
||||
|
||||
if !bytes.Equal(b, append(generate(6), d...)) {
|
||||
t.Fatal("invalid content")
|
||||
}
|
||||
@ -97,17 +85,13 @@ func TestReadBytes(t *testing.T) {
|
||||
|
||||
t.Run("find not across segments", func(t *testing.T) {
|
||||
g := &gen{max: 1 << 15}
|
||||
o := buffer.Options{Pool: buffer.NoPool(15)}
|
||||
o := buffer.Options{BufferPool: buffer.NoPool(15)}
|
||||
r := cr(g, o)
|
||||
b, ok, err := r.ReadBytes([]byte("123"), 24)
|
||||
b, err := r.ReadBytes([]byte("123"), 24)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if ok {
|
||||
t.Fatal("invalid delimiter found")
|
||||
}
|
||||
|
||||
if len(b) != 0 {
|
||||
t.Fatal("invalid content", len(b), string(b))
|
||||
}
|
||||
@ -115,17 +99,13 @@ func TestReadBytes(t *testing.T) {
|
||||
|
||||
t.Run("find not across multiple segments", func(t *testing.T) {
|
||||
g := &gen{max: 1 << 15}
|
||||
o := buffer.Options{Pool: buffer.NoPool(15)}
|
||||
o := buffer.Options{BufferPool: buffer.NoPool(15)}
|
||||
r := cr(g, o)
|
||||
b, ok, err := r.ReadBytes([]byte("123"), 64)
|
||||
b, err := r.ReadBytes([]byte("123"), 64)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if ok {
|
||||
t.Fatal("invalid delimiter found")
|
||||
}
|
||||
|
||||
if len(b) != 0 {
|
||||
t.Fatal("invalid content", len(b), string(b))
|
||||
}
|
||||
@ -138,17 +118,13 @@ func TestReadBytes(t *testing.T) {
|
||||
customContent: map[int][]byte{12: []byte("123")},
|
||||
}
|
||||
|
||||
o := buffer.Options{Pool: buffer.NoPool(1 << 12)}
|
||||
o := buffer.Options{BufferPool: buffer.NoPool(1 << 12)}
|
||||
r := cr(g, o)
|
||||
b, ok, err := r.ReadBytes([]byte("8"), 64)
|
||||
b, err := r.ReadBytes([]byte("8"), 64)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if ok {
|
||||
t.Fatal("invalid delimiter found")
|
||||
}
|
||||
|
||||
if len(b) != 0 {
|
||||
t.Fatal("invalid content")
|
||||
}
|
||||
@ -161,17 +137,13 @@ func TestReadBytes(t *testing.T) {
|
||||
customContent: map[int][]byte{12: []byte("12")},
|
||||
}
|
||||
|
||||
o := buffer.Options{Pool: buffer.NoPool(1 << 12)}
|
||||
o := buffer.Options{BufferPool: buffer.NoPool(1 << 12)}
|
||||
r := cr(g, o)
|
||||
b, ok, err := r.ReadBytes([]byte("123"), 64)
|
||||
b, err := r.ReadBytes([]byte("123"), 64)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if ok {
|
||||
t.Fatal("invalid delimiter found")
|
||||
}
|
||||
|
||||
if len(b) != 0 {
|
||||
t.Fatal("invalid content")
|
||||
}
|
||||
@ -187,30 +159,22 @@ func TestReadBytes(t *testing.T) {
|
||||
},
|
||||
}
|
||||
|
||||
o := buffer.Options{Pool: buffer.NoPool(1 << 12)}
|
||||
o := buffer.Options{BufferPool: buffer.NoPool(1 << 12)}
|
||||
r := cr(g, o)
|
||||
b, ok, err := r.ReadBytes([]byte("123"), 16)
|
||||
b, err := r.ReadBytes([]byte("123"), 16)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if ok {
|
||||
t.Fatal("invalid delimiter found")
|
||||
}
|
||||
|
||||
if len(b) != 0 {
|
||||
t.Fatal("invalid content")
|
||||
}
|
||||
|
||||
b, ok, err = r.ReadBytes([]byte("123"), 24)
|
||||
b, err = r.ReadBytes([]byte("123"), 24)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if !ok {
|
||||
t.Fatal("delimiter")
|
||||
}
|
||||
|
||||
check := append(
|
||||
append(generate(12), append([]byte("12"), generate(18)[14:]...)...),
|
||||
[]byte("123")...,
|
||||
@ -228,17 +192,13 @@ func TestReadBytes(t *testing.T) {
|
||||
customContent: map[int][]byte{7: []byte("12")},
|
||||
}
|
||||
|
||||
o := buffer.Options{Pool: buffer.NoPool(8)}
|
||||
o := buffer.Options{BufferPool: buffer.NoPool(8)}
|
||||
r := cr(g, o)
|
||||
b, ok, err := r.ReadBytes([]byte("123"), 64)
|
||||
b, err := r.ReadBytes([]byte("123"), 64)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if ok {
|
||||
t.Fatal("invalid delimiter found")
|
||||
}
|
||||
|
||||
if len(b) != 0 {
|
||||
t.Fatal("invalid content")
|
||||
}
|
||||
@ -251,17 +211,13 @@ func TestReadBytes(t *testing.T) {
|
||||
customContent: map[int][]byte{7: []byte("1234567890")},
|
||||
}
|
||||
|
||||
o := buffer.Options{Pool: buffer.NoPool(8)}
|
||||
o := buffer.Options{BufferPool: buffer.NoPool(8)}
|
||||
r := cr(g, o)
|
||||
b, ok, err := r.ReadBytes([]byte("1234567890123"), 64)
|
||||
b, err := r.ReadBytes([]byte("1234567890123"), 64)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if ok {
|
||||
t.Fatal("invalid delimiter found")
|
||||
}
|
||||
|
||||
if len(b) != 0 {
|
||||
t.Fatal("invalid content")
|
||||
}
|
||||
@ -277,30 +233,22 @@ func TestReadBytes(t *testing.T) {
|
||||
},
|
||||
}
|
||||
|
||||
o := buffer.Options{Pool: buffer.NoPool(8)}
|
||||
o := buffer.Options{BufferPool: buffer.NoPool(8)}
|
||||
r := cr(g, o)
|
||||
b, ok, err := r.ReadBytes([]byte("123"), 10)
|
||||
b, err := r.ReadBytes([]byte("123"), 10)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if ok {
|
||||
t.Fatal("invalid delimiter found")
|
||||
}
|
||||
|
||||
if len(b) != 0 {
|
||||
t.Fatal("invalid content")
|
||||
}
|
||||
|
||||
b, ok, err = r.ReadBytes([]byte("123"), 64)
|
||||
b, err = r.ReadBytes([]byte("123"), 64)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if !ok {
|
||||
t.Fatal("delimiter")
|
||||
}
|
||||
|
||||
check := append(
|
||||
append(generate(7), append([]byte("12"), generate(15)[9:]...)...),
|
||||
[]byte("123")...,
|
||||
@ -321,30 +269,22 @@ func TestReadBytes(t *testing.T) {
|
||||
},
|
||||
}
|
||||
|
||||
o := buffer.Options{Pool: buffer.NoPool(8)}
|
||||
o := buffer.Options{BufferPool: buffer.NoPool(8)}
|
||||
r := cr(g, o)
|
||||
b, ok, err := r.ReadBytes([]byte("1234567890123"), 20)
|
||||
b, err := r.ReadBytes([]byte("1234567890123"), 20)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if ok {
|
||||
t.Fatal("invalid delimiter found")
|
||||
}
|
||||
|
||||
if len(b) != 0 {
|
||||
t.Fatal("invalid content")
|
||||
}
|
||||
|
||||
b, ok, err = r.ReadBytes([]byte("1234567890123"), 64)
|
||||
b, err = r.ReadBytes([]byte("1234567890123"), 64)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if !ok {
|
||||
t.Fatal("delimiter")
|
||||
}
|
||||
|
||||
check := append(
|
||||
append(append(generate(7), []byte("1234567890")...), generate(22)[17:]...),
|
||||
[]byte("1234567890123")...,
|
||||
@ -362,17 +302,13 @@ func TestReadBytes(t *testing.T) {
|
||||
customContent: map[int][]byte{12: []byte("123")},
|
||||
}
|
||||
|
||||
o := buffer.Options{Pool: buffer.NoPool(1 << 12)}
|
||||
o := buffer.Options{BufferPool: buffer.NoPool(1 << 12)}
|
||||
r := cr(g, o)
|
||||
b, ok, err := r.ReadBytes([]byte("123"), 14)
|
||||
b, err := r.ReadBytes([]byte("123"), 14)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if ok {
|
||||
t.Fatal("delimiter")
|
||||
}
|
||||
|
||||
if len(b) != 0 {
|
||||
t.Fatal("invalid content")
|
||||
}
|
||||
@ -385,30 +321,22 @@ func TestReadBytes(t *testing.T) {
|
||||
customContent: map[int][]byte{12: []byte("123")},
|
||||
}
|
||||
|
||||
o := buffer.Options{Pool: buffer.NoPool(1 << 12)}
|
||||
o := buffer.Options{BufferPool: buffer.NoPool(1 << 12)}
|
||||
r := cr(g, o)
|
||||
b, ok, err := r.ReadBytes([]byte("123"), 14)
|
||||
b, err := r.ReadBytes([]byte("123"), 14)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if ok {
|
||||
t.Fatal("delimiter")
|
||||
}
|
||||
|
||||
if len(b) != 0 {
|
||||
t.Fatal("invalid content")
|
||||
}
|
||||
|
||||
b, ok, err = r.ReadBytes([]byte("123"), 64)
|
||||
b, err = r.ReadBytes([]byte("123"), 64)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if !ok {
|
||||
t.Fatal("delimiter")
|
||||
}
|
||||
|
||||
if !bytes.Equal(b, append(generate(12), []byte("123")...)) {
|
||||
t.Fatal("invalid content")
|
||||
}
|
||||
@ -421,17 +349,13 @@ func TestReadBytes(t *testing.T) {
|
||||
customContent: map[int][]byte{12: []byte("123")},
|
||||
}
|
||||
|
||||
o := buffer.Options{Pool: buffer.NoPool(1 << 12)}
|
||||
o := buffer.Options{BufferPool: buffer.NoPool(1 << 12)}
|
||||
r := cr(g, o)
|
||||
b, ok, err := r.ReadBytes(nil, 64)
|
||||
b, err := r.ReadBytes(nil, 64)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if !ok {
|
||||
t.Fatal("failed to find delimiter")
|
||||
}
|
||||
|
||||
if len(b) != 0 {
|
||||
t.Fatal("failed to generate right content")
|
||||
}
|
||||
@ -444,17 +368,13 @@ func TestReadBytes(t *testing.T) {
|
||||
customContent: map[int][]byte{12: []byte("1")},
|
||||
}
|
||||
|
||||
o := buffer.Options{Pool: buffer.NoPool(1 << 12)}
|
||||
o := buffer.Options{BufferPool: buffer.NoPool(1 << 12)}
|
||||
r := cr(g, o)
|
||||
b, ok, err := r.ReadBytes([]byte{'1'}, 64)
|
||||
b, err := r.ReadBytes([]byte{'1'}, 64)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if !ok {
|
||||
t.Fatal("delimiter")
|
||||
}
|
||||
|
||||
if !bytes.Equal(b, append(generate(12), '1')) {
|
||||
t.Fatal("failed to generate right content")
|
||||
}
|
||||
@ -467,41 +387,33 @@ func TestReadBytes(t *testing.T) {
|
||||
customContent: map[int][]byte{1<<17 - 3: []byte("123")},
|
||||
}
|
||||
|
||||
r := buffer.BufferedReader(src, buffer.Options{Pool: buffer.NoPool(1 << 12)})
|
||||
r := buffer.BufferedReader(src, buffer.Options{BufferPool: buffer.NoPool(1 << 12)})
|
||||
r.ReadBytes([]byte{'1'}, 1<<17+1<<16)
|
||||
})
|
||||
|
||||
t.Run("delimiter longer than content", func(t *testing.T) {
|
||||
g := &gen{max: 1 << 9}
|
||||
o := buffer.Options{Pool: buffer.NoPool(16)}
|
||||
o := buffer.Options{BufferPool: buffer.NoPool(16)}
|
||||
r := cr(g, o)
|
||||
b, ok, err := r.ReadBytes(generate(1<<10), 1<<11)
|
||||
b, err := r.ReadBytes(generate(1<<10), 1<<11)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if ok {
|
||||
t.Fatal("delimiter")
|
||||
}
|
||||
|
||||
if !bytes.Equal(b, generate(1<<9)) {
|
||||
if len(b) != 0 {
|
||||
t.Fatal("content")
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("find not none consumed", func(t *testing.T) {
|
||||
g := &gen{}
|
||||
o := buffer.Options{Pool: buffer.NoPool(1 << 12)}
|
||||
o := buffer.Options{BufferPool: buffer.NoPool(1 << 12)}
|
||||
r := cr(g, o)
|
||||
b, ok, err := r.ReadBytes([]byte("123"), 64)
|
||||
b, err := r.ReadBytes([]byte("123"), 64)
|
||||
if !errors.Is(err, io.EOF) {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if ok {
|
||||
t.Fatal("failed to find delimiter")
|
||||
}
|
||||
|
||||
if len(b) != 0 {
|
||||
t.Fatal("invalid content")
|
||||
}
|
||||
@ -519,30 +431,22 @@ func TestReadBytes(t *testing.T) {
|
||||
customContent: map[int][]byte{12: []byte("123")},
|
||||
}
|
||||
|
||||
o := buffer.Options{Pool: buffer.NoPool(8)}
|
||||
o := buffer.Options{BufferPool: buffer.NoPool(8)}
|
||||
r := cr(g, o)
|
||||
b, ok, err := r.ReadBytes([]byte("123"), 64)
|
||||
b, err := r.ReadBytes([]byte("123"), 64)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if ok {
|
||||
t.Fatal("delimiter")
|
||||
}
|
||||
|
||||
if !bytes.Equal(b, generate(8)) {
|
||||
if len(b) != 0 {
|
||||
t.Fatal("invalid content")
|
||||
}
|
||||
|
||||
b, ok, err = r.ReadBytes([]byte("123"), 64)
|
||||
if !errors.Is(err, errTest) {
|
||||
b, err = r.ReadBytes([]byte("123"), 64)
|
||||
if err != nil {
|
||||
t.Fatal("failed to fail", err)
|
||||
}
|
||||
|
||||
if ok {
|
||||
t.Fatal("delimiter")
|
||||
}
|
||||
|
||||
if len(b) != 0 {
|
||||
t.Fatal("invalid content")
|
||||
}
|
||||
@ -557,43 +461,22 @@ func TestReadBytes(t *testing.T) {
|
||||
customContent: map[int][]byte{12: []byte("123")},
|
||||
}
|
||||
|
||||
o := buffer.Options{Pool: buffer.NoPool(8)}
|
||||
o := buffer.Options{BufferPool: buffer.NoPool(8)}
|
||||
r := cr(g, o)
|
||||
b, ok, err := r.ReadBytes([]byte("123"), 64)
|
||||
b, err := r.ReadBytes([]byte("123"), 64)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if !ok {
|
||||
t.Fatal("delimiter", len(b), string(b))
|
||||
}
|
||||
|
||||
if !bytes.Equal(b, append(generate(12), []byte("123")...)) {
|
||||
t.Fatal("invalid content")
|
||||
}
|
||||
|
||||
b, ok, err = r.ReadBytes([]byte("123"), 64)
|
||||
b, err = r.ReadBytes([]byte("123"), 64)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if ok {
|
||||
t.Fatal("unexpected delimiter")
|
||||
}
|
||||
|
||||
if !bytes.Equal(b, generate(16)[15:]) {
|
||||
t.Fatal("invalid content", len(b), string(b))
|
||||
}
|
||||
|
||||
b, ok, err = r.ReadBytes([]byte("123"), 64)
|
||||
if !errors.Is(err, errTest) {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if ok {
|
||||
t.Fatal("unexpected delimiter")
|
||||
}
|
||||
|
||||
if len(b) != 0 {
|
||||
t.Fatal("invalid content", len(b), string(b))
|
||||
}
|
||||
@ -608,43 +491,31 @@ func TestReadBytes(t *testing.T) {
|
||||
customContent: map[int][]byte{12: []byte("123")},
|
||||
}
|
||||
|
||||
o := buffer.Options{Pool: buffer.NoPool(8)}
|
||||
o := buffer.Options{BufferPool: buffer.NoPool(8)}
|
||||
r := cr(g, o)
|
||||
b, ok, err := r.ReadBytes([]byte("123"), 64)
|
||||
b, err := r.ReadBytes([]byte("123"), 64)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if !ok {
|
||||
t.Fatal("delimiter", len(b), string(b))
|
||||
}
|
||||
|
||||
if !bytes.Equal(b, append(generate(12), []byte("123")...)) {
|
||||
t.Fatal("invalid content")
|
||||
}
|
||||
|
||||
b, ok, err = r.ReadBytes([]byte("123"), 64)
|
||||
b, err = r.ReadBytes([]byte("123"), 64)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if ok {
|
||||
t.Fatal("unexpected delimiter")
|
||||
}
|
||||
|
||||
if !bytes.Equal(b, generate(24)[15:]) {
|
||||
if len(b) != 0 {
|
||||
t.Fatal("invalid content", len(b), string(b))
|
||||
}
|
||||
|
||||
b, ok, err = r.ReadBytes([]byte("123"), 64)
|
||||
if !errors.Is(err, errTest) {
|
||||
b, err = r.ReadBytes([]byte("123"), 64)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if ok {
|
||||
t.Fatal("unexpected delimiter")
|
||||
}
|
||||
|
||||
if len(b) != 0 {
|
||||
t.Fatal("invalid content", len(b), string(b))
|
||||
}
|
||||
@ -658,30 +529,22 @@ func TestReadBytes(t *testing.T) {
|
||||
customContent: map[int][]byte{12: []byte("123")},
|
||||
}
|
||||
|
||||
o := buffer.Options{Pool: buffer.NoPool(8)}
|
||||
o := buffer.Options{BufferPool: buffer.NoPool(8)}
|
||||
r := cr(g, o)
|
||||
b, ok, err := r.ReadBytes([]byte("123"), 64)
|
||||
b, err := r.ReadBytes([]byte("123"), 64)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if ok {
|
||||
t.Fatal("delimiter")
|
||||
}
|
||||
|
||||
if len(b) != 0 {
|
||||
t.Fatal("invalid content")
|
||||
}
|
||||
|
||||
b, ok, err = r.ReadBytes([]byte("123"), 64)
|
||||
b, err = r.ReadBytes([]byte("123"), 64)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if !ok {
|
||||
t.Fatal("delimiter")
|
||||
}
|
||||
|
||||
if !bytes.Equal(b, append(generate(12), []byte("123")...)) {
|
||||
t.Fatal("failed to generate right content")
|
||||
}
|
||||
@ -693,18 +556,14 @@ func TestReadBytes(t *testing.T) {
|
||||
fastErr: true,
|
||||
}
|
||||
|
||||
o := buffer.Options{Pool: buffer.NoPool(256)}
|
||||
o := buffer.Options{BufferPool: buffer.NoPool(256)}
|
||||
r := cr(g, o)
|
||||
b, ok, err := r.ReadBytes([]byte("123"), 64)
|
||||
b, err := r.ReadBytes([]byte("123"), 64)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if ok {
|
||||
t.Fatal("delimiter")
|
||||
}
|
||||
|
||||
if !bytes.Equal(b, generate(64)) {
|
||||
if len(b) != 0 {
|
||||
t.Fatal("failed to generate right content")
|
||||
}
|
||||
})
|
||||
|
||||
181
reader.go
181
reader.go
@ -16,30 +16,31 @@ type reader struct {
|
||||
err error
|
||||
}
|
||||
|
||||
func (r *reader) fillSegment() (fn int, full bool) {
|
||||
if r.err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
func (r *reader) fillSegment() int {
|
||||
var n int
|
||||
seg := r.segments[len(r.segments)-1]
|
||||
start := r.offset + r.len - r.lastSegStart
|
||||
if start == len(seg) {
|
||||
full = true
|
||||
return
|
||||
n, r.err = r.in.Read(seg[start:len(seg)])
|
||||
if n == 0 && r.err == nil {
|
||||
n, r.err = r.in.Read(seg[start:len(seg)])
|
||||
}
|
||||
|
||||
fn, r.err = r.in.Read(seg[start:len(seg)])
|
||||
if fn == 0 && r.err == nil {
|
||||
fn, r.err = r.in.Read(seg[start:len(seg)])
|
||||
r.len += n
|
||||
return n
|
||||
}
|
||||
|
||||
r.len += fn
|
||||
full = fn == len(seg)-start
|
||||
return
|
||||
func (r reader) segmentFull() bool {
|
||||
if len(r.segments) == 0 {
|
||||
return true
|
||||
}
|
||||
|
||||
segmentPosition := r.offset + r.len - r.lastSegStart
|
||||
lastSeg := r.segments[len(r.segments)-1]
|
||||
return segmentPosition == len(lastSeg)
|
||||
}
|
||||
|
||||
func (r *reader) allocate() {
|
||||
segment, err := r.options.Pool.Get()
|
||||
segment, err := r.options.BufferPool.Get()
|
||||
if err != nil {
|
||||
r.err = err
|
||||
return
|
||||
@ -51,7 +52,8 @@ func (r *reader) allocate() {
|
||||
}
|
||||
|
||||
if len(r.segments) > 0 {
|
||||
r.lastSegStart += len(r.segments[len(r.segments)-1])
|
||||
lastSeg := r.segments[len(r.segments)-1]
|
||||
r.lastSegStart += len(lastSeg)
|
||||
}
|
||||
|
||||
r.segments = append(r.segments, segment)
|
||||
@ -68,16 +70,14 @@ func (r *reader) fill(to int) int {
|
||||
return n
|
||||
}
|
||||
|
||||
if len(r.segments) == 0 || r.offset+r.len == r.lastSegStart+len(r.segments[len(r.segments)-1]) {
|
||||
if r.segmentFull() {
|
||||
r.allocate()
|
||||
if r.err != nil {
|
||||
return n
|
||||
}
|
||||
continue
|
||||
}
|
||||
|
||||
fn, full := r.fillSegment()
|
||||
fn := r.fillSegment()
|
||||
n += fn
|
||||
if fn == 0 || !full {
|
||||
if fn == 0 || !r.segmentFull() {
|
||||
return n
|
||||
}
|
||||
}
|
||||
@ -112,41 +112,55 @@ func (r reader) copy(p []byte) (n int) {
|
||||
func (r *reader) consume(n int) {
|
||||
r.offset += n
|
||||
r.len -= n
|
||||
seg := 0
|
||||
if len(r.options.InitialSegment) > 0 {
|
||||
seg = 1
|
||||
}
|
||||
|
||||
for {
|
||||
if len(r.segments) <= 1 {
|
||||
if r.len == 0 {
|
||||
break
|
||||
}
|
||||
|
||||
segEnd := len(r.segments[seg])
|
||||
if seg == 1 {
|
||||
segEnd += len(r.segments[0])
|
||||
}
|
||||
|
||||
if r.offset < segEnd {
|
||||
break
|
||||
}
|
||||
|
||||
r.offset -= len(r.segments[seg])
|
||||
r.lastSegStart -= len(r.segments[seg])
|
||||
r.options.BufferPool.Put(r.segments[seg])
|
||||
r.segments = r.segments[seg+1:]
|
||||
}
|
||||
|
||||
if len(r.segments) == 1 {
|
||||
copy(r.segments[0], r.segments[0][r.offset:r.offset+r.len])
|
||||
r.offset = 0
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
if r.offset < len(r.segments[0]) {
|
||||
return
|
||||
}
|
||||
|
||||
r.offset -= len(r.segments[0])
|
||||
if len(r.segments) > 1 {
|
||||
r.lastSegStart -= len(r.segments[0])
|
||||
}
|
||||
|
||||
r.options.Pool.Put(r.segments[0])
|
||||
r.segments = r.segments[1:]
|
||||
}
|
||||
}
|
||||
|
||||
func (r *reader) free() {
|
||||
if len(r.segments) > 0 && len(r.options.InitialSegment) > 0 {
|
||||
r.segments = r.segments[1:]
|
||||
}
|
||||
|
||||
for {
|
||||
if len(r.segments) == 0 {
|
||||
break
|
||||
}
|
||||
|
||||
r.options.Pool.Put(r.segments[0])
|
||||
r.options.BufferPool.Put(r.segments[0])
|
||||
r.segments[0] = nil
|
||||
r.segments = r.segments[1:]
|
||||
}
|
||||
|
||||
r.segments = nil
|
||||
r.len = 0
|
||||
r.options.Pool = nil
|
||||
r.options.BufferPool = nil
|
||||
if c, ok := r.in.(interface{ close() error }); ok {
|
||||
if err := c.close(); err != nil {
|
||||
r.err = errors.Join(r.err, err)
|
||||
@ -208,9 +222,8 @@ func (r *reader) fillToDelimiter(delimiter []byte, max int) (int, bool) {
|
||||
}
|
||||
|
||||
if r.len < i+len(d) {
|
||||
clen := r.len
|
||||
r.fill(i + len(d))
|
||||
if r.len == clen {
|
||||
fn := r.fill(i + len(d))
|
||||
if fn == 0 {
|
||||
return 0, false
|
||||
}
|
||||
}
|
||||
@ -297,34 +310,23 @@ func (r *reader) read(p []byte) (int, error) {
|
||||
return 0, r.err
|
||||
}
|
||||
|
||||
var n int
|
||||
for len(p) > 0 {
|
||||
if len(p) == 0 {
|
||||
return 0, nil
|
||||
}
|
||||
|
||||
if len(r.segments) == 0 {
|
||||
r.allocate()
|
||||
if r.err != nil {
|
||||
break
|
||||
return 0, r.err
|
||||
}
|
||||
}
|
||||
|
||||
var partialRead bool
|
||||
if r.len == 0 {
|
||||
_, full := r.fillSegment()
|
||||
partialRead = !full
|
||||
}
|
||||
|
||||
ni := r.copy(p)
|
||||
if ni == 0 {
|
||||
break
|
||||
}
|
||||
|
||||
r.consume(ni)
|
||||
p = p[ni:]
|
||||
n += ni
|
||||
if partialRead {
|
||||
break
|
||||
}
|
||||
r.fillSegment()
|
||||
}
|
||||
|
||||
n := r.copy(p)
|
||||
r.consume(n)
|
||||
if r.err != nil && r.len == 0 {
|
||||
r.free()
|
||||
if n == 0 {
|
||||
@ -335,13 +337,13 @@ func (r *reader) read(p []byte) (int, error) {
|
||||
return n, nil
|
||||
}
|
||||
|
||||
func (r *reader) readBytes(delimiter []byte, max int) ([]byte, bool, error) {
|
||||
func (r *reader) readBytes(delimiter []byte, max int) ([]byte, error) {
|
||||
if r.err != nil && r.len == 0 {
|
||||
return nil, false, r.err
|
||||
return nil, r.err
|
||||
}
|
||||
|
||||
if len(delimiter) == 0 {
|
||||
return nil, true, nil
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
var (
|
||||
@ -356,25 +358,14 @@ func (r *reader) readBytes(delimiter []byte, max int) ([]byte, bool, error) {
|
||||
r.consume(n)
|
||||
}
|
||||
|
||||
if !ok && r.err != nil {
|
||||
l = r.len
|
||||
if l > max {
|
||||
l = max
|
||||
}
|
||||
|
||||
p = make([]byte, l)
|
||||
n = r.copy(p)
|
||||
r.consume(n)
|
||||
}
|
||||
|
||||
if r.err != nil && r.len == 0 {
|
||||
r.free()
|
||||
if n == 0 {
|
||||
return nil, ok, r.err
|
||||
return nil, r.err
|
||||
}
|
||||
}
|
||||
|
||||
return p, ok, nil
|
||||
return p, nil
|
||||
}
|
||||
|
||||
func (r *reader) readUTF8(max int) ([]rune, int, error) {
|
||||
@ -392,16 +383,23 @@ func (r *reader) readUTF8(max int) ([]rune, int, error) {
|
||||
break
|
||||
}
|
||||
|
||||
var nullRead bool
|
||||
var zeroRead bool
|
||||
b := r.view(n, 4)
|
||||
if len(b) < 4 && !utf8.FullRune(b) {
|
||||
clen := r.len
|
||||
r.fill(n + 4)
|
||||
b = r.view(n, 4)
|
||||
nullRead = r.len == clen
|
||||
for len(b) < 4 && !utf8.FullRune(b) {
|
||||
fn := r.fill(n + 4)
|
||||
zeroRead = fn == 0
|
||||
if zeroRead {
|
||||
break
|
||||
}
|
||||
|
||||
if nullRead && r.err == nil || len(b) == 0 {
|
||||
b = r.view(n, 4)
|
||||
}
|
||||
|
||||
if len(b) == 0 {
|
||||
break
|
||||
}
|
||||
|
||||
if zeroRead && r.err == nil {
|
||||
break
|
||||
}
|
||||
|
||||
@ -435,12 +433,17 @@ func (r *reader) peek(max int) ([]byte, error) {
|
||||
return nil, r.err
|
||||
}
|
||||
|
||||
r.fill(max)
|
||||
for r.len < max {
|
||||
if fn := r.fill(max); fn == 0 {
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
v := r.view(0, max)
|
||||
if r.err != nil && r.len == 0 {
|
||||
r.free()
|
||||
if len(v) == 0 {
|
||||
return v, r.err
|
||||
return nil, r.err
|
||||
}
|
||||
}
|
||||
|
||||
@ -478,7 +481,7 @@ func (r *reader) writeTo(w io.Writer) (int64, error) {
|
||||
}
|
||||
}
|
||||
|
||||
fn, _ := r.fillSegment()
|
||||
fn := r.fillSegment()
|
||||
if fn == 0 && r.err == nil {
|
||||
return n, io.ErrNoProgress
|
||||
}
|
||||
|
||||
@ -12,23 +12,23 @@ func TestReadUTF8(t *testing.T) {
|
||||
t.Run(title, func(t *testing.T) {
|
||||
t.Run("read all after error", func(t *testing.T) {
|
||||
g := &gen{
|
||||
rng: utf8W2Range,
|
||||
max: 30,
|
||||
rng: utf8Range,
|
||||
max: 24,
|
||||
fastErr: true,
|
||||
}
|
||||
|
||||
o := buffer.Options{Pool: buffer.NoPool(1 << 12)}
|
||||
o := buffer.Options{BufferPool: buffer.NoPool(1 << 12)}
|
||||
r := cr(g, o)
|
||||
runes, n0, err := r.ReadUTF8(12)
|
||||
runes0, n0, err := r.ReadUTF8(12)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if len(runes) != 12 {
|
||||
t.Fatal("invalid read 0", len(runes), n0)
|
||||
if len(runes0) != 12 {
|
||||
t.Fatal("invalid read 0", len(runes0), n0)
|
||||
}
|
||||
|
||||
if string(runes) != string(generateFrom(utf8W2Range, n0)) {
|
||||
if string(runes0) != string(generateFrom(utf8Range, n0)) {
|
||||
t.Fatal("invalid content")
|
||||
}
|
||||
|
||||
@ -41,8 +41,8 @@ func TestReadUTF8(t *testing.T) {
|
||||
t.Fatal("invalid read 1", len(runes1), n0, n1)
|
||||
}
|
||||
|
||||
if string(runes1) != string(generateFrom(utf8W2Range, n0+n1)[n0:]) {
|
||||
t.Fatal("invalid content", string(runes1), string(generateFrom(utf8W2Range, n0+n1)[n0:]))
|
||||
if string(runes1) != string(generateFrom(utf8Range, n0+n1)[n0:]) {
|
||||
t.Fatal("invalid content", string(runes1), string(generateFrom(utf8Range, n0+n1)[n0:]))
|
||||
}
|
||||
|
||||
runes2, n2, err := r.ReadUTF8(12)
|
||||
@ -61,7 +61,7 @@ func TestReadUTF8(t *testing.T) {
|
||||
|
||||
t.Run("ascii", func(t *testing.T) {
|
||||
g := &gen{max: 1 << 15}
|
||||
o := buffer.Options{Pool: buffer.NoPool(1 << 12)}
|
||||
o := buffer.Options{BufferPool: buffer.NoPool(1 << 12)}
|
||||
r := cr(g, o)
|
||||
runes, n, err := r.ReadUTF8(12)
|
||||
if err != nil {
|
||||
@ -83,7 +83,7 @@ func TestReadUTF8(t *testing.T) {
|
||||
max: 1 << 15,
|
||||
}
|
||||
|
||||
o := buffer.Options{Pool: buffer.NoPool(1 << 12)}
|
||||
o := buffer.Options{BufferPool: buffer.NoPool(1 << 12)}
|
||||
r := cr(g, o)
|
||||
runes, n, err := r.ReadUTF8(12)
|
||||
if err != nil {
|
||||
@ -105,7 +105,7 @@ func TestReadUTF8(t *testing.T) {
|
||||
max: 1 << 15,
|
||||
}
|
||||
|
||||
o := buffer.Options{Pool: buffer.NoPool(9)}
|
||||
o := buffer.Options{BufferPool: buffer.NoPool(9)}
|
||||
r := cr(g, o)
|
||||
runes, n, err := r.ReadUTF8(12)
|
||||
if err != nil {
|
||||
@ -130,7 +130,7 @@ func TestReadUTF8(t *testing.T) {
|
||||
customContent: map[int][]byte{len(utf8Range): brokenRange},
|
||||
}
|
||||
|
||||
o := buffer.Options{Pool: buffer.NoPool(1 << 12)}
|
||||
o := buffer.Options{BufferPool: buffer.NoPool(1 << 12)}
|
||||
r := cr(g, o)
|
||||
runes, n, err := r.ReadUTF8(24)
|
||||
if err != nil {
|
||||
@ -160,7 +160,7 @@ func TestReadUTF8(t *testing.T) {
|
||||
|
||||
t.Run("immediate err", func(t *testing.T) {
|
||||
g := &gen{rng: utf8Range}
|
||||
o := buffer.Options{Pool: buffer.NoPool(1 << 12)}
|
||||
o := buffer.Options{BufferPool: buffer.NoPool(1 << 12)}
|
||||
r := cr(g, o)
|
||||
runes, n, err := r.ReadUTF8(12)
|
||||
if !errors.Is(err, io.EOF) {
|
||||
@ -189,7 +189,7 @@ func TestReadUTF8(t *testing.T) {
|
||||
nullReadAfter: []int{nullReadAfter, nullReadAfter},
|
||||
}
|
||||
|
||||
o := buffer.Options{Pool: buffer.NoPool(nullReadAfter)}
|
||||
o := buffer.Options{BufferPool: buffer.NoPool(nullReadAfter)}
|
||||
r := cr(g, o)
|
||||
runes, _, err := r.ReadUTF8(numRunes - 2) // -2 for min read in readUTF8
|
||||
if err != nil {
|
||||
|
||||
10
writer.go
10
writer.go
@ -27,7 +27,7 @@ func (w *writer) write(p []byte) (int, error) {
|
||||
}
|
||||
|
||||
if len(w.buffer) == 0 {
|
||||
w.buffer, w.err = w.options.Pool.Get()
|
||||
w.buffer, w.err = w.options.BufferPool.Get()
|
||||
if len(w.buffer) == 0 && w.err == nil {
|
||||
w.err = ErrZeroAllocation
|
||||
}
|
||||
@ -55,7 +55,7 @@ func (w *writer) readFrom(r io.Reader) (int64, error) {
|
||||
}
|
||||
|
||||
if len(w.buffer) == 0 {
|
||||
w.buffer, w.err = w.options.Pool.Get()
|
||||
w.buffer, w.err = w.options.BufferPool.Get()
|
||||
if len(w.buffer) == 0 && w.err == nil {
|
||||
w.err = ErrZeroAllocation
|
||||
}
|
||||
@ -117,11 +117,11 @@ func (w *writer) flush() error {
|
||||
func (w *writer) close() error {
|
||||
newErr := w.err == nil
|
||||
w.flush()
|
||||
if len(w.buffer) > 0 {
|
||||
w.options.Pool.Put(w.buffer)
|
||||
w.buffer = nil
|
||||
if len(w.buffer) > 0 && len(w.options.InitialSegment) == 0 {
|
||||
w.options.BufferPool.Put(w.buffer)
|
||||
}
|
||||
|
||||
w.buffer = nil
|
||||
if newErr && w.err != nil {
|
||||
return w.err
|
||||
}
|
||||
|
||||
@ -10,7 +10,7 @@ import (
|
||||
func TestWriter(t *testing.T) {
|
||||
t.Run("write out", func(t *testing.T) {
|
||||
w := &writer{}
|
||||
o := buffer.Options{Pool: buffer.NoPool(32)}
|
||||
o := buffer.Options{BufferPool: buffer.NoPool(32)}
|
||||
b := buffer.BufferedWriter(w, o)
|
||||
if n, err := b.Write([]byte("123")); n != 3 || err != nil {
|
||||
t.Fatal(n, err)
|
||||
@ -35,7 +35,7 @@ func TestWriter(t *testing.T) {
|
||||
|
||||
t.Run("zero bytes when empty", func(t *testing.T) {
|
||||
w := &writer{}
|
||||
o := buffer.Options{Pool: buffer.NoPool(32)}
|
||||
o := buffer.Options{BufferPool: buffer.NoPool(32)}
|
||||
b := buffer.BufferedWriter(w, o)
|
||||
if n, err := b.Write(nil); n != 0 || err != nil {
|
||||
t.Fatal(n, err)
|
||||
@ -44,7 +44,7 @@ func TestWriter(t *testing.T) {
|
||||
|
||||
t.Run("zero bytes when erred", func(t *testing.T) {
|
||||
w := &writer{errAfter: []int{3}}
|
||||
o := buffer.Options{Pool: buffer.NoPool(2)}
|
||||
o := buffer.Options{BufferPool: buffer.NoPool(2)}
|
||||
b := buffer.BufferedWriter(w, o)
|
||||
if n, err := b.Write([]byte("123")); n != 3 || err != nil {
|
||||
t.Fatal(n, err)
|
||||
@ -69,7 +69,7 @@ func TestWriter(t *testing.T) {
|
||||
|
||||
t.Run("zero bytes when not empty", func(t *testing.T) {
|
||||
w := &writer{errAfter: []int{3}}
|
||||
o := buffer.Options{Pool: buffer.NoPool(32)}
|
||||
o := buffer.Options{BufferPool: buffer.NoPool(32)}
|
||||
b := buffer.BufferedWriter(w, o)
|
||||
if n, err := b.Write([]byte("123")); n != 3 || err != nil {
|
||||
t.Fatal(n, err)
|
||||
@ -91,7 +91,7 @@ func TestWriter(t *testing.T) {
|
||||
errAfter: []int{0},
|
||||
}
|
||||
|
||||
o := buffer.Options{Pool: p}
|
||||
o := buffer.Options{BufferPool: p}
|
||||
b := buffer.BufferedWriter(w, o)
|
||||
if n, err := b.Write([]byte("123")); n != 0 || !errors.Is(err, errTest) {
|
||||
t.Fatal(n, err)
|
||||
@ -100,7 +100,7 @@ func TestWriter(t *testing.T) {
|
||||
|
||||
t.Run("no underlying write until full", func(t *testing.T) {
|
||||
w := &writer{}
|
||||
o := buffer.Options{Pool: buffer.NoPool(4)}
|
||||
o := buffer.Options{BufferPool: buffer.NoPool(4)}
|
||||
b := buffer.BufferedWriter(w, o)
|
||||
if n, err := b.Write([]byte("123")); n != 3 || err != nil {
|
||||
t.Fatal(n, err)
|
||||
@ -136,7 +136,7 @@ func TestWriter(t *testing.T) {
|
||||
|
||||
t.Run("auto flush when write larger than buffer", func(t *testing.T) {
|
||||
w := &writer{}
|
||||
o := buffer.Options{Pool: buffer.NoPool(4)}
|
||||
o := buffer.Options{BufferPool: buffer.NoPool(4)}
|
||||
b := buffer.BufferedWriter(w, o)
|
||||
if n, err := b.Write([]byte("123456")); err != nil {
|
||||
t.Fatal(n, err)
|
||||
@ -149,7 +149,7 @@ func TestWriter(t *testing.T) {
|
||||
|
||||
t.Run("auto flush when multiple smaller writes fill the buffer", func(t *testing.T) {
|
||||
w := &writer{}
|
||||
o := buffer.Options{Pool: buffer.NoPool(4)}
|
||||
o := buffer.Options{BufferPool: buffer.NoPool(4)}
|
||||
b := buffer.BufferedWriter(w, o)
|
||||
if n, err := b.Write([]byte("123")); err != nil {
|
||||
t.Fatal(n, err)
|
||||
@ -170,7 +170,7 @@ func TestWriter(t *testing.T) {
|
||||
|
||||
t.Run("flush on close", func(t *testing.T) {
|
||||
w := &writer{}
|
||||
o := buffer.Options{Pool: buffer.NoPool(4)}
|
||||
o := buffer.Options{BufferPool: buffer.NoPool(4)}
|
||||
b := buffer.BufferedWriter(w, o)
|
||||
if n, err := b.Write([]byte("123")); err != nil {
|
||||
t.Fatal(n, err)
|
||||
@ -191,7 +191,7 @@ func TestWriter(t *testing.T) {
|
||||
|
||||
t.Run("manual flush", func(t *testing.T) {
|
||||
w := &writer{}
|
||||
o := buffer.Options{Pool: buffer.NoPool(4)}
|
||||
o := buffer.Options{BufferPool: buffer.NoPool(4)}
|
||||
b := buffer.BufferedWriter(w, o)
|
||||
if n, err := b.Write([]byte("123")); err != nil {
|
||||
t.Fatal(n, err)
|
||||
@ -212,7 +212,7 @@ func TestWriter(t *testing.T) {
|
||||
|
||||
t.Run("write after flush", func(t *testing.T) {
|
||||
w := &writer{}
|
||||
o := buffer.Options{Pool: buffer.NoPool(4)}
|
||||
o := buffer.Options{BufferPool: buffer.NoPool(4)}
|
||||
b := buffer.BufferedWriter(w, o)
|
||||
if n, err := b.Write([]byte("123")); err != nil {
|
||||
t.Fatal(n, err)
|
||||
@ -246,7 +246,7 @@ func TestWriter(t *testing.T) {
|
||||
t.Run("zero write recover", func(t *testing.T) {
|
||||
w := &writer{zeroAfter: []int{2}}
|
||||
p := &fakePool{allocSize: 2}
|
||||
o := buffer.Options{Pool: p}
|
||||
o := buffer.Options{BufferPool: p}
|
||||
b := buffer.BufferedWriter(w, o)
|
||||
if n, err := b.Write([]byte("123")); err != nil {
|
||||
t.Fatal(n, err)
|
||||
@ -268,7 +268,7 @@ func TestWriter(t *testing.T) {
|
||||
t.Run("zero write terminal", func(t *testing.T) {
|
||||
w := &writer{zeroAfter: []int{2, 2}}
|
||||
p := &fakePool{allocSize: 2}
|
||||
o := buffer.Options{Pool: p}
|
||||
o := buffer.Options{BufferPool: p}
|
||||
b := buffer.BufferedWriter(w, o)
|
||||
if n, err := b.Write([]byte("123")); err != nil {
|
||||
t.Fatal(n, err)
|
||||
@ -282,7 +282,7 @@ func TestWriter(t *testing.T) {
|
||||
t.Run("partial write", func(t *testing.T) {
|
||||
w := &writer{shortAfter: []int{2}}
|
||||
p := &fakePool{allocSize: 2}
|
||||
o := buffer.Options{Pool: p}
|
||||
o := buffer.Options{BufferPool: p}
|
||||
b := buffer.BufferedWriter(w, o)
|
||||
if n, err := b.Write([]byte("123")); err != nil {
|
||||
t.Fatal(n, err)
|
||||
@ -304,7 +304,7 @@ func TestWriter(t *testing.T) {
|
||||
t.Run("buffer released on write error immediately", func(t *testing.T) {
|
||||
w := &writer{errAfter: []int{0}}
|
||||
p := &fakePool{allocSize: 2}
|
||||
o := buffer.Options{Pool: p}
|
||||
o := buffer.Options{BufferPool: p}
|
||||
b := buffer.BufferedWriter(w, o)
|
||||
if n, err := b.Write([]byte("123")); n != 2 || !errors.Is(err, errTest) {
|
||||
t.Fatal(n, err)
|
||||
@ -318,7 +318,7 @@ func TestWriter(t *testing.T) {
|
||||
t.Run("buffer released on write error", func(t *testing.T) {
|
||||
w := &writer{errAfter: []int{3}}
|
||||
p := &fakePool{allocSize: 2}
|
||||
o := buffer.Options{Pool: p}
|
||||
o := buffer.Options{BufferPool: p}
|
||||
b := buffer.BufferedWriter(w, o)
|
||||
if n, err := b.Write([]byte("123")); n != 3 || err != nil {
|
||||
t.Fatal(n, err)
|
||||
@ -340,7 +340,7 @@ func TestWriter(t *testing.T) {
|
||||
t.Run("close on err", func(t *testing.T) {
|
||||
w := &writer{errAfter: []int{3}}
|
||||
p := &fakePool{allocSize: 2}
|
||||
o := buffer.Options{Pool: p}
|
||||
o := buffer.Options{BufferPool: p}
|
||||
b := buffer.BufferedWriter(w, o)
|
||||
if n, err := b.Write([]byte("123")); n != 3 || err != nil {
|
||||
t.Fatal(n, err)
|
||||
@ -366,7 +366,7 @@ func TestWriter(t *testing.T) {
|
||||
t.Run("close and flush err", func(t *testing.T) {
|
||||
w := &writer{errAfter: []int{3}}
|
||||
p := &fakePool{allocSize: 2}
|
||||
o := buffer.Options{Pool: p}
|
||||
o := buffer.Options{BufferPool: p}
|
||||
b := buffer.BufferedWriter(w, o)
|
||||
if n, err := b.Write([]byte("123")); n != 3 || err != nil {
|
||||
t.Fatal(n, err)
|
||||
@ -384,7 +384,7 @@ func TestWriter(t *testing.T) {
|
||||
t.Run("close", func(t *testing.T) {
|
||||
w := &writer{}
|
||||
p := &fakePool{allocSize: 2}
|
||||
o := buffer.Options{Pool: p}
|
||||
o := buffer.Options{BufferPool: p}
|
||||
b := buffer.BufferedWriter(w, o)
|
||||
if n, err := b.Write([]byte("123")); n != 3 || err != nil {
|
||||
t.Fatal(n, err)
|
||||
@ -406,7 +406,7 @@ func TestWriter(t *testing.T) {
|
||||
t.Run("zero allocation", func(t *testing.T) {
|
||||
w := &writer{}
|
||||
p := &fakePool{}
|
||||
o := buffer.Options{Pool: p}
|
||||
o := buffer.Options{BufferPool: p}
|
||||
b := buffer.BufferedWriter(w, o)
|
||||
if n, err := b.Write([]byte("123")); n != 0 || !errors.Is(err, buffer.ErrZeroAllocation) {
|
||||
t.Fatal(n, err)
|
||||
@ -418,7 +418,7 @@ func TestWriter(t *testing.T) {
|
||||
w := &writer{}
|
||||
r := &gen{max: 1 << 12}
|
||||
p := buffer.NoPool(1 << 9)
|
||||
o := buffer.Options{Pool: p}
|
||||
o := buffer.Options{BufferPool: p}
|
||||
b := buffer.BufferedWriter(w, o)
|
||||
n, err := b.ReadFrom(r)
|
||||
if n != 1<<12 || err != nil {
|
||||
@ -434,7 +434,7 @@ func TestWriter(t *testing.T) {
|
||||
}
|
||||
|
||||
p := buffer.NoPool(1 << 9)
|
||||
o := buffer.Options{Pool: p}
|
||||
o := buffer.Options{BufferPool: p}
|
||||
b := buffer.BufferedWriter(w, o)
|
||||
n, err := b.ReadFrom(r)
|
||||
if n != 1<<12 || !errors.Is(err, errTest) {
|
||||
@ -450,7 +450,7 @@ func TestWriter(t *testing.T) {
|
||||
}
|
||||
|
||||
p := buffer.NoPool(1 << 9)
|
||||
o := buffer.Options{Pool: p}
|
||||
o := buffer.Options{BufferPool: p}
|
||||
b := buffer.BufferedWriter(w, o)
|
||||
n, err := b.ReadFrom(r)
|
||||
if n != 1<<11 || !errors.Is(err, errTest) {
|
||||
@ -462,7 +462,7 @@ func TestWriter(t *testing.T) {
|
||||
w := &writer{errAfter: []int{1 << 11}}
|
||||
r := &gen{max: 1 << 12}
|
||||
p := buffer.NoPool(1 << 9)
|
||||
o := buffer.Options{Pool: p}
|
||||
o := buffer.Options{BufferPool: p}
|
||||
b := buffer.BufferedWriter(w, o)
|
||||
n, err := b.ReadFrom(r)
|
||||
if n != 1<<11+1<<9 || !errors.Is(err, errTest) {
|
||||
@ -474,7 +474,7 @@ func TestWriter(t *testing.T) {
|
||||
w := &writer{}
|
||||
r := &gen{max: 1 << 12}
|
||||
p := &fakePool{}
|
||||
o := buffer.Options{Pool: p}
|
||||
o := buffer.Options{BufferPool: p}
|
||||
b := buffer.BufferedWriter(w, o)
|
||||
n, err := b.ReadFrom(r)
|
||||
if n != 0 || !errors.Is(err, buffer.ErrZeroAllocation) {
|
||||
@ -490,7 +490,7 @@ func TestWriter(t *testing.T) {
|
||||
}
|
||||
|
||||
p := &fakePool{allocSize: 1 << 9}
|
||||
o := buffer.Options{Pool: p}
|
||||
o := buffer.Options{BufferPool: p}
|
||||
b := buffer.BufferedWriter(w, o)
|
||||
n, err := b.ReadFrom(r)
|
||||
if n != 512 || !errors.Is(err, io.ErrNoProgress) {
|
||||
|
||||
@ -13,7 +13,7 @@ func TestWriteTo(t *testing.T) {
|
||||
t.Run(title, func(t *testing.T) {
|
||||
t.Run("write out from zero", func(t *testing.T) {
|
||||
g := &gen{max: 1 << 15}
|
||||
o := buffer.Options{Pool: buffer.NoPool(1 << 12)}
|
||||
o := buffer.Options{BufferPool: buffer.NoPool(1 << 12)}
|
||||
r := cr(g, o)
|
||||
|
||||
var b bytes.Buffer
|
||||
@ -33,7 +33,7 @@ func TestWriteTo(t *testing.T) {
|
||||
|
||||
t.Run("write out from started", func(t *testing.T) {
|
||||
g := &gen{max: 1 << 15}
|
||||
o := buffer.Options{Pool: buffer.NoPool(1 << 12)}
|
||||
o := buffer.Options{BufferPool: buffer.NoPool(1 << 12)}
|
||||
r := cr(g, o)
|
||||
p := make([]byte, 256)
|
||||
n, err := r.Read(p)
|
||||
@ -66,7 +66,7 @@ func TestWriteTo(t *testing.T) {
|
||||
|
||||
t.Run("after EOF", func(t *testing.T) {
|
||||
g := &gen{max: 256}
|
||||
o := buffer.Options{Pool: buffer.NoPool(1 << 12)}
|
||||
o := buffer.Options{BufferPool: buffer.NoPool(1 << 12)}
|
||||
r := cr(g, o)
|
||||
b, err := r.Peek(512)
|
||||
if err != nil {
|
||||
@ -94,7 +94,7 @@ func TestWriteTo(t *testing.T) {
|
||||
|
||||
t.Run("after eof empty", func(t *testing.T) {
|
||||
g := &gen{max: 256}
|
||||
o := buffer.Options{Pool: buffer.NoPool(1 << 12)}
|
||||
o := buffer.Options{BufferPool: buffer.NoPool(1 << 12)}
|
||||
r := cr(g, o)
|
||||
p := make([]byte, 512)
|
||||
n, err := r.Read(p)
|
||||
@ -127,7 +127,7 @@ func TestWriteTo(t *testing.T) {
|
||||
|
||||
t.Run("write error", func(t *testing.T) {
|
||||
g := &gen{max: 1 << 15}
|
||||
o := buffer.Options{Pool: buffer.NoPool(1 << 12)}
|
||||
o := buffer.Options{BufferPool: buffer.NoPool(1 << 12)}
|
||||
r := cr(g, o)
|
||||
w := &writer{errAfter: []int{256}}
|
||||
n, err := r.WriteTo(w)
|
||||
@ -146,7 +146,7 @@ func TestWriteTo(t *testing.T) {
|
||||
|
||||
t.Run("short write", func(t *testing.T) {
|
||||
g := &gen{max: 1 << 15}
|
||||
o := buffer.Options{Pool: buffer.NoPool(1 << 12)}
|
||||
o := buffer.Options{BufferPool: buffer.NoPool(1 << 12)}
|
||||
r := cr(g, o)
|
||||
w := &writer{shortAfter: []int{256}}
|
||||
n, err := r.WriteTo(w)
|
||||
@ -174,7 +174,7 @@ func TestWriteTo(t *testing.T) {
|
||||
fastErr: true,
|
||||
}
|
||||
|
||||
o := buffer.Options{Pool: buffer.NoPool(64)}
|
||||
o := buffer.Options{BufferPool: buffer.NoPool(64)}
|
||||
r := cr(g, o)
|
||||
b, err := r.Peek(512)
|
||||
if err != nil {
|
||||
@ -206,7 +206,7 @@ func TestWriteTo(t *testing.T) {
|
||||
errAfter: []int{256},
|
||||
}
|
||||
|
||||
o := buffer.Options{Pool: buffer.NoPool(1 << 12)}
|
||||
o := buffer.Options{BufferPool: buffer.NoPool(1 << 12)}
|
||||
r := cr(g, o)
|
||||
p := make([]byte, 1<<15)
|
||||
n, err := r.Read(p)
|
||||
@ -243,7 +243,7 @@ func TestWriteTo(t *testing.T) {
|
||||
nullReadAfter: []int{256, 256},
|
||||
}
|
||||
|
||||
o := buffer.Options{Pool: buffer.NoPool(1 << 12)}
|
||||
o := buffer.Options{BufferPool: buffer.NoPool(1 << 12)}
|
||||
r := cr(g, o)
|
||||
|
||||
var b bytes.Buffer
|
||||
@ -267,7 +267,7 @@ func TestWriteTo(t *testing.T) {
|
||||
errAfter: []int{256},
|
||||
}
|
||||
|
||||
o := buffer.Options{Pool: buffer.NoPool(1 << 12)}
|
||||
o := buffer.Options{BufferPool: buffer.NoPool(1 << 12)}
|
||||
r := cr(g, o)
|
||||
|
||||
var b bytes.Buffer
|
||||
|
||||
Loading…
Reference in New Issue
Block a user