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