github.com/goki/ki@v1.1.11/kit/maps.go (about) 1 // Copyright (c) 2018, The GoKi Authors. 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 kit 6 7 import ( 8 "fmt" 9 "log" 10 "reflect" 11 "sort" 12 "strings" 13 "time" 14 15 "github.com/goki/ki/floats" 16 "github.com/goki/ki/ints" 17 ) 18 19 // This file contains helpful functions for dealing with maps, in the reflect 20 // system 21 22 // MapValueType returns the type of the value for the given map (which can be 23 // a pointer to a map or a direct map) -- just Elem() of map type, but using 24 // this function makes it more explicit what is going on. 25 func MapValueType(mp interface{}) reflect.Type { 26 return NonPtrType(reflect.TypeOf(mp)).Elem() 27 } 28 29 // MapKeyType returns the type of the key for the given map (which can be a 30 // pointer to a map or a direct map) -- just Key() of map type, but using 31 // this function makes it more explicit what is going on. 32 func MapKeyType(mp interface{}) reflect.Type { 33 return NonPtrType(reflect.TypeOf(mp)).Key() 34 } 35 36 // MapElsValueFun calls a function on all the "basic" elements of given map -- 37 // iterates over maps within maps (but not structs, slices within maps). 38 func MapElsValueFun(mp interface{}, fun func(mp interface{}, typ reflect.Type, key, val reflect.Value) bool) bool { 39 vv := reflect.ValueOf(mp) 40 if mp == nil { 41 log.Printf("kit.MapElsValueFun: must pass a non-nil pointer to the map: %v\n", mp) 42 return false 43 } 44 v := NonPtrValue(vv) 45 if !v.IsValid() { 46 return true 47 } 48 typ := v.Type() 49 if typ.Kind() != reflect.Map { 50 log.Printf("kit.MapElsValueFun: non-pointer type is not a map: %v\n", typ.String()) 51 return false 52 } 53 rval := true 54 keys := v.MapKeys() 55 for _, key := range keys { 56 val := v.MapIndex(key) 57 vali := val.Interface() 58 // vt := val.Type() 59 vt := reflect.TypeOf(vali) 60 // fmt.Printf("key %v val %v kind: %v\n", key, val, vt.Kind()) 61 if vt.Kind() == reflect.Map { 62 rval = MapElsValueFun(vali, fun) 63 if !rval { 64 break 65 } 66 // } else if vt.Kind() == reflect.Struct { // todo 67 // rval = MapElsValueFun(vali, fun) 68 // if !rval { 69 // break 70 // } 71 } else { 72 rval = fun(vali, typ, key, val) 73 if !rval { 74 break 75 } 76 } 77 } 78 return rval 79 } 80 81 // MapElsN returns number of elemental fields in given map type 82 func MapElsN(mp interface{}) int { 83 n := 0 84 falseErr := MapElsValueFun(mp, func(mp interface{}, typ reflect.Type, key, val reflect.Value) bool { 85 n++ 86 return true 87 }) 88 if falseErr == false { 89 return 0 90 } 91 return n 92 } 93 94 // MapStructElsValueFun calls a function on all the "basic" elements of given 95 // map or struct -- iterates over maps within maps and fields within structs 96 func MapStructElsValueFun(mp interface{}, fun func(mp interface{}, typ reflect.Type, val reflect.Value) bool) bool { 97 vv := reflect.ValueOf(mp) 98 if mp == nil { 99 log.Printf("kit.MapElsValueFun: must pass a non-nil pointer to the map: %v\n", mp) 100 return false 101 } 102 v := NonPtrValue(vv) 103 if !v.IsValid() { 104 return true 105 } 106 typ := v.Type() 107 vk := typ.Kind() 108 rval := true 109 switch vk { 110 case reflect.Map: 111 keys := v.MapKeys() 112 for _, key := range keys { 113 val := v.MapIndex(key) 114 vali := val.Interface() 115 if IfaceIsNil(vali) { 116 continue 117 } 118 vt := reflect.TypeOf(vali) 119 if vt == nil { 120 continue 121 } 122 vtk := vt.Kind() 123 switch vtk { 124 case reflect.Map: 125 rval = MapStructElsValueFun(vali, fun) 126 if !rval { 127 break 128 } 129 case reflect.Struct: 130 rval = MapStructElsValueFun(vali, fun) 131 if !rval { 132 break 133 } 134 default: 135 rval = fun(vali, typ, val) 136 if !rval { 137 break 138 } 139 } 140 } 141 case reflect.Struct: 142 for i := 0; i < typ.NumField(); i++ { 143 f := typ.Field(i) 144 vf := v.Field(i) 145 if !vf.CanInterface() { 146 continue 147 } 148 vfi := vf.Interface() 149 if vfi == mp { 150 continue 151 } 152 vtk := f.Type.Kind() 153 switch vtk { 154 case reflect.Map: 155 rval = MapStructElsValueFun(vfi, fun) 156 if !rval { 157 break 158 } 159 case reflect.Struct: 160 rval = MapStructElsValueFun(vfi, fun) 161 if !rval { 162 break 163 } 164 default: 165 rval = fun(vfi, typ, vf) 166 if !rval { 167 break 168 } 169 } 170 } 171 default: 172 log.Printf("kit.MapStructElsValueFun: non-pointer type is not a map or struct: %v\n", typ.String()) 173 return false 174 } 175 return rval 176 } 177 178 // MapStructElsN returns number of elemental fields in given map / struct types 179 func MapStructElsN(mp interface{}) int { 180 n := 0 181 falseErr := MapStructElsValueFun(mp, func(mp interface{}, typ reflect.Type, val reflect.Value) bool { 182 n++ 183 return true 184 }) 185 if falseErr == false { 186 return 0 187 } 188 return n 189 } 190 191 // MapAdd adds a new blank entry to the map 192 func MapAdd(mv interface{}) { 193 mpv := reflect.ValueOf(mv) 194 mpvnp := NonPtrValue(mpv) 195 mvtyp := mpvnp.Type() 196 valtyp := MapValueType(mv) 197 if valtyp.Kind() == reflect.Interface && valtyp.String() == "interface {}" { 198 str := "" 199 valtyp = reflect.TypeOf(str) 200 } 201 nkey := reflect.New(MapKeyType(mv)) 202 nval := reflect.New(valtyp) 203 if mpvnp.IsNil() { // make a new map 204 nmp := MakeMap(mvtyp) 205 mpv.Elem().Set(nmp.Elem()) 206 mpvnp = NonPtrValue(mpv) 207 } 208 mpvnp.SetMapIndex(nkey.Elem(), nval.Elem()) 209 } 210 211 // MapDelete deletes a key-value from the map (set key to a zero value) 212 func MapDelete(mv interface{}, key interface{}) { 213 mpv := reflect.ValueOf(mv) 214 mpvnp := NonPtrValue(mpv) 215 mpvnp.SetMapIndex(reflect.ValueOf(key), reflect.Value{}) // delete 216 } 217 218 // MapDeleteValue deletes a key-value from the map (set key to a zero value) 219 // -- key is already a reflect.Value 220 func MapDeleteValue(mv interface{}, key reflect.Value) { 221 mpv := reflect.ValueOf(mv) 222 mpvnp := NonPtrValue(mpv) 223 mpvnp.SetMapIndex(key, reflect.Value{}) // delete 224 } 225 226 // MapSort sorts keys of map either by key or by value, returns those keys as 227 // a slice of reflect.Value, as returned by reflect.Value.MapKeys() method 228 func MapSort(mp interface{}, byKey, ascending bool) []reflect.Value { 229 mpv := reflect.ValueOf(mp) 230 mpvnp := NonPtrValue(mpv) 231 keys := mpvnp.MapKeys() // note: this is a slice of reflect.Value! 232 if byKey { 233 ValueSliceSort(keys, ascending) 234 } else { 235 MapValueSort(mpvnp, keys, ascending) 236 } 237 return keys 238 } 239 240 // MapValueSort sorts keys of map by values 241 func MapValueSort(mpvnp reflect.Value, keys []reflect.Value, ascending bool) error { 242 if len(keys) == 0 { 243 return nil 244 } 245 keyval := keys[0] 246 felval := mpvnp.MapIndex(keyval) 247 eltyp := felval.Type() 248 elnptyp := NonPtrType(eltyp) 249 vk := elnptyp.Kind() 250 elval := OnePtrValue(felval) 251 elif := elval.Interface() 252 253 switch elif.(type) { 254 case floats.Floater: 255 sort.Slice(keys, func(i, j int) bool { 256 iv := NonPtrValue(mpvnp.MapIndex(keys[i])).Interface().(floats.Floater).Float() 257 jv := NonPtrValue(mpvnp.MapIndex(keys[j])).Interface().(floats.Floater).Float() 258 if ascending { 259 return iv < jv 260 } 261 return iv > jv 262 }) 263 return nil 264 case ints.Inter: 265 sort.Slice(keys, func(i, j int) bool { 266 iv := NonPtrValue(mpvnp.MapIndex(keys[i])).Interface().(ints.Inter).Int() 267 jv := NonPtrValue(mpvnp.MapIndex(keys[j])).Interface().(ints.Inter).Int() 268 if ascending { 269 return iv < jv 270 } 271 return iv > jv 272 }) 273 return nil 274 } 275 276 // try all the numeric types first! 277 278 switch { 279 case vk >= reflect.Int && vk <= reflect.Int64: 280 sort.Slice(keys, func(i, j int) bool { 281 iv := NonPtrValue(mpvnp.MapIndex(keys[i])).Int() 282 jv := NonPtrValue(mpvnp.MapIndex(keys[j])).Int() 283 if ascending { 284 return iv < jv 285 } 286 return iv > jv 287 }) 288 return nil 289 case vk >= reflect.Uint && vk <= reflect.Uint64: 290 sort.Slice(keys, func(i, j int) bool { 291 iv := NonPtrValue(mpvnp.MapIndex(keys[i])).Uint() 292 jv := NonPtrValue(mpvnp.MapIndex(keys[j])).Uint() 293 if ascending { 294 return iv < jv 295 } 296 return iv > jv 297 }) 298 return nil 299 case vk >= reflect.Float32 && vk <= reflect.Float64: 300 sort.Slice(keys, func(i, j int) bool { 301 iv := NonPtrValue(mpvnp.MapIndex(keys[i])).Float() 302 jv := NonPtrValue(mpvnp.MapIndex(keys[j])).Float() 303 if ascending { 304 return iv < jv 305 } 306 return iv > jv 307 }) 308 return nil 309 case vk == reflect.Struct && ShortTypeName(elnptyp) == "time.Time": 310 sort.Slice(keys, func(i, j int) bool { 311 iv := NonPtrValue(mpvnp.MapIndex(keys[i])).Interface().(time.Time) 312 jv := NonPtrValue(mpvnp.MapIndex(keys[j])).Interface().(time.Time) 313 if ascending { 314 return iv.Before(jv) 315 } 316 return jv.Before(iv) 317 }) 318 } 319 320 // this stringer case will likely pick up most of the rest 321 switch elif.(type) { 322 case fmt.Stringer: 323 sort.Slice(keys, func(i, j int) bool { 324 iv := NonPtrValue(mpvnp.MapIndex(keys[i])).Interface().(fmt.Stringer).String() 325 jv := NonPtrValue(mpvnp.MapIndex(keys[j])).Interface().(fmt.Stringer).String() 326 if ascending { 327 return iv < jv 328 } 329 return iv > jv 330 }) 331 return nil 332 } 333 334 // last resort! 335 switch { 336 case vk == reflect.String: 337 sort.Slice(keys, func(i, j int) bool { 338 iv := NonPtrValue(mpvnp.MapIndex(keys[i])).String() 339 jv := NonPtrValue(mpvnp.MapIndex(keys[j])).String() 340 if ascending { 341 return strings.ToLower(iv) < strings.ToLower(jv) 342 } 343 return strings.ToLower(iv) > strings.ToLower(jv) 344 }) 345 return nil 346 } 347 348 err := fmt.Errorf("MapValueSort: unable to sort elements of type: %v", eltyp.String()) 349 log.Println(err) 350 return err 351 }