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