From 7b45edb45016307151266731ccd158e14504598f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20M=C3=B6hrmann?= Date: Sun, 31 Oct 2021 10:04:03 +0100 Subject: [PATCH] bytes: add Clone function MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The new Clone function returns a copy of b[:len(b)] for the input byte slice b. The result may have additional unused capacity. Clone(nil) returns nil. Fixes #45038 Change-Id: I0469a202d77a7b491f1341c08915d07ddd1f0300 Reviewed-on: https://go-review.googlesource.com/c/go/+/359675 Run-TryBot: Martin Möhrmann TryBot-Result: Gopher Robot Reviewed-by: Joseph Tsai Reviewed-by: Martin Möhrmann Reviewed-by: Ian Lance Taylor --- api/next/45038.txt | 1 + src/bytes/bytes.go | 10 ++++++++++ src/bytes/bytes_test.go | 33 +++++++++++++++++++++++++++++++++ 3 files changed, 44 insertions(+) create mode 100644 api/next/45038.txt diff --git a/api/next/45038.txt b/api/next/45038.txt new file mode 100644 index 0000000000000..64c3f5f295817 --- /dev/null +++ b/api/next/45038.txt @@ -0,0 +1 @@ +pkg bytes, func Clone([]uint8) []uint8 #45038 diff --git a/src/bytes/bytes.go b/src/bytes/bytes.go index 659a82bcc8c95..27834fc6db723 100644 --- a/src/bytes/bytes.go +++ b/src/bytes/bytes.go @@ -1299,3 +1299,13 @@ func Cut(s, sep []byte) (before, after []byte, found bool) { } return s, nil, false } + +// Clone returns a copy of b[:len(b)]. +// The result may have additional unused capacity. +// Clone(nil) returns nil. +func Clone(b []byte) []byte { + if b == nil { + return nil + } + return append([]byte{}, b...) +} diff --git a/src/bytes/bytes_test.go b/src/bytes/bytes_test.go index b407fe8a2d91e..392657d1fada7 100644 --- a/src/bytes/bytes_test.go +++ b/src/bytes/bytes_test.go @@ -15,6 +15,7 @@ import ( "testing" "unicode" "unicode/utf8" + "unsafe" ) func eq(a, b []string) bool { @@ -2118,3 +2119,35 @@ func BenchmarkIndexPeriodic(b *testing.B) { }) } } + +func TestClone(t *testing.T) { + var cloneTests = [][]byte{ + []byte(nil), + []byte{}, + Clone([]byte{}), + []byte(strings.Repeat("a", 42))[:0], + []byte(strings.Repeat("a", 42))[:0:0], + []byte("short"), + []byte(strings.Repeat("a", 42)), + } + for _, input := range cloneTests { + clone := Clone(input) + if !Equal(clone, input) { + t.Errorf("Clone(%q) = %q; want %q", input, clone, input) + } + + if input == nil && clone != nil { + t.Errorf("Clone(%#v) return value should be equal to nil slice.", input) + } + + if input != nil && clone == nil { + t.Errorf("Clone(%#v) return value should not be equal to nil slice.", input) + } + + inputHeader := (*reflect.SliceHeader)(unsafe.Pointer(&input)) + cloneHeader := (*reflect.SliceHeader)(unsafe.Pointer(&clone)) + if cap(input) != 0 && cloneHeader.Data == inputHeader.Data { + t.Errorf("Clone(%q) return value should not reference inputs backing memory.", input) + } + } +}