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  }