github.com/searKing/golang/go@v1.2.74/reflect/value.go (about) 1 // Copyright 2020 The searKing Author. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 package reflect 6 7 import ( 8 "bytes" 9 "fmt" 10 "reflect" 11 12 bytes_ "github.com/searKing/golang/go/bytes" 13 "github.com/searKing/golang/go/container/traversal" 14 ) 15 16 const PtrSize = 4 << (^uintptr(0) >> 63) // unsafe.Sizeof(uintptr(0)) but an ideal const, sizeof *void 17 18 func IsEmptyValue(v reflect.Value) bool { 19 switch v.Kind() { 20 case reflect.Array, reflect.Map, reflect.Slice, reflect.String: 21 return v.Len() == 0 22 case reflect.Bool: 23 return !v.Bool() 24 case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: 25 return v.Int() == 0 26 case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: 27 return v.Uint() == 0 28 case reflect.Float32, reflect.Float64: 29 return v.Float() == 0 30 case reflect.Interface, reflect.Ptr: 31 return v.IsNil() 32 } 33 return reflect.DeepEqual(v.Interface(), reflect.Zero(v.Type()).Interface()) 34 } 35 36 // cmd/compile/internal/gc/dump.go 37 func IsZeroValue(v reflect.Value) bool { 38 if !v.IsValid() { 39 return true 40 } 41 42 switch v.Kind() { 43 case reflect.Bool: 44 return !v.Bool() 45 case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: 46 return v.Int() == 0 47 case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: 48 return v.Uint() == 0 49 case reflect.Float32, reflect.Float64: 50 return v.Float() == 0 51 case reflect.Complex64, reflect.Complex128: 52 return v.Complex() == 0 53 case reflect.String: 54 return v.String() == "" 55 case reflect.UnsafePointer: 56 return v.Pointer() == 0 57 case reflect.Array, reflect.Chan, reflect.Map, reflect.Slice: 58 return v.Len() == 0 59 case reflect.Func: 60 return v.IsNil() 61 case reflect.Interface, reflect.Ptr: 62 if v.IsNil() { 63 return true 64 } 65 break 66 case reflect.Struct: 67 break 68 default: 69 } 70 71 return reflect.DeepEqual(v.Interface(), reflect.Zero(v.Type()).Interface()) 72 } 73 74 func IsNilValue(v reflect.Value) (result bool) { 75 if !v.IsValid() { 76 return true 77 } 78 switch v.Kind() { 79 case reflect.Chan, reflect.Func, reflect.Interface, reflect.Map, reflect.Ptr, reflect.Slice: 80 return v.IsNil() 81 } 82 return 83 } 84 85 func FollowValuePointer(v reflect.Value) reflect.Value { 86 v = reflect.Indirect(v) 87 if v.Kind() == reflect.Ptr { 88 return FollowValuePointer(v) 89 } 90 return v 91 } 92 93 // A field represents a single field found in a struct. 94 type FieldValueInfo struct { 95 value reflect.Value 96 structField reflect.StructField 97 index []int 98 } 99 100 func (info FieldValueInfo) MiddleNodes() []interface{} { 101 102 if !info.value.IsValid() { 103 return nil 104 } 105 if IsNilType(info.value.Type()) { 106 return nil 107 } 108 val := FollowValuePointer(info.value) 109 if val.Kind() != reflect.Struct { 110 return nil 111 } 112 113 var middles []interface{} 114 // Scan typ for fields to include. 115 for i := 0; i < val.NumField(); i++ { 116 index := make([]int, len(info.index)+1) 117 copy(index, info.index) 118 index[len(info.index)] = i 119 middles = append(middles, FieldValueInfo{ 120 value: val.Field(i), 121 structField: val.Type().Field(i), 122 index: index, 123 }) 124 } 125 return middles 126 } 127 func (info FieldValueInfo) Depth() int { 128 return len(info.index) 129 } 130 131 func (info FieldValueInfo) Value() reflect.Value { 132 return info.value 133 } 134 135 func (info FieldValueInfo) StructField() (reflect.StructField, bool) { 136 if IsEmptyValue(reflect.ValueOf(info.structField)) { 137 return info.structField, false 138 } 139 return info.structField, true 140 } 141 142 func (info FieldValueInfo) Index() []int { 143 return info.index 144 } 145 146 func (info *FieldValueInfo) String() string { 147 //if IsNilValue(info.value) { 148 // return fmt.Sprintf("%+v", nil) 149 //} 150 //info.value.String() 151 //return fmt.Sprintf("%+v %+v", info.value.Type().String(), info.value) 152 153 switch k := info.value.Kind(); k { 154 case reflect.Invalid: 155 return "<invalid value>" 156 case reflect.String: 157 return "[string: " + info.value.String() + "]" 158 } 159 // If you call String on a reflect.value of other type, it's better to 160 // print something than to panic. Useful in debugging. 161 return "[" + info.value.Type().String() + ":" + func() string { 162 if info.value.CanInterface() && info.value.Interface() == nil { 163 return "<nil value>" 164 } 165 return fmt.Sprintf(" %+v", info.value) 166 }() + "]" 167 } 168 169 type FieldValueInfoHandler interface { 170 Handler(info FieldValueInfo) (goon bool) 171 } 172 type FieldValueInfoHandlerFunc func(info FieldValueInfo) (goon bool) 173 174 func (f FieldValueInfoHandlerFunc) Handler(info FieldValueInfo) (goon bool) { 175 return f(info) 176 } 177 178 func WalkValueDFS(val reflect.Value, handler FieldValueInfoHandler) { 179 traversal.DepthFirstSearchOrder(FieldValueInfo{ 180 value: val, 181 }, traversal.HandlerFunc(func(node interface{}, depth int) (goon bool) { 182 return handler.Handler(node.(FieldValueInfo)) 183 })) 184 } 185 186 func WalkValueBFS(val reflect.Value, handler FieldValueInfoHandler) { 187 traversal.BreadthFirstSearchOrder(FieldValueInfo{ 188 value: val, 189 }, traversal.HandlerFunc(func(node interface{}, depth int) (goon bool) { 190 return handler.Handler(node.(FieldValueInfo)) 191 })) 192 } 193 194 func DumpValueInfoDFS(v reflect.Value) string { 195 dumpInfo := &bytes.Buffer{} 196 first := true 197 WalkValueDFS(v, FieldValueInfoHandlerFunc(func(info FieldValueInfo) (goon bool) { 198 if first { 199 first = false 200 bytes_.NewIndent(dumpInfo, "", "\t", info.Depth()) 201 } else { 202 bytes_.NewLine(dumpInfo, "", "\t", info.Depth()) 203 } 204 dumpInfo.WriteString(fmt.Sprintf("%+v", info.String())) 205 return true 206 })) 207 return dumpInfo.String() 208 } 209 210 func DumpValueInfoBFS(v reflect.Value) string { 211 dumpInfo := &bytes.Buffer{} 212 first := true 213 WalkValueBFS(v, FieldValueInfoHandlerFunc(func(info FieldValueInfo) (goon bool) { 214 if first { 215 first = false 216 bytes_.NewIndent(dumpInfo, "", "\t", info.Depth()) 217 } else { 218 bytes_.NewLine(dumpInfo, "", "\t", info.Depth()) 219 } 220 dumpInfo.WriteString(fmt.Sprintf("%+v", info.String())) 221 return true 222 })) 223 return dumpInfo.String() 224 }