github.com/gogf/gf@v1.16.9/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/internal/json" 12 "github.com/gogf/gf/util/gconv" 13 14 "github.com/gogf/gf/internal/empty" 15 16 "github.com/gogf/gf/internal/rwmutex" 17 ) 18 19 type StrStrMap struct { 20 mu rwmutex.RWMutex 21 data map[string]string 22 } 23 24 // NewStrStrMap returns an empty StrStrMap object. 25 // The parameter <safe> is used to specify whether using map in concurrent-safety, 26 // which is false in default. 27 func NewStrStrMap(safe ...bool) *StrStrMap { 28 return &StrStrMap{ 29 data: make(map[string]string), 30 mu: rwmutex.Create(safe...), 31 } 32 } 33 34 // NewStrStrMapFrom creates and returns a hash map from given map <data>. 35 // Note that, the param <data> map will be set as the underlying data map(no deep copy), 36 // there might be some concurrent-safe issues when changing the map outside. 37 func NewStrStrMapFrom(data map[string]string, safe ...bool) *StrStrMap { 38 return &StrStrMap{ 39 mu: rwmutex.Create(safe...), 40 data: data, 41 } 42 } 43 44 // Iterator iterates the hash map readonly with custom callback function <f>. 45 // If <f> returns true, then it continues iterating; or false to stop. 46 func (m *StrStrMap) Iterator(f func(k string, v string) bool) { 47 m.mu.RLock() 48 defer m.mu.RUnlock() 49 for k, v := range m.data { 50 if !f(k, v) { 51 break 52 } 53 } 54 } 55 56 // Clone returns a new hash map with copy of current map data. 57 func (m *StrStrMap) Clone() *StrStrMap { 58 return NewStrStrMapFrom(m.MapCopy(), m.mu.IsSafe()) 59 } 60 61 // Map returns the underlying data map. 62 // Note that, if it's in concurrent-safe usage, it returns a copy of underlying data, 63 // or else a pointer to the underlying data. 64 func (m *StrStrMap) Map() map[string]string { 65 m.mu.RLock() 66 defer m.mu.RUnlock() 67 if !m.mu.IsSafe() { 68 return m.data 69 } 70 data := make(map[string]string, len(m.data)) 71 for k, v := range m.data { 72 data[k] = v 73 } 74 return data 75 } 76 77 // MapStrAny returns a copy of the underlying data of the map as map[string]interface{}. 78 func (m *StrStrMap) MapStrAny() map[string]interface{} { 79 m.mu.RLock() 80 data := make(map[string]interface{}, len(m.data)) 81 for k, v := range m.data { 82 data[k] = v 83 } 84 m.mu.RUnlock() 85 return data 86 } 87 88 // MapCopy returns a copy of the underlying data of the hash map. 89 func (m *StrStrMap) MapCopy() map[string]string { 90 m.mu.RLock() 91 defer m.mu.RUnlock() 92 data := make(map[string]string, len(m.data)) 93 for k, v := range m.data { 94 data[k] = v 95 } 96 return data 97 } 98 99 // FilterEmpty deletes all key-value pair of which the value is empty. 100 // Values like: 0, nil, false, "", len(slice/map/chan) == 0 are considered empty. 101 func (m *StrStrMap) FilterEmpty() { 102 m.mu.Lock() 103 for k, v := range m.data { 104 if empty.IsEmpty(v) { 105 delete(m.data, k) 106 } 107 } 108 m.mu.Unlock() 109 } 110 111 // Set sets key-value to the hash map. 112 func (m *StrStrMap) Set(key string, val string) { 113 m.mu.Lock() 114 if m.data == nil { 115 m.data = make(map[string]string) 116 } 117 m.data[key] = val 118 m.mu.Unlock() 119 } 120 121 // Sets batch sets key-values to the hash map. 122 func (m *StrStrMap) Sets(data map[string]string) { 123 m.mu.Lock() 124 if m.data == nil { 125 m.data = data 126 } else { 127 for k, v := range data { 128 m.data[k] = v 129 } 130 } 131 m.mu.Unlock() 132 } 133 134 // Search searches the map with given <key>. 135 // Second return parameter <found> is true if key was found, otherwise false. 136 func (m *StrStrMap) Search(key string) (value string, found bool) { 137 m.mu.RLock() 138 if m.data != nil { 139 value, found = m.data[key] 140 } 141 m.mu.RUnlock() 142 return 143 } 144 145 // Get returns the value by given <key>. 146 func (m *StrStrMap) Get(key string) (value string) { 147 m.mu.RLock() 148 if m.data != nil { 149 value, _ = m.data[key] 150 } 151 m.mu.RUnlock() 152 return 153 } 154 155 // Pop retrieves and deletes an item from the map. 156 func (m *StrStrMap) Pop() (key, value string) { 157 m.mu.Lock() 158 defer m.mu.Unlock() 159 for key, value = range m.data { 160 delete(m.data, key) 161 return 162 } 163 return 164 } 165 166 // Pops retrieves and deletes <size> items from the map. 167 // It returns all items if size == -1. 168 func (m *StrStrMap) Pops(size int) map[string]string { 169 m.mu.Lock() 170 defer m.mu.Unlock() 171 if size > len(m.data) || size == -1 { 172 size = len(m.data) 173 } 174 if size == 0 { 175 return nil 176 } 177 var ( 178 index = 0 179 newMap = make(map[string]string, size) 180 ) 181 for k, v := range m.data { 182 delete(m.data, k) 183 newMap[k] = v 184 index++ 185 if index == size { 186 break 187 } 188 } 189 return newMap 190 } 191 192 // doSetWithLockCheck checks whether value of the key exists with mutex.Lock, 193 // if not exists, set value to the map with given <key>, 194 // or else just return the existing value. 195 // 196 // It returns value with given <key>. 197 func (m *StrStrMap) doSetWithLockCheck(key string, value string) string { 198 m.mu.Lock() 199 defer m.mu.Unlock() 200 if m.data == nil { 201 m.data = make(map[string]string) 202 } 203 if v, ok := m.data[key]; ok { 204 return v 205 } 206 m.data[key] = value 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 *StrStrMap) GetOrSet(key string, value string) string { 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 *StrStrMap) GetOrSetFunc(key string, f func() string) string { 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 *StrStrMap) GetOrSetFuncLock(key string, f func() string) string { 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]string) 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 *StrStrMap) SetIfNotExist(key string, value string) 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 *StrStrMap) SetIfNotExistFunc(key string, f func() string) 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 *StrStrMap) SetIfNotExistFuncLock(key string, f func() string) 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]string) 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 *StrStrMap) 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 *StrStrMap) Remove(key string) (value string) { 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 *StrStrMap) 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 *StrStrMap) Values() []string { 336 m.mu.RLock() 337 var ( 338 values = make([]string, 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 *StrStrMap) 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 *StrStrMap) 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 *StrStrMap) 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 *StrStrMap) Clear() { 377 m.mu.Lock() 378 m.data = make(map[string]string) 379 m.mu.Unlock() 380 } 381 382 // Replace the data of the map with given <data>. 383 func (m *StrStrMap) Replace(data map[string]string) { 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 *StrStrMap) LockFunc(f func(m map[string]string)) { 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 *StrStrMap) RLockFunc(f func(m map[string]string)) { 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 *StrStrMap) Flip() { 405 m.mu.Lock() 406 defer m.mu.Unlock() 407 n := make(map[string]string, len(m.data)) 408 for k, v := range m.data { 409 n[v] = 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 *StrStrMap) Merge(other *StrStrMap) { 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 *StrStrMap) String() string { 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 }