Skip to content

Commit

Permalink
Merge pull request #4 from jf-tech/tests
Browse files Browse the repository at this point in the history
bug fix: replace can be nil/empty
  • Loading branch information
jf-tech authored May 27, 2020
2 parents da541c5 + b80abf2 commit 792bbf6
Show file tree
Hide file tree
Showing 2 changed files with 19 additions and 16 deletions.
23 changes: 11 additions & 12 deletions readers.go
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ type BytesReplacingReader struct {
const defaultBufSize = int(4096)

// NewBytesReplacingReader creates a new `*BytesReplacingReader`.
// `search` cannot be nil/empty. `replace` can.
func NewBytesReplacingReader(r io.Reader, search, replace []byte) *BytesReplacingReader {
return (&BytesReplacingReader{}).Reset(r, search, replace)
}
Expand All @@ -60,24 +61,15 @@ func max(a, b int) int {
return b
}

func min(a, b int) int {
if a < b {
return a
}
return b
}

// Reset allows reuse of a previous allocated `*BytesReplacingReader` for buf allocation optimization.
// `search` cannot be nil/empty. `replace` can.
func (r *BytesReplacingReader) Reset(r1 io.Reader, search1, replace1 []byte) *BytesReplacingReader {
if r1 == nil {
panic("io.Reader cannot be nil")
}
if len(search1) == 0 {
panic("search token cannot be nil/empty")
}
if len(replace1) == 0 {
panic("replace token cannot be nil/empty")
}
r.r = r1
r.search = search1
r.searchLen = len(search1)
Expand All @@ -86,12 +78,19 @@ func (r *BytesReplacingReader) Reset(r1 io.Reader, search1, replace1 []byte) *By
r.lenDelta = r.replaceLen - r.searchLen // could be negative
r.err = nil
bufSize := max(defaultBufSize, max(r.searchLen, r.replaceLen))
if r.buf == nil || cap(r.buf) < bufSize {
if r.buf == nil || len(r.buf) < bufSize {
r.buf = make([]byte, bufSize)
}
r.buf0 = 0
r.buf1 = 0
r.max = min(cap(r.buf), (cap(r.buf)/r.replaceLen)*r.searchLen)
r.max = len(r.buf)
if r.searchLen < r.replaceLen {
// If len(search) < len(replace), then we have to assume the worst case:
// what's the max bound value such that if we have consecutive 'search' filling up
// the buf up to buf[:max], and all of them are placed with 'replace', and the final
// result won't end up exceed the len(buf)?
r.max = (len(r.buf) / r.replaceLen) * r.searchLen
}
return r
}

Expand Down
12 changes: 8 additions & 4 deletions readers_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,13 @@ func TestBytesReplacingReader(t *testing.T) {
replace: []byte{9},
expected: []byte{1, 9, 2, 3, 4, 5, 6, 7, 8},
},
{
name: "strip out search, no replace",
input: []byte{1, 2, 3, 2, 2, 3, 4, 2, 3, 2, 8},
search: []byte{2, 3, 2},
replace: []byte{},
expected: []byte{1, 2, 3, 4, 8},
},
{
name: "len(replace) == len(search)",
input: []byte{1, 2, 3, 4, 5, 5, 5, 5, 5, 5, 5, 5, 5},
Expand Down Expand Up @@ -85,9 +92,6 @@ func TestBytesReplacingReader(t *testing.T) {
assert.PanicsWithValue(t, "search token cannot be nil/empty", func() {
(&BytesReplacingReader{}).Reset(strings.NewReader("test"), nil, []byte("est"))
})
assert.PanicsWithValue(t, "replace token cannot be nil/empty", func() {
NewBytesReplacingReader(strings.NewReader("test"), []byte("est"), nil)
})
}

func createTestInput(length int, numTarget int) []byte {
Expand Down Expand Up @@ -151,7 +155,7 @@ func BenchmarkBytesReplacingReader_50KBLength_1000Targets(b *testing.B) {
}
}

func BenchmarkRegularReader_50KBLength_100Targets(b *testing.B) {
func BenchmarkRegularReader_50KBLength_1000Targets(b *testing.B) {
for i := 0; i < b.N; i++ {
_, _ = ioutil.ReadAll(bytes.NewReader(testInput50KBLength1000Targets))
}
Expand Down

0 comments on commit 792bbf6

Please sign in to comment.