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