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