Commit d16ceca5 authored by Gustavo Niemeyer's avatar Gustavo Niemeyer

bytes: fix Replace so it actually copies

The documentation for bytes.Replace says it copies
the slice but it won't necessarily copy them.  Since
the data is mutable, breaking the contract is an issue.

We either have to fix this by making the copy at all
times, as suggested in this CL, or we should change the
documentation and perhaps make better use of the fact
it's fine to mutate the slice in place otherwise.

R=golang-dev, bradfitz, adg, rsc
CC=golang-dev
https://golang.org/cl/5081043
parent 96f968df
......@@ -572,13 +572,18 @@ func Runes(s []byte) []int {
// non-overlapping instances of old replaced by new.
// If n < 0, there is no limit on the number of replacements.
func Replace(s, old, new []byte, n int) []byte {
if n == 0 {
return s // avoid allocation
}
// Compute number of replacements.
if m := Count(s, old); m == 0 {
return s // avoid allocation
} else if n <= 0 || m < n {
m := 0
if n != 0 {
// Compute number of replacements.
m = Count(s, old)
}
if m == 0 {
// Nothing to do. Just copy.
t := make([]byte, len(s))
copy(t, s)
return t
}
if n < 0 || m < n {
n = m
}
......
......@@ -829,9 +829,15 @@ var ReplaceTests = []ReplaceTest{
func TestReplace(t *testing.T) {
for _, tt := range ReplaceTests {
if s := string(Replace([]byte(tt.in), []byte(tt.old), []byte(tt.new), tt.n)); s != tt.out {
in := append([]byte(tt.in), []byte("<spare>")...)
in = in[:len(tt.in)]
out := Replace(in, []byte(tt.old), []byte(tt.new), tt.n)
if s := string(out); s != tt.out {
t.Errorf("Replace(%q, %q, %q, %d) = %q, want %q", tt.in, tt.old, tt.new, tt.n, s, tt.out)
}
if cap(in) == cap(out) && &in[:1][0] == &out[:1][0] {
t.Errorf("Replace(%q, %q, %q, %d) didn't copy", tt.in, tt.old, tt.new, tt.n)
}
}
}
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment