aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNigel Tao <nigeltao@golang.org>2010-12-15 08:50:08 +1100
committerNigel Tao <nigeltao@golang.org>2010-12-15 08:50:08 +1100
commit8b64cd9c5e13768828d1f5f979c62680b5e90ff0 (patch)
tree12eb7bd62b5bce95c4e35718be4b0c93da586442
parentda1cbe5d11b60ea6e640f7ff3c5e3fff1a642b61 (diff)
downloadgo-8b64cd9c5e13768828d1f5f979c62680b5e90ff0.tar.gz
go-8b64cd9c5e13768828d1f5f979c62680b5e90ff0.zip
reflect: add Append and AppendSlice functions.
R=r, nigeltao_gnome, rog, niemeyer CC=golang-dev https://golang.org/cl/3529042
-rw-r--r--src/pkg/reflect/all_test.go49
-rw-r--r--src/pkg/reflect/value.go46
2 files changed, 94 insertions, 1 deletions
diff --git a/src/pkg/reflect/all_test.go b/src/pkg/reflect/all_test.go
index aa831f3365..1652e17316 100644
--- a/src/pkg/reflect/all_test.go
+++ b/src/pkg/reflect/all_test.go
@@ -498,7 +498,54 @@ func TestFunctionValue(t *testing.T) {
assert(t, v.Type().String(), "func()")
}
-func TestCopyArray(t *testing.T) {
+var appendTests = []struct {
+ orig, extra []int
+}{
+ {make([]int, 2, 4), []int{22}},
+ {make([]int, 2, 4), []int{22, 33, 44}},
+}
+
+func TestAppend(t *testing.T) {
+ for i, test := range appendTests {
+ origLen, extraLen := len(test.orig), len(test.extra)
+ want := append(test.orig, test.extra...)
+ // Convert extra from []int to []Value.
+ e0 := make([]Value, len(test.extra))
+ for j, e := range test.extra {
+ e0[j] = NewValue(e)
+ }
+ // Convert extra from []int to *SliceValue.
+ e1 := NewValue(test.extra).(*SliceValue)
+ // Test Append.
+ a0 := NewValue(test.orig).(*SliceValue)
+ have0 := Append(a0, e0...).Interface().([]int)
+ if !DeepEqual(have0, want) {
+ t.Errorf("Append #%d: have %v, want %v", i, have0, want)
+ }
+ // Check that the orig and extra slices were not modified.
+ if len(test.orig) != origLen {
+ t.Errorf("Append #%d origLen: have %v, want %v", i, len(test.orig), origLen)
+ }
+ if len(test.extra) != extraLen {
+ t.Errorf("Append #%d extraLen: have %v, want %v", i, len(test.extra), extraLen)
+ }
+ // Test AppendSlice.
+ a1 := NewValue(test.orig).(*SliceValue)
+ have1 := AppendSlice(a1, e1).Interface().([]int)
+ if !DeepEqual(have1, want) {
+ t.Errorf("AppendSlice #%d: have %v, want %v", i, have1, want)
+ }
+ // Check that the orig and extra slices were not modified.
+ if len(test.orig) != origLen {
+ t.Errorf("AppendSlice #%d origLen: have %v, want %v", i, len(test.orig), origLen)
+ }
+ if len(test.extra) != extraLen {
+ t.Errorf("AppendSlice #%d extraLen: have %v, want %v", i, len(test.extra), extraLen)
+ }
+ }
+}
+
+func TestCopy(t *testing.T) {
a := []int{1, 2, 3, 4, 10, 9, 8, 7}
b := []int{11, 22, 33, 44, 1010, 99, 88, 77, 66, 55, 44}
c := []int{11, 22, 33, 44, 1010, 99, 88, 77, 66, 55, 44}
diff --git a/src/pkg/reflect/value.go b/src/pkg/reflect/value.go
index 8b2c1a9530..e0bcb1a39d 100644
--- a/src/pkg/reflect/value.go
+++ b/src/pkg/reflect/value.go
@@ -400,6 +400,52 @@ type ArrayOrSliceValue interface {
addr() addr
}
+// grow grows the slice s so that it can hold extra more values, allocating
+// more capacity if needed. It also returns the old and new slice lengths.
+func grow(s *SliceValue, extra int) (*SliceValue, int, int) {
+ i0 := s.Len()
+ i1 := i0 + extra
+ if i1 < i0 {
+ panic("append: slice overflow")
+ }
+ m := s.Cap()
+ if i1 <= m {
+ return s.Slice(0, i1), i0, i1
+ }
+ if m == 0 {
+ m = extra
+ } else {
+ for m < i1 {
+ if i0 < 1024 {
+ m += m
+ } else {
+ m += m / 4
+ }
+ }
+ }
+ t := MakeSlice(s.Type().(*SliceType), i1, m)
+ Copy(t, s)
+ return t, i0, i1
+}
+
+// Append appends the values x to a slice s and returns the resulting slice.
+// Each x must have the same type as s' element type.
+func Append(s *SliceValue, x ...Value) *SliceValue {
+ s, i0, i1 := grow(s, len(x))
+ for i, j := i0, 0; i < i1; i, j = i+1, j+1 {
+ s.Elem(i).SetValue(x[j])
+ }
+ return s
+}
+
+// AppendSlice appends a slice t to a slice s and returns the resulting slice.
+// The slices s and t must have the same element type.
+func AppendSlice(s, t *SliceValue) *SliceValue {
+ s, i0, i1 := grow(s, t.Len())
+ Copy(s.Slice(i0, i1), t)
+ return s
+}
+
// Copy copies the contents of src into dst until either
// dst has been filled or src has been exhausted.
// It returns the number of elements copied.