-
Notifications
You must be signed in to change notification settings - Fork 1
/
reflect_internal.go
117 lines (94 loc) · 2.28 KB
/
reflect_internal.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
package gg
import r "reflect"
const expectedStructNesting = 8
func cloneArray(src r.Value) {
if !(src.Cap() > 0) || !IsIndirect(src.Type().Elem()) {
return
}
for ind := range Iter(src.Len()) {
ValueClone(src.Index(ind))
}
}
func clonedArray(src r.Value) r.Value {
if !(src.Cap() > 0) || !IsIndirect(src.Type().Elem()) {
return src
}
out := NewElem(src.Type())
r.Copy(out, src)
cloneArray(out)
return out
}
/*
Known defect: when cloning, in addition to allocating a new backing array, this
allocates a slice header, which could theoretically be avoided if we could make
just a backing array of the required size and replace the array pointer in the
slice header we already have.
*/
func cloneSlice(src r.Value) { ValueSet(src, clonedSlice(src)) }
func clonedSlice(src r.Value) r.Value {
if src.IsNil() || !(src.Cap() > 0) {
return src
}
out := r.MakeSlice(src.Type(), src.Len(), src.Cap())
r.Copy(out, src)
cloneArray(out)
return out
}
func cloneInterface(src r.Value) { ValueSet(src, clonedInterface(src)) }
func clonedInterface(src r.Value) r.Value {
if src.IsNil() {
return src
}
elem0 := src.Elem()
elem1 := ValueCloned(elem0)
if elem0 == elem1 {
return elem0
}
return elem1.Convert(src.Type())
}
func cloneMap(src r.Value) { ValueSet(src, clonedMap(src)) }
func clonedMap(src r.Value) r.Value {
if src.IsNil() {
return src
}
out := r.MakeMapWithSize(src.Type(), src.Len())
iter := src.MapRange()
for iter.Next() {
out.SetMapIndex(ValueCloned(iter.Key()), ValueCloned(iter.Value()))
}
return out
}
func clonePointer(src r.Value) { ValueSet(src, clonedPointer(src)) }
func clonedPointer(src r.Value) r.Value {
if src.IsNil() {
return src
}
out := r.New(src.Type().Elem())
out.Elem().Set(src.Elem())
ValueClone(out.Elem())
return out
}
func cloneStruct(src r.Value) {
for _, field := range StructPublicFieldCache.Get(src.Type()) {
ValueClone(src.FieldByIndex(field.Index))
}
}
func clonedStruct(src r.Value) r.Value {
if !IsIndirect(src.Type()) {
return src
}
out := NewElem(src.Type())
out.Set(src)
cloneStruct(out)
return out
}
func growLenReflect(tar r.Value) {
len, cap := tar.Len(), tar.Cap()
if cap > len {
tar.SetLen(len + 1)
return
}
buf := r.MakeSlice(tar.Type(), len+1, MaxPrim(len*2, 4))
r.Copy(buf, tar)
tar.Set(buf)
}