github.com/gogf/gf/v2@v2.7.4/container/gmap/gmap_hash_str_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 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 // StrStrMap implements map[string]string with RWMutex that has switch. 18 type StrStrMap struct { 19 mu rwmutex.RWMutex 20 data map[string]string 21 } 22 23 // NewStrStrMap returns an empty StrStrMap object. 24 // The parameter `safe` is used to specify whether using map in concurrent-safety, 25 // which is false in default. 26 func NewStrStrMap(safe ...bool) *StrStrMap { 27 return &StrStrMap{ 28 data: make(map[string]string), 29 mu: rwmutex.Create(safe...), 30 } 31 } 32 33 // NewStrStrMapFrom 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 NewStrStrMapFrom(data map[string]string, safe ...bool) *StrStrMap { 37 return &StrStrMap{ 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 *StrStrMap) Iterator(f func(k string, v string) 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 *StrStrMap) Clone() *StrStrMap { 55 return NewStrStrMapFrom(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 *StrStrMap) Map() map[string]string { 62 m.mu.RLock() 63 defer m.mu.RUnlock() 64 if !m.mu.IsSafe() { 65 return m.data 66 } 67 data := make(map[string]string, 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 *StrStrMap) MapStrAny() map[string]interface{} { 76 m.mu.RLock() 77 data := make(map[string]interface{}, len(m.data)) 78 for k, v := range m.data { 79 data[k] = v 80 } 81 m.mu.RUnlock() 82 return data 83 } 84 85 // MapCopy returns a copy of the underlying data of the hash map. 86 func (m *StrStrMap) MapCopy() map[string]string { 87 m.mu.RLock() 88 defer m.mu.RUnlock() 89 data := make(map[string]string, 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 *StrStrMap) 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 *StrStrMap) Set(key string, val string) { 110 m.mu.Lock() 111 if m.data == nil { 112 m.data = make(map[string]string) 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 *StrStrMap) Sets(data map[string]string) { 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 *StrStrMap) Search(key string) (value string, 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 *StrStrMap) Get(key string) (value string) { 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 *StrStrMap) Pop() (key, value string) { 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 *StrStrMap) Pops(size int) map[string]string { 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]string, 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 *StrStrMap) doSetWithLockCheck(key string, value string) string { 195 m.mu.Lock() 196 defer m.mu.Unlock() 197 if m.data == nil { 198 m.data = make(map[string]string) 199 } 200 if v, ok := m.data[key]; ok { 201 return v 202 } 203 m.data[key] = value 204 return value 205 } 206 207 // GetOrSet returns the value by key, 208 // or sets value with given `value` if it does not exist and then returns this value. 209 func (m *StrStrMap) GetOrSet(key string, value string) string { 210 if v, ok := m.Search(key); !ok { 211 return m.doSetWithLockCheck(key, value) 212 } else { 213 return v 214 } 215 } 216 217 // GetOrSetFunc returns the value by key, 218 // or sets value with returned value of callback function `f` if it does not exist 219 // and then returns this value. 220 func (m *StrStrMap) GetOrSetFunc(key string, f func() string) string { 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 230 // and then returns this value. 231 // 232 // GetOrSetFuncLock differs with GetOrSetFunc function is that it executes function `f` 233 // with mutex.Lock of the hash map. 234 func (m *StrStrMap) GetOrSetFuncLock(key string, f func() string) string { 235 if v, ok := m.Search(key); !ok { 236 m.mu.Lock() 237 defer m.mu.Unlock() 238 if m.data == nil { 239 m.data = make(map[string]string) 240 } 241 if v, ok = m.data[key]; ok { 242 return v 243 } 244 v = f() 245 m.data[key] = v 246 return v 247 } else { 248 return v 249 } 250 } 251 252 // SetIfNotExist sets `value` to the map if the `key` does not exist, and then returns true. 253 // It returns false if `key` exists, and `value` would be ignored. 254 func (m *StrStrMap) SetIfNotExist(key string, value string) bool { 255 if !m.Contains(key) { 256 m.doSetWithLockCheck(key, value) 257 return true 258 } 259 return false 260 } 261 262 // SetIfNotExistFunc sets value with return value of callback function `f`, and then returns true. 263 // It returns false if `key` exists, and `value` would be ignored. 264 func (m *StrStrMap) SetIfNotExistFunc(key string, f func() string) bool { 265 if !m.Contains(key) { 266 m.doSetWithLockCheck(key, f()) 267 return true 268 } 269 return false 270 } 271 272 // SetIfNotExistFuncLock sets value with return value of callback function `f`, and then returns true. 273 // It returns false if `key` exists, and `value` would be ignored. 274 // 275 // SetIfNotExistFuncLock differs with SetIfNotExistFunc function is that 276 // it executes function `f` with mutex.Lock of the hash map. 277 func (m *StrStrMap) SetIfNotExistFuncLock(key string, f func() string) bool { 278 if !m.Contains(key) { 279 m.mu.Lock() 280 defer m.mu.Unlock() 281 if m.data == nil { 282 m.data = make(map[string]string) 283 } 284 if _, ok := m.data[key]; !ok { 285 m.data[key] = f() 286 } 287 return true 288 } 289 return false 290 } 291 292 // Removes batch deletes values of the map by keys. 293 func (m *StrStrMap) Removes(keys []string) { 294 m.mu.Lock() 295 if m.data != nil { 296 for _, key := range keys { 297 delete(m.data, key) 298 } 299 } 300 m.mu.Unlock() 301 } 302 303 // Remove deletes value from map by given `key`, and return this deleted value. 304 func (m *StrStrMap) Remove(key string) (value string) { 305 m.mu.Lock() 306 if m.data != nil { 307 var ok bool 308 if value, ok = m.data[key]; ok { 309 delete(m.data, key) 310 } 311 } 312 m.mu.Unlock() 313 return 314 } 315 316 // Keys returns all keys of the map as a slice. 317 func (m *StrStrMap) Keys() []string { 318 m.mu.RLock() 319 var ( 320 keys = make([]string, len(m.data)) 321 index = 0 322 ) 323 for key := range m.data { 324 keys[index] = key 325 index++ 326 } 327 m.mu.RUnlock() 328 return keys 329 } 330 331 // Values returns all values of the map as a slice. 332 func (m *StrStrMap) Values() []string { 333 m.mu.RLock() 334 var ( 335 values = make([]string, len(m.data)) 336 index = 0 337 ) 338 for _, value := range m.data { 339 values[index] = value 340 index++ 341 } 342 m.mu.RUnlock() 343 return values 344 } 345 346 // Contains checks whether a key exists. 347 // It returns true if the `key` exists, or else false. 348 func (m *StrStrMap) Contains(key string) bool { 349 var ok bool 350 m.mu.RLock() 351 if m.data != nil { 352 _, ok = m.data[key] 353 } 354 m.mu.RUnlock() 355 return ok 356 } 357 358 // Size returns the size of the map. 359 func (m *StrStrMap) Size() int { 360 m.mu.RLock() 361 length := len(m.data) 362 m.mu.RUnlock() 363 return length 364 } 365 366 // IsEmpty checks whether the map is empty. 367 // It returns true if map is empty, or else false. 368 func (m *StrStrMap) IsEmpty() bool { 369 return m.Size() == 0 370 } 371 372 // Clear deletes all data of the map, it will remake a new underlying data map. 373 func (m *StrStrMap) Clear() { 374 m.mu.Lock() 375 m.data = make(map[string]string) 376 m.mu.Unlock() 377 } 378 379 // Replace the data of the map with given `data`. 380 func (m *StrStrMap) Replace(data map[string]string) { 381 m.mu.Lock() 382 m.data = data 383 m.mu.Unlock() 384 } 385 386 // LockFunc locks writing with given callback function `f` within RWMutex.Lock. 387 func (m *StrStrMap) LockFunc(f func(m map[string]string)) { 388 m.mu.Lock() 389 defer m.mu.Unlock() 390 f(m.data) 391 } 392 393 // RLockFunc locks reading with given callback function `f` within RWMutex.RLock. 394 func (m *StrStrMap) RLockFunc(f func(m map[string]string)) { 395 m.mu.RLock() 396 defer m.mu.RUnlock() 397 f(m.data) 398 } 399 400 // Flip exchanges key-value of the map to value-key. 401 func (m *StrStrMap) Flip() { 402 m.mu.Lock() 403 defer m.mu.Unlock() 404 n := make(map[string]string, len(m.data)) 405 for k, v := range m.data { 406 n[v] = k 407 } 408 m.data = n 409 } 410 411 // Merge merges two hash maps. 412 // The `other` map will be merged into the map `m`. 413 func (m *StrStrMap) Merge(other *StrStrMap) { 414 m.mu.Lock() 415 defer m.mu.Unlock() 416 if m.data == nil { 417 m.data = other.MapCopy() 418 return 419 } 420 if other != m { 421 other.mu.RLock() 422 defer other.mu.RUnlock() 423 } 424 for k, v := range other.data { 425 m.data[k] = v 426 } 427 } 428 429 // String returns the map as a string. 430 func (m *StrStrMap) String() string { 431 if m == nil { 432 return "" 433 } 434 b, _ := m.MarshalJSON() 435 return string(b) 436 } 437 438 // MarshalJSON implements the interface MarshalJSON for json.Marshal. 439 func (m StrStrMap) MarshalJSON() ([]byte, error) { 440 m.mu.RLock() 441 defer m.mu.RUnlock() 442 return json.Marshal(m.data) 443 } 444 445 // UnmarshalJSON implements the interface UnmarshalJSON for json.Unmarshal. 446 func (m *StrStrMap) UnmarshalJSON(b []byte) error { 447 m.mu.Lock() 448 defer m.mu.Unlock() 449 if m.data == nil { 450 m.data = make(map[string]string) 451 } 452 if err := json.UnmarshalUseNumber(b, &m.data); err != nil { 453 return err 454 } 455 return nil 456 } 457 458 // UnmarshalValue is an interface implement which sets any type of value for map. 459 func (m *StrStrMap) UnmarshalValue(value interface{}) (err error) { 460 m.mu.Lock() 461 defer m.mu.Unlock() 462 m.data = gconv.MapStrStr(value) 463 return 464 } 465 466 // DeepCopy implements interface for deep copy of current type. 467 func (m *StrStrMap) DeepCopy() interface{} { 468 if m == nil { 469 return nil 470 } 471 m.mu.RLock() 472 defer m.mu.RUnlock() 473 data := make(map[string]string, len(m.data)) 474 for k, v := range m.data { 475 data[k] = v 476 } 477 return NewStrStrMapFrom(data, m.mu.IsSafe()) 478 } 479 480 // IsSubOf checks whether the current map is a sub-map of `other`. 481 func (m *StrStrMap) IsSubOf(other *StrStrMap) bool { 482 if m == other { 483 return true 484 } 485 m.mu.RLock() 486 defer m.mu.RUnlock() 487 other.mu.RLock() 488 defer other.mu.RUnlock() 489 for key, value := range m.data { 490 otherValue, ok := other.data[key] 491 if !ok { 492 return false 493 } 494 if otherValue != value { 495 return false 496 } 497 } 498 return true 499 } 500 501 // Diff compares current map `m` with map `other` and returns their different keys. 502 // The returned `addedKeys` are the keys that are in map `m` but not in map `other`. 503 // The returned `removedKeys` are the keys that are in map `other` but not in map `m`. 504 // The returned `updatedKeys` are the keys that are both in map `m` and `other` but their values and not equal (`!=`). 505 func (m *StrStrMap) Diff(other *StrStrMap) (addedKeys, removedKeys, updatedKeys []string) { 506 m.mu.RLock() 507 defer m.mu.RUnlock() 508 other.mu.RLock() 509 defer other.mu.RUnlock() 510 511 for key := range m.data { 512 if _, ok := other.data[key]; !ok { 513 removedKeys = append(removedKeys, key) 514 } else if m.data[key] != other.data[key] { 515 updatedKeys = append(updatedKeys, key) 516 } 517 } 518 for key := range other.data { 519 if _, ok := m.data[key]; !ok { 520 addedKeys = append(addedKeys, key) 521 } 522 } 523 return 524 }