goki.dev/laser@v0.1.34/maps.go (about)

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