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  }