Skip to content
Snippets Groups Projects
Commit d16ceca5 authored by Gustavo Niemeyer's avatar Gustavo Niemeyer
Browse files

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
No related branches found
No related tags found
No related merge requests found
......@@ -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)
}
}
}
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment