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  }