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