github.com/jxskiss/gopkg@v0.17.3/gemap/utils.go (about)

     1  package gemap
     2  
     3  import (
     4  	"fmt"
     5  	"github.com/jxskiss/gopkg/internal"
     6  	"github.com/jxskiss/gopkg/internal/linkname"
     7  	"reflect"
     8  )
     9  
    10  // Keys is reserved for a generic implementation.
    11  
    12  // Values is reserved for a generic implementation.
    13  
    14  // MapKeys returns a slice containing all the keys present in the map,
    15  // in unspecified order.
    16  // It panics if m's kind is not reflect.Map.
    17  // It returns an emtpy slice if m is a nil map.
    18  func MapKeys(m interface{}) (keys interface{}) {
    19  	mTyp := reflect.TypeOf(m)
    20  	if mTyp.Kind() != reflect.Map {
    21  		panic(invalidType("MapKeys", "map", m))
    22  	}
    23  
    24  	mVal := reflect.ValueOf(m)
    25  	keyTyp := mTyp.Key()
    26  	keySliceTyp := reflect.SliceOf(keyTyp)
    27  	length := mVal.Len()
    28  	keysVal := reflect.MakeSlice(keySliceTyp, 0, length)
    29  	for _, kVal := range mVal.MapKeys() {
    30  		keysVal = reflect.Append(keysVal, kVal)
    31  	}
    32  	return keysVal.Interface()
    33  }
    34  
    35  // MapValues returns a slice containing all the values present in the map,
    36  // in unspecified order.
    37  // It panics if m's kind is not reflect.Map.
    38  // It returns an empty slice if m is a nil map.
    39  func MapValues(m interface{}) (values interface{}) {
    40  	mTyp := reflect.TypeOf(m)
    41  	if mTyp.Kind() != reflect.Map {
    42  		panic(invalidType("MapValues", "map", m))
    43  	}
    44  
    45  	mVal := reflect.ValueOf(m)
    46  	elemTyp := mTyp.Elem()
    47  	elemSliceTyp := reflect.SliceOf(elemTyp)
    48  	length := mVal.Len()
    49  	valuesVal := reflect.MakeSlice(elemSliceTyp, 0, length)
    50  	for iter := mVal.MapRange(); iter.Next(); {
    51  		valuesVal = reflect.Append(valuesVal, iter.Value())
    52  	}
    53  	return valuesVal.Interface()
    54  }
    55  
    56  // IntKeys returns a int64 slice containing all the keys present in the map,
    57  // in unspecified order.
    58  // It panics if m's kind is not reflect.Map or the key's type is not integer.
    59  // It returns an empty slice if m is a nil map.
    60  func IntKeys(m interface{}) (keys []int64) {
    61  	mTyp := reflect.TypeOf(m)
    62  	if mTyp.Kind() != reflect.Map || !isIntType(mTyp.Key().Kind()) {
    63  		panic(invalidType("IntKeys", "map with integer keys", m))
    64  	}
    65  
    66  	eface := internal.EFaceOf(&m)
    67  	length := linkname.Reflect_maplen(eface.Word)
    68  	keyKind := mTyp.Key().Kind()
    69  	iter := linkname.Reflect_mapiterinit(eface.RType, eface.Word)
    70  	keys = make([]int64, 0, length)
    71  	for i := 0; i < length; i++ {
    72  		keyptr := linkname.Reflect_mapiterkey(iter)
    73  		if keyptr == nil {
    74  			break
    75  		}
    76  		keys = append(keys, internal.CastIntPointer(keyKind, keyptr))
    77  		linkname.Reflect_mapiternext(iter)
    78  	}
    79  	return keys
    80  }
    81  
    82  // IntValues returns a int64 slice containing all the values present in the map,
    83  // in unspecified order.
    84  // It panics if m's kind is not reflect.Map or the value's type is not integer.
    85  // It returns an empty slice if m is a nil map.
    86  func IntValues(m interface{}) (values []int64) {
    87  	mTyp := reflect.TypeOf(m)
    88  	if mTyp.Kind() != reflect.Map || !isIntType(mTyp.Elem().Kind()) {
    89  		panic(invalidType("IntValues", "map with integer values", m))
    90  	}
    91  
    92  	eface := internal.EFaceOf(&m)
    93  	length := linkname.Reflect_maplen(eface.Word)
    94  	elemKind := mTyp.Elem().Kind()
    95  	iter := linkname.Reflect_mapiterinit(eface.RType, eface.Word)
    96  	values = make([]int64, 0, length)
    97  	for i := 0; i < length; i++ {
    98  		keyptr := linkname.Reflect_mapiterkey(iter)
    99  		if keyptr == nil {
   100  			break
   101  		}
   102  		elemptr := linkname.Reflect_mapiterelem(iter)
   103  		values = append(values, internal.CastIntPointer(elemKind, elemptr))
   104  		linkname.Reflect_mapiternext(iter)
   105  	}
   106  	return values
   107  }
   108  
   109  // StringKeys returns a string slice containing all the keys present
   110  // in the map, in unspecified order.
   111  // It panics if m's kind is not reflect.Map or the key's kind is not string.
   112  // It returns an empty slice if m is a nil map.
   113  func StringKeys(m interface{}) (keys []string) {
   114  	mTyp := reflect.TypeOf(m)
   115  	if mTyp.Kind() != reflect.Map || mTyp.Key().Kind() != reflect.String {
   116  		panic(invalidType("StringKeys", "map with string keys", m))
   117  	}
   118  
   119  	eface := internal.EFaceOf(&m)
   120  	length := linkname.Reflect_maplen(eface.Word)
   121  	iter := linkname.Reflect_mapiterinit(eface.RType, eface.Word)
   122  	keys = make([]string, 0, length)
   123  	for i := 0; i < length; i++ {
   124  		keyptr := linkname.Reflect_mapiterkey(iter)
   125  		if keyptr == nil {
   126  			break
   127  		}
   128  		keys = append(keys, *(*string)(keyptr))
   129  		linkname.Reflect_mapiternext(iter)
   130  	}
   131  	return keys
   132  }
   133  
   134  // StringValues returns a string slice containing all the values present
   135  // in the map, in unspecified order.
   136  // It panics if m's kind is not reflect.Map or the value's kind is not string.
   137  // It returns an empty slice if m is a nil map.
   138  func StringValues(m interface{}) (values []string) {
   139  	mTyp := reflect.TypeOf(m)
   140  	if mTyp.Kind() != reflect.Map || mTyp.Elem().Kind() != reflect.String {
   141  		panic(invalidType("StringValues", "map with string values", m))
   142  	}
   143  
   144  	eface := internal.EFaceOf(&m)
   145  	length := linkname.Reflect_maplen(eface.Word)
   146  	iter := linkname.Reflect_mapiterinit(eface.RType, eface.Word)
   147  	values = make([]string, 0, length)
   148  	for i := 0; i < length; i++ {
   149  		keyptr := linkname.Reflect_mapiterkey(iter)
   150  		if keyptr == nil {
   151  			break
   152  		}
   153  		elemptr := linkname.Reflect_mapiterelem(iter)
   154  		values = append(values, *(*string)(elemptr))
   155  		linkname.Reflect_mapiternext(iter)
   156  	}
   157  	return values
   158  }
   159  
   160  // Merge and is reserved for a generic implementation.
   161  
   162  // MergeTo is reserved for a generic implementation.
   163  
   164  // MergeMaps returns a new map containing all key values present in maps.
   165  // It panics if given zero param.
   166  // It panics if given param which is not a map, or different map types.
   167  // It returns an empty map if all params are nil or empty.
   168  func MergeMaps(maps ...interface{}) interface{} {
   169  	if len(maps) == 0 {
   170  		panic(invalidParam("MergeMaps", "maps"))
   171  	}
   172  	var dstTyp reflect.Type
   173  	var length int
   174  	for _, m := range maps {
   175  		if m == nil {
   176  			continue
   177  		}
   178  		mTyp := reflect.TypeOf(m)
   179  		if mTyp.Kind() != reflect.Map {
   180  			panic(invalidType("MergeMaps", "map", m))
   181  		}
   182  		if dstTyp == nil {
   183  			dstTyp = mTyp
   184  			continue
   185  		}
   186  		if mTyp != dstTyp {
   187  			panic(invalidType("MergeMaps", dstTyp.String(), m))
   188  		}
   189  		eface := internal.EFaceOf(&m)
   190  		length += linkname.Reflect_maplen(eface.Word)
   191  	}
   192  	dstMap := reflect.MakeMapWithSize(dstTyp, length).Interface()
   193  	return mergeMapsTo(dstMap, maps...)
   194  }
   195  
   196  // MergeMapsTo adds key values present in others to the dst map.
   197  // It panics if dst is nil or not a map, or any param in others is not a map,
   198  // or they are different map types.
   199  // If dst is a nil map, it creates a new map and returns it.
   200  func MergeMapsTo(dst interface{}, others ...interface{}) interface{} {
   201  	dstTyp := reflect.TypeOf(dst)
   202  	if dstTyp.Kind() != reflect.Map {
   203  		panic(invalidType("MergeMapsTo", "map", dst))
   204  	}
   205  	for _, m := range others {
   206  		if m == nil {
   207  			continue
   208  		}
   209  		if reflect.TypeOf(m) != dstTyp {
   210  			panic(invalidType("MergeMapsTo", dstTyp.String(), m))
   211  		}
   212  	}
   213  	return mergeMapsTo(dst, others...)
   214  }
   215  
   216  func mergeMapsTo(dst interface{}, others ...interface{}) interface{} {
   217  	dstVal := reflect.ValueOf(dst)
   218  	if dstVal.IsNil() {
   219  		dstTyp := reflect.TypeOf(dst)
   220  		dstVal = reflect.MakeMap(dstTyp)
   221  	}
   222  	for _, m := range others {
   223  		if m == nil {
   224  			continue
   225  		}
   226  		mVal := reflect.ValueOf(m)
   227  		for iter := mVal.MapRange(); iter.Next(); {
   228  			dstVal.SetMapIndex(iter.Key(), iter.Value())
   229  		}
   230  	}
   231  	return dstVal.Interface()
   232  }
   233  
   234  func invalidType(where string, want string, got interface{}) string {
   235  	const invalidType = "%s: invalid type, want %s, got %T"
   236  	return fmt.Sprintf(invalidType, where, want, got)
   237  }
   238  
   239  func invalidParam(where string, name string) string {
   240  	const invalidParam = "%s: invalid param %s"
   241  	return fmt.Sprintf(invalidParam, where, name)
   242  }
   243  
   244  func isIntType(kind reflect.Kind) bool {
   245  	switch kind {
   246  	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64,
   247  		reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
   248  		return true
   249  	}
   250  	return false
   251  }