github.com/wangyougui/gf/v2@v2.6.5/container/gmap/gmap_hash_str_any_map.go (about) 1 // Copyright GoFrame Author(https://goframe.org). All Rights Reserved. 2 // 3 // This Source Code Form is subject to the terms of the MIT License. 4 // If a copy of the MIT was not distributed with gm file, 5 // You can obtain one at https://github.com/wangyougui/gf. 6 // 7 8 package gmap 9 10 import ( 11 "reflect" 12 13 "github.com/wangyougui/gf/v2/container/gvar" 14 "github.com/wangyougui/gf/v2/internal/deepcopy" 15 "github.com/wangyougui/gf/v2/internal/empty" 16 "github.com/wangyougui/gf/v2/internal/json" 17 "github.com/wangyougui/gf/v2/internal/rwmutex" 18 "github.com/wangyougui/gf/v2/util/gconv" 19 ) 20 21 // StrAnyMap implements map[string]interface{} with RWMutex that has switch. 22 type StrAnyMap struct { 23 mu rwmutex.RWMutex 24 data map[string]interface{} 25 } 26 27 // NewStrAnyMap returns an empty StrAnyMap object. 28 // The parameter `safe` is used to specify whether using map in concurrent-safety, 29 // which is false in default. 30 func NewStrAnyMap(safe ...bool) *StrAnyMap { 31 return &StrAnyMap{ 32 mu: rwmutex.Create(safe...), 33 data: make(map[string]interface{}), 34 } 35 } 36 37 // NewStrAnyMapFrom creates and returns a hash map from given map `data`. 38 // Note that, the param `data` map will be set as the underlying data map(no deep copy), 39 // there might be some concurrent-safe issues when changing the map outside. 40 func NewStrAnyMapFrom(data map[string]interface{}, safe ...bool) *StrAnyMap { 41 return &StrAnyMap{ 42 mu: rwmutex.Create(safe...), 43 data: data, 44 } 45 } 46 47 // Iterator iterates the hash map readonly with custom callback function `f`. 48 // If `f` returns true, then it continues iterating; or false to stop. 49 func (m *StrAnyMap) Iterator(f func(k string, v interface{}) bool) { 50 m.mu.RLock() 51 defer m.mu.RUnlock() 52 for k, v := range m.data { 53 if !f(k, v) { 54 break 55 } 56 } 57 } 58 59 // Clone returns a new hash map with copy of current map data. 60 func (m *StrAnyMap) Clone() *StrAnyMap { 61 return NewStrAnyMapFrom(m.MapCopy(), m.mu.IsSafe()) 62 } 63 64 // Map returns the underlying data map. 65 // Note that, if it's in concurrent-safe usage, it returns a copy of underlying data, 66 // or else a pointer to the underlying data. 67 func (m *StrAnyMap) Map() map[string]interface{} { 68 m.mu.RLock() 69 defer m.mu.RUnlock() 70 if !m.mu.IsSafe() { 71 return m.data 72 } 73 data := make(map[string]interface{}, len(m.data)) 74 for k, v := range m.data { 75 data[k] = v 76 } 77 return data 78 } 79 80 // MapStrAny returns a copy of the underlying data of the map as map[string]interface{}. 81 func (m *StrAnyMap) MapStrAny() map[string]interface{} { 82 return m.Map() 83 } 84 85 // MapCopy returns a copy of the underlying data of the hash map. 86 func (m *StrAnyMap) MapCopy() map[string]interface{} { 87 m.mu.RLock() 88 defer m.mu.RUnlock() 89 data := make(map[string]interface{}, len(m.data)) 90 for k, v := range m.data { 91 data[k] = v 92 } 93 return data 94 } 95 96 // FilterEmpty deletes all key-value pair of which the value is empty. 97 // Values like: 0, nil, false, "", len(slice/map/chan) == 0 are considered empty. 98 func (m *StrAnyMap) FilterEmpty() { 99 m.mu.Lock() 100 for k, v := range m.data { 101 if empty.IsEmpty(v) { 102 delete(m.data, k) 103 } 104 } 105 m.mu.Unlock() 106 } 107 108 // FilterNil deletes all key-value pair of which the value is nil. 109 func (m *StrAnyMap) FilterNil() { 110 m.mu.Lock() 111 defer m.mu.Unlock() 112 for k, v := range m.data { 113 if empty.IsNil(v) { 114 delete(m.data, k) 115 } 116 } 117 } 118 119 // Set sets key-value to the hash map. 120 func (m *StrAnyMap) Set(key string, val interface{}) { 121 m.mu.Lock() 122 if m.data == nil { 123 m.data = make(map[string]interface{}) 124 } 125 m.data[key] = val 126 m.mu.Unlock() 127 } 128 129 // Sets batch sets key-values to the hash map. 130 func (m *StrAnyMap) Sets(data map[string]interface{}) { 131 m.mu.Lock() 132 if m.data == nil { 133 m.data = data 134 } else { 135 for k, v := range data { 136 m.data[k] = v 137 } 138 } 139 m.mu.Unlock() 140 } 141 142 // Search searches the map with given `key`. 143 // Second return parameter `found` is true if key was found, otherwise false. 144 func (m *StrAnyMap) Search(key string) (value interface{}, found bool) { 145 m.mu.RLock() 146 if m.data != nil { 147 value, found = m.data[key] 148 } 149 m.mu.RUnlock() 150 return 151 } 152 153 // Get returns the value by given `key`. 154 func (m *StrAnyMap) Get(key string) (value interface{}) { 155 m.mu.RLock() 156 if m.data != nil { 157 value = m.data[key] 158 } 159 m.mu.RUnlock() 160 return 161 } 162 163 // Pop retrieves and deletes an item from the map. 164 func (m *StrAnyMap) Pop() (key string, value interface{}) { 165 m.mu.Lock() 166 defer m.mu.Unlock() 167 for key, value = range m.data { 168 delete(m.data, key) 169 return 170 } 171 return 172 } 173 174 // Pops retrieves and deletes `size` items from the map. 175 // It returns all items if size == -1. 176 func (m *StrAnyMap) Pops(size int) map[string]interface{} { 177 m.mu.Lock() 178 defer m.mu.Unlock() 179 if size > len(m.data) || size == -1 { 180 size = len(m.data) 181 } 182 if size == 0 { 183 return nil 184 } 185 var ( 186 index = 0 187 newMap = make(map[string]interface{}, size) 188 ) 189 for k, v := range m.data { 190 delete(m.data, k) 191 newMap[k] = v 192 index++ 193 if index == size { 194 break 195 } 196 } 197 return newMap 198 } 199 200 // doSetWithLockCheck checks whether value of the key exists with mutex.Lock, 201 // if not exists, set value to the map with given `key`, 202 // or else just return the existing value. 203 // 204 // When setting value, if `value` is type of `func() interface {}`, 205 // it will be executed with mutex.Lock of the hash map, 206 // and its return value will be set to the map with `key`. 207 // 208 // It returns value with given `key`. 209 func (m *StrAnyMap) doSetWithLockCheck(key string, value interface{}) interface{} { 210 m.mu.Lock() 211 defer m.mu.Unlock() 212 if m.data == nil { 213 m.data = make(map[string]interface{}) 214 } 215 if v, ok := m.data[key]; ok { 216 return v 217 } 218 if f, ok := value.(func() interface{}); ok { 219 value = f() 220 } 221 if value != nil { 222 m.data[key] = value 223 } 224 return value 225 } 226 227 // GetOrSet returns the value by key, 228 // or sets value with given `value` if it does not exist and then returns this value. 229 func (m *StrAnyMap) GetOrSet(key string, value interface{}) interface{} { 230 if v, ok := m.Search(key); !ok { 231 return m.doSetWithLockCheck(key, value) 232 } else { 233 return v 234 } 235 } 236 237 // GetOrSetFunc returns the value by key, 238 // or sets value with returned value of callback function `f` if it does not exist 239 // and then returns this value. 240 func (m *StrAnyMap) GetOrSetFunc(key string, f func() interface{}) interface{} { 241 if v, ok := m.Search(key); !ok { 242 return m.doSetWithLockCheck(key, f()) 243 } else { 244 return v 245 } 246 } 247 248 // GetOrSetFuncLock returns the value by key, 249 // or sets value with returned value of callback function `f` if it does not exist 250 // and then returns this value. 251 // 252 // GetOrSetFuncLock differs with GetOrSetFunc function is that it executes function `f` 253 // with mutex.Lock of the hash map. 254 func (m *StrAnyMap) GetOrSetFuncLock(key string, f func() interface{}) interface{} { 255 if v, ok := m.Search(key); !ok { 256 return m.doSetWithLockCheck(key, f) 257 } else { 258 return v 259 } 260 } 261 262 // GetVar returns a Var with the value by given `key`. 263 // The returned Var is un-concurrent safe. 264 func (m *StrAnyMap) GetVar(key string) *gvar.Var { 265 return gvar.New(m.Get(key)) 266 } 267 268 // GetVarOrSet returns a Var with result from GetVarOrSet. 269 // The returned Var is un-concurrent safe. 270 func (m *StrAnyMap) GetVarOrSet(key string, value interface{}) *gvar.Var { 271 return gvar.New(m.GetOrSet(key, value)) 272 } 273 274 // GetVarOrSetFunc returns a Var with result from GetOrSetFunc. 275 // The returned Var is un-concurrent safe. 276 func (m *StrAnyMap) GetVarOrSetFunc(key string, f func() interface{}) *gvar.Var { 277 return gvar.New(m.GetOrSetFunc(key, f)) 278 } 279 280 // GetVarOrSetFuncLock returns a Var with result from GetOrSetFuncLock. 281 // The returned Var is un-concurrent safe. 282 func (m *StrAnyMap) GetVarOrSetFuncLock(key string, f func() interface{}) *gvar.Var { 283 return gvar.New(m.GetOrSetFuncLock(key, f)) 284 } 285 286 // SetIfNotExist sets `value` to the map if the `key` does not exist, and then returns true. 287 // It returns false if `key` exists, and `value` would be ignored. 288 func (m *StrAnyMap) SetIfNotExist(key string, value interface{}) bool { 289 if !m.Contains(key) { 290 m.doSetWithLockCheck(key, value) 291 return true 292 } 293 return false 294 } 295 296 // SetIfNotExistFunc sets value with return value of callback function `f`, and then returns true. 297 // It returns false if `key` exists, and `value` would be ignored. 298 func (m *StrAnyMap) SetIfNotExistFunc(key string, f func() interface{}) bool { 299 if !m.Contains(key) { 300 m.doSetWithLockCheck(key, f()) 301 return true 302 } 303 return false 304 } 305 306 // SetIfNotExistFuncLock sets value with return value of callback function `f`, and then returns true. 307 // It returns false if `key` exists, and `value` would be ignored. 308 // 309 // SetIfNotExistFuncLock differs with SetIfNotExistFunc function is that 310 // it executes function `f` with mutex.Lock of the hash map. 311 func (m *StrAnyMap) SetIfNotExistFuncLock(key string, f func() interface{}) bool { 312 if !m.Contains(key) { 313 m.doSetWithLockCheck(key, f) 314 return true 315 } 316 return false 317 } 318 319 // Removes batch deletes values of the map by keys. 320 func (m *StrAnyMap) Removes(keys []string) { 321 m.mu.Lock() 322 if m.data != nil { 323 for _, key := range keys { 324 delete(m.data, key) 325 } 326 } 327 m.mu.Unlock() 328 } 329 330 // Remove deletes value from map by given `key`, and return this deleted value. 331 func (m *StrAnyMap) Remove(key string) (value interface{}) { 332 m.mu.Lock() 333 if m.data != nil { 334 var ok bool 335 if value, ok = m.data[key]; ok { 336 delete(m.data, key) 337 } 338 } 339 m.mu.Unlock() 340 return 341 } 342 343 // Keys returns all keys of the map as a slice. 344 func (m *StrAnyMap) Keys() []string { 345 m.mu.RLock() 346 var ( 347 keys = make([]string, len(m.data)) 348 index = 0 349 ) 350 for key := range m.data { 351 keys[index] = key 352 index++ 353 } 354 m.mu.RUnlock() 355 return keys 356 } 357 358 // Values returns all values of the map as a slice. 359 func (m *StrAnyMap) Values() []interface{} { 360 m.mu.RLock() 361 var ( 362 values = make([]interface{}, len(m.data)) 363 index = 0 364 ) 365 for _, value := range m.data { 366 values[index] = value 367 index++ 368 } 369 m.mu.RUnlock() 370 return values 371 } 372 373 // Contains checks whether a key exists. 374 // It returns true if the `key` exists, or else false. 375 func (m *StrAnyMap) Contains(key string) bool { 376 var ok bool 377 m.mu.RLock() 378 if m.data != nil { 379 _, ok = m.data[key] 380 } 381 m.mu.RUnlock() 382 return ok 383 } 384 385 // Size returns the size of the map. 386 func (m *StrAnyMap) Size() int { 387 m.mu.RLock() 388 length := len(m.data) 389 m.mu.RUnlock() 390 return length 391 } 392 393 // IsEmpty checks whether the map is empty. 394 // It returns true if map is empty, or else false. 395 func (m *StrAnyMap) IsEmpty() bool { 396 return m.Size() == 0 397 } 398 399 // Clear deletes all data of the map, it will remake a new underlying data map. 400 func (m *StrAnyMap) Clear() { 401 m.mu.Lock() 402 m.data = make(map[string]interface{}) 403 m.mu.Unlock() 404 } 405 406 // Replace the data of the map with given `data`. 407 func (m *StrAnyMap) Replace(data map[string]interface{}) { 408 m.mu.Lock() 409 m.data = data 410 m.mu.Unlock() 411 } 412 413 // LockFunc locks writing with given callback function `f` within RWMutex.Lock. 414 func (m *StrAnyMap) LockFunc(f func(m map[string]interface{})) { 415 m.mu.Lock() 416 defer m.mu.Unlock() 417 f(m.data) 418 } 419 420 // RLockFunc locks reading with given callback function `f` within RWMutex.RLock. 421 func (m *StrAnyMap) RLockFunc(f func(m map[string]interface{})) { 422 m.mu.RLock() 423 defer m.mu.RUnlock() 424 f(m.data) 425 } 426 427 // Flip exchanges key-value of the map to value-key. 428 func (m *StrAnyMap) Flip() { 429 m.mu.Lock() 430 defer m.mu.Unlock() 431 n := make(map[string]interface{}, len(m.data)) 432 for k, v := range m.data { 433 n[gconv.String(v)] = k 434 } 435 m.data = n 436 } 437 438 // Merge merges two hash maps. 439 // The `other` map will be merged into the map `m`. 440 func (m *StrAnyMap) Merge(other *StrAnyMap) { 441 m.mu.Lock() 442 defer m.mu.Unlock() 443 if m.data == nil { 444 m.data = other.MapCopy() 445 return 446 } 447 if other != m { 448 other.mu.RLock() 449 defer other.mu.RUnlock() 450 } 451 for k, v := range other.data { 452 m.data[k] = v 453 } 454 } 455 456 // String returns the map as a string. 457 func (m *StrAnyMap) String() string { 458 if m == nil { 459 return "" 460 } 461 b, _ := m.MarshalJSON() 462 return string(b) 463 } 464 465 // MarshalJSON implements the interface MarshalJSON for json.Marshal. 466 func (m StrAnyMap) MarshalJSON() ([]byte, error) { 467 m.mu.RLock() 468 defer m.mu.RUnlock() 469 return json.Marshal(m.data) 470 } 471 472 // UnmarshalJSON implements the interface UnmarshalJSON for json.Unmarshal. 473 func (m *StrAnyMap) UnmarshalJSON(b []byte) error { 474 m.mu.Lock() 475 defer m.mu.Unlock() 476 if m.data == nil { 477 m.data = make(map[string]interface{}) 478 } 479 if err := json.UnmarshalUseNumber(b, &m.data); err != nil { 480 return err 481 } 482 return nil 483 } 484 485 // UnmarshalValue is an interface implement which sets any type of value for map. 486 func (m *StrAnyMap) UnmarshalValue(value interface{}) (err error) { 487 m.mu.Lock() 488 defer m.mu.Unlock() 489 m.data = gconv.Map(value) 490 return 491 } 492 493 // DeepCopy implements interface for deep copy of current type. 494 func (m *StrAnyMap) DeepCopy() interface{} { 495 if m == nil { 496 return nil 497 } 498 m.mu.RLock() 499 defer m.mu.RUnlock() 500 data := make(map[string]interface{}, len(m.data)) 501 for k, v := range m.data { 502 data[k] = deepcopy.Copy(v) 503 } 504 return NewStrAnyMapFrom(data, m.mu.IsSafe()) 505 } 506 507 // IsSubOf checks whether the current map is a sub-map of `other`. 508 func (m *StrAnyMap) IsSubOf(other *StrAnyMap) bool { 509 if m == other { 510 return true 511 } 512 m.mu.RLock() 513 defer m.mu.RUnlock() 514 other.mu.RLock() 515 defer other.mu.RUnlock() 516 for key, value := range m.data { 517 otherValue, ok := other.data[key] 518 if !ok { 519 return false 520 } 521 if otherValue != value { 522 return false 523 } 524 } 525 return true 526 } 527 528 // Diff compares current map `m` with map `other` and returns their different keys. 529 // The returned `addedKeys` are the keys that are in map `m` but not in map `other`. 530 // The returned `removedKeys` are the keys that are in map `other` but not in map `m`. 531 // The returned `updatedKeys` are the keys that are both in map `m` and `other` but their values and not equal (`!=`). 532 func (m *StrAnyMap) Diff(other *StrAnyMap) (addedKeys, removedKeys, updatedKeys []string) { 533 m.mu.RLock() 534 defer m.mu.RUnlock() 535 other.mu.RLock() 536 defer other.mu.RUnlock() 537 538 for key := range m.data { 539 if _, ok := other.data[key]; !ok { 540 removedKeys = append(removedKeys, key) 541 } else if !reflect.DeepEqual(m.data[key], other.data[key]) { 542 updatedKeys = append(updatedKeys, key) 543 } 544 } 545 for key := range other.data { 546 if _, ok := m.data[key]; !ok { 547 addedKeys = append(addedKeys, key) 548 } 549 } 550 return 551 }