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 }