Skip to content

Commit

Permalink
fix: resolve bugs in array deep copy (#1)
Browse files Browse the repository at this point in the history
  • Loading branch information
xieyuschen authored Aug 3, 2023
1 parent 906c255 commit 0aa03ad
Show file tree
Hide file tree
Showing 5 changed files with 157 additions and 3 deletions.
2 changes: 1 addition & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -25,4 +25,4 @@ _testmain.go
*.out
*.log

.idea/
.idea/
10 changes: 8 additions & 2 deletions deepcopy.go
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ func copyRecursive(original, cpy reflect.Value) {
// Get the actual value being pointed to.
originalValue := original.Elem()

// if it isn't valid, return.
// if it isn't valid, return.
if !originalValue.IsValid() {
return
}
Expand Down Expand Up @@ -100,12 +100,18 @@ func copyRecursive(original, cpy reflect.Value) {
if original.IsNil() {
return
}

// Make a new slice and copy each element.
cpy.Set(reflect.MakeSlice(original.Type(), original.Len(), original.Cap()))
for i := 0; i < original.Len(); i++ {
copyRecursive(original.Index(i), cpy.Index(i))
}

case reflect.Array:
// since origin is an array, the capacity of array will be conserved
cpy.Set(reflect.New(original.Type()).Elem())
for i := 0; i < original.Len(); i++ {
copyRecursive(original.Index(i), cpy.Index(i))
}
case reflect.Map:
if original.IsNil() {
return
Expand Down
127 changes: 127 additions & 0 deletions deepcopy_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,135 @@ import (
"testing"
"time"
"unsafe"

"github.com/stretchr/testify/assert"
)

func TestArray(t *testing.T) {
verifyCases := map[string]struct {
modifyAndVerify func(t *testing.T)
}{
"array of map": {
modifyAndVerify: func(t *testing.T) {
origin := [1]map[string]int{
{
"1": 1,
},
}
copied := Copy(&origin)
assert.NotSame(t, origin, copied)
assert.NotSame(t, origin[0], copied.(*[1]map[string]int)[0])
origin[0]["1"] = 999
if 1 != copied.(*[1]map[string]int)[0]["1"] {
t.Fatalf("fail to do deep copy")
}
},
},
"array of *map": {
modifyAndVerify: func(t *testing.T) {
origin := [1]*map[string]int{
{
"1": 1,
},
}
copied := Copy(&origin)
assert.NotSame(t, origin, copied)
assert.NotSame(t, origin[0], copied.(*[1]*map[string]int)[0])
(*origin[0])["1"] = 999
if 1 != (*copied.(*[1]*map[string]int)[0])["1"] {
t.Fatalf("fail to do deep copy")
}
},
},
"array of *int": {
modifyAndVerify: func(t *testing.T) {
intp := func(i int) *int {
return &i
}
arrayOfInt := [3]*int{intp(1), intp(2)}
copied := Copy(&arrayOfInt)
assert.NotSame(t, &arrayOfInt, copied)
assert.NotSame(t, arrayOfInt[0], copied.(*[3]*int)[0])
arrayOfInt[0] = intp(999)
if 1 != *copied.(*[3]*int)[0] {
t.Fatalf("fail to do deep copy")
}
},
},
"array of int": {
modifyAndVerify: func(t *testing.T) {
arrayOfInt := [3]int{1, 2}
copied := Copy(&arrayOfInt)
assert.NotSame(t, &arrayOfInt, copied)
assert.NotSame(t, &arrayOfInt[0], copied.(*[3]int)[0])
arrayOfInt[0] = 999
if 1 != (*copied.(*[3]int))[0] {
t.Fatalf("fail to do deep copy")
}
},
},
"array of slice": {
modifyAndVerify: func(t *testing.T) {
arraySlice := [3][]int{{1, 2}}
copied := Copy(&arraySlice)
assert.NotSame(t, &arraySlice, copied)
assert.NotSame(t, &arraySlice[0], copied.(*[3][]int)[0])
assert.NotSame(t, &arraySlice[0][0], copied.(*[3][]int)[0][0])
arraySlice[0][0] = 999
if 1 != (*copied.(*[3][]int))[0][0] {
t.Fatalf("fail to do deep copy")
}
},
},
"array of *slice": {
modifyAndVerify: func(t *testing.T) {
PointerSlice := [3]*[]int{{1, 2}}
copied := Copy(&PointerSlice)
assert.NotSame(t, &PointerSlice, copied)
assert.NotSame(t, PointerSlice[0], copied.(*[3]*[]int)[0])
assert.NotSame(t, &(*PointerSlice[0])[0], &(*copied.(*[3]*[]int)[0])[0])
(*PointerSlice[0])[0] = 999
if 1 != (*(copied.(*[3]*[]int))[0])[0] {
t.Fatalf("fail to do deep copy")
}
},
},
"array of struct": {
modifyAndVerify: func(t *testing.T) {
type s struct {
I int
}
arrayOfStruct := [3]s{{I: 1}}
copied := Copy(&arrayOfStruct)
assert.NotSame(t, &arrayOfStruct, copied)
assert.NotSame(t, arrayOfStruct[0], copied.(*[3]s)[0])
arrayOfStruct[0].I = 999
if 1 != copied.(*[3]s)[0].I {
t.Fatalf("fail to do deep copy")
}
},
},
"array of *struct": {
modifyAndVerify: func(t *testing.T) {
type s struct {
I int
}
arrayOfPointerStruct := [3]*s{&s{I: 1}}
copied := Copy(&arrayOfPointerStruct)
assert.NotSame(t, &arrayOfPointerStruct, copied)
assert.NotSame(t, arrayOfPointerStruct[0], copied.(*[3]*s)[0])
arrayOfPointerStruct[0].I = 999
if 1 != copied.(*[3]*s)[0].I {
t.Fatalf("fail to do deep copy")
}
},
},
}
for key, tt := range verifyCases {
t.Run(key, tt.modifyAndVerify)
}
}

// just basic is this working stuff
func TestSimple(t *testing.T) {
Strings := []string{"a", "b", "c"}
Expand Down
2 changes: 2 additions & 0 deletions go.mod
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
module github.com/xieyuschen/deepcopy

go 1.14

require github.com/stretchr/testify v1.7.5 // indirect
19 changes: 19 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.7.5 h1:s5PTfem8p8EbKQOctVV53k6jCJt3UX4IEJzwh+C324Q=
github.com/stretchr/testify v1.7.5/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk=
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=

0 comments on commit 0aa03ad

Please sign in to comment.