From 8b64cd9c5e13768828d1f5f979c62680b5e90ff0 Mon Sep 17 00:00:00 2001 From: Nigel Tao Date: Wed, 15 Dec 2010 08:50:08 +1100 Subject: [PATCH] reflect: add Append and AppendSlice functions. R=r, nigeltao_gnome, rog, niemeyer CC=golang-dev https://golang.org/cl/3529042 --- src/pkg/reflect/all_test.go | 49 ++++++++++++++++++++++++++++++++++++- src/pkg/reflect/value.go | 46 ++++++++++++++++++++++++++++++++++ 2 files changed, 94 insertions(+), 1 deletion(-) 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.