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