github.com/zhongdalu/gf@v1.0.0/g/container/gmap/gmap_hash_str_any_map.go (about) 1 // Copyright 2017 gf Author(https://github.com/zhongdalu/gf). 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/zhongdalu/gf. 6 // 7 8 package gmap 9 10 import ( 11 "encoding/json" 12 13 "github.com/zhongdalu/gf/g/container/gvar" 14 "github.com/zhongdalu/gf/g/internal/rwmutex" 15 "github.com/zhongdalu/gf/g/util/gconv" 16 ) 17 18 type StrAnyMap struct { 19 mu *rwmutex.RWMutex 20 data map[string]interface{} 21 } 22 23 // NewStrAnyMap returns an empty StrAnyMap object. 24 // The parameter <unsafe> used to specify whether using map in un-concurrent-safety, 25 // which is false in default, means concurrent-safe. 26 func NewStrAnyMap(unsafe ...bool) *StrAnyMap { 27 return &StrAnyMap{ 28 mu: rwmutex.New(unsafe...), 29 data: make(map[string]interface{}), 30 } 31 } 32 33 // NewStrAnyMapFrom 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 NewStrAnyMapFrom(data map[string]interface{}, unsafe ...bool) *StrAnyMap { 37 return &StrAnyMap{ 38 mu: rwmutex.New(unsafe...), 39 data: data, 40 } 41 } 42 43 // Iterator iterates the hash map with custom callback function <f>. 44 // If <f> returns true, then it continues iterating; or false to stop. 45 func (m *StrAnyMap) Iterator(f func(k string, v interface{}) bool) { 46 m.mu.RLock() 47 defer m.mu.RUnlock() 48 for k, v := range m.data { 49 if !f(k, v) { 50 break 51 } 52 } 53 } 54 55 // Clone returns a new hash map with copy of current map data. 56 func (m *StrAnyMap) Clone() *StrAnyMap { 57 return NewStrAnyMapFrom(m.Map(), !m.mu.IsSafe()) 58 } 59 60 // Map returns a copy of the data of the hash map. 61 func (m *StrAnyMap) Map() map[string]interface{} { 62 m.mu.RLock() 63 data := make(map[string]interface{}, len(m.data)) 64 for k, v := range m.data { 65 data[k] = v 66 } 67 m.mu.RUnlock() 68 return data 69 } 70 71 // Set sets key-value to the hash map. 72 func (m *StrAnyMap) Set(key string, val interface{}) { 73 m.mu.Lock() 74 m.data[key] = val 75 m.mu.Unlock() 76 } 77 78 // Sets batch sets key-values to the hash map. 79 func (m *StrAnyMap) Sets(data map[string]interface{}) { 80 m.mu.Lock() 81 for k, v := range data { 82 m.data[k] = v 83 } 84 m.mu.Unlock() 85 } 86 87 // Search searches the map with given <key>. 88 // Second return parameter <found> is true if key was found, otherwise false. 89 func (m *StrAnyMap) Search(key string) (value interface{}, found bool) { 90 m.mu.RLock() 91 value, found = m.data[key] 92 m.mu.RUnlock() 93 return 94 } 95 96 // Get returns the value by given <key>. 97 func (m *StrAnyMap) Get(key string) interface{} { 98 m.mu.RLock() 99 val, _ := m.data[key] 100 m.mu.RUnlock() 101 return val 102 } 103 104 // doSetWithLockCheck checks whether value of the key exists with mutex.Lock, 105 // if not exists, set value to the map with given <key>, 106 // or else just return the existing value. 107 // 108 // When setting value, if <value> is type of <func() interface {}>, 109 // it will be executed with mutex.Lock of the hash map, 110 // and its return value will be set to the map with <key>. 111 // 112 // It returns value with given <key>. 113 func (m *StrAnyMap) doSetWithLockCheck(key string, value interface{}) interface{} { 114 m.mu.Lock() 115 defer m.mu.Unlock() 116 if v, ok := m.data[key]; ok { 117 return v 118 } 119 if f, ok := value.(func() interface{}); ok { 120 value = f() 121 } 122 if value != nil { 123 m.data[key] = value 124 } 125 return value 126 } 127 128 // GetOrSet returns the value by key, 129 // or set value with given <value> if not exist and returns this value. 130 func (m *StrAnyMap) GetOrSet(key string, value interface{}) interface{} { 131 if v, ok := m.Search(key); !ok { 132 return m.doSetWithLockCheck(key, value) 133 } else { 134 return v 135 } 136 } 137 138 // GetOrSetFunc returns the value by key, 139 // or sets value with return value of callback function <f> if not exist 140 // and returns this value. 141 func (m *StrAnyMap) GetOrSetFunc(key string, f func() interface{}) interface{} { 142 if v, ok := m.Search(key); !ok { 143 return m.doSetWithLockCheck(key, f()) 144 } else { 145 return v 146 } 147 } 148 149 // GetOrSetFuncLock returns the value by key, 150 // or sets value with return value of callback function <f> if not exist 151 // and returns this value. 152 // 153 // GetOrSetFuncLock differs with GetOrSetFunc function is that it executes function <f> 154 // with mutex.Lock of the hash map. 155 func (m *StrAnyMap) GetOrSetFuncLock(key string, f func() interface{}) interface{} { 156 if v, ok := m.Search(key); !ok { 157 return m.doSetWithLockCheck(key, f) 158 } else { 159 return v 160 } 161 } 162 163 // GetVar returns a gvar.Var with the value by given <key>. 164 // The returned gvar.Var is un-concurrent safe. 165 func (m *StrAnyMap) GetVar(key string) *gvar.Var { 166 return gvar.New(m.Get(key), true) 167 } 168 169 // GetVarOrSet returns a gvar.Var with result from GetVarOrSet. 170 // The returned gvar.Var is un-concurrent safe. 171 func (m *StrAnyMap) GetVarOrSet(key string, value interface{}) *gvar.Var { 172 return gvar.New(m.GetOrSet(key, value), true) 173 } 174 175 // GetVarOrSetFunc returns a gvar.Var with result from GetOrSetFunc. 176 // The returned gvar.Var is un-concurrent safe. 177 func (m *StrAnyMap) GetVarOrSetFunc(key string, f func() interface{}) *gvar.Var { 178 return gvar.New(m.GetOrSetFunc(key, f), true) 179 } 180 181 // GetVarOrSetFuncLock returns a gvar.Var with result from GetOrSetFuncLock. 182 // The returned gvar.Var is un-concurrent safe. 183 func (m *StrAnyMap) GetVarOrSetFuncLock(key string, f func() interface{}) *gvar.Var { 184 return gvar.New(m.GetOrSetFuncLock(key, f), true) 185 } 186 187 // SetIfNotExist sets <value> to the map if the <key> does not exist, then return true. 188 // It returns false if <key> exists, and <value> would be ignored. 189 func (m *StrAnyMap) SetIfNotExist(key string, value interface{}) bool { 190 if !m.Contains(key) { 191 m.doSetWithLockCheck(key, value) 192 return true 193 } 194 return false 195 } 196 197 // SetIfNotExistFunc sets value with return value of callback function <f>, then return true. 198 // It returns false if <key> exists, and <value> would be ignored. 199 func (m *StrAnyMap) SetIfNotExistFunc(key string, f func() interface{}) bool { 200 if !m.Contains(key) { 201 m.doSetWithLockCheck(key, f()) 202 return true 203 } 204 return false 205 } 206 207 // SetIfNotExistFuncLock sets value with return value of callback function <f>, then return true. 208 // It returns false if <key> exists, and <value> would be ignored. 209 // 210 // SetIfNotExistFuncLock differs with SetIfNotExistFunc function is that 211 // it executes function <f> with mutex.Lock of the hash map. 212 func (m *StrAnyMap) SetIfNotExistFuncLock(key string, f func() interface{}) bool { 213 if !m.Contains(key) { 214 m.doSetWithLockCheck(key, f) 215 return true 216 } 217 return false 218 } 219 220 // Removes batch deletes values of the map by keys. 221 func (m *StrAnyMap) Removes(keys []string) { 222 m.mu.Lock() 223 for _, key := range keys { 224 delete(m.data, key) 225 } 226 m.mu.Unlock() 227 } 228 229 // Remove deletes value from map by given <key>, and return this deleted value. 230 func (m *StrAnyMap) Remove(key string) interface{} { 231 m.mu.Lock() 232 val, exists := m.data[key] 233 if exists { 234 delete(m.data, key) 235 } 236 m.mu.Unlock() 237 return val 238 } 239 240 // Keys returns all keys of the map as a slice. 241 func (m *StrAnyMap) Keys() []string { 242 m.mu.RLock() 243 keys := make([]string, len(m.data)) 244 index := 0 245 for key := range m.data { 246 keys[index] = key 247 index++ 248 } 249 m.mu.RUnlock() 250 return keys 251 } 252 253 // Values returns all values of the map as a slice. 254 func (m *StrAnyMap) Values() []interface{} { 255 m.mu.RLock() 256 values := make([]interface{}, len(m.data)) 257 index := 0 258 for _, value := range m.data { 259 values[index] = value 260 index++ 261 } 262 m.mu.RUnlock() 263 return values 264 } 265 266 // Contains checks whether a key exists. 267 // It returns true if the <key> exists, or else false. 268 func (m *StrAnyMap) Contains(key string) bool { 269 m.mu.RLock() 270 _, exists := m.data[key] 271 m.mu.RUnlock() 272 return exists 273 } 274 275 // Size returns the size of the map. 276 func (m *StrAnyMap) Size() int { 277 m.mu.RLock() 278 length := len(m.data) 279 m.mu.RUnlock() 280 return length 281 } 282 283 // IsEmpty checks whether the map is empty. 284 // It returns true if map is empty, or else false. 285 func (m *StrAnyMap) IsEmpty() bool { 286 m.mu.RLock() 287 empty := len(m.data) == 0 288 m.mu.RUnlock() 289 return empty 290 } 291 292 // Clear deletes all data of the map, it will remake a new underlying data map. 293 func (m *StrAnyMap) Clear() { 294 m.mu.Lock() 295 m.data = make(map[string]interface{}) 296 m.mu.Unlock() 297 } 298 299 // LockFunc locks writing with given callback function <f> within RWMutex.Lock. 300 func (m *StrAnyMap) LockFunc(f func(m map[string]interface{})) { 301 m.mu.Lock() 302 defer m.mu.Unlock() 303 f(m.data) 304 } 305 306 // RLockFunc locks reading with given callback function <f> within RWMutex.RLock. 307 func (m *StrAnyMap) RLockFunc(f func(m map[string]interface{})) { 308 m.mu.RLock() 309 defer m.mu.RUnlock() 310 f(m.data) 311 } 312 313 // Flip exchanges key-value of the map to value-key. 314 func (m *StrAnyMap) Flip() { 315 m.mu.Lock() 316 defer m.mu.Unlock() 317 n := make(map[string]interface{}, len(m.data)) 318 for k, v := range m.data { 319 n[gconv.String(v)] = k 320 } 321 m.data = n 322 } 323 324 // Merge merges two hash maps. 325 // The <other> map will be merged into the map <m>. 326 func (m *StrAnyMap) Merge(other *StrAnyMap) { 327 m.mu.Lock() 328 defer m.mu.Unlock() 329 if other != m { 330 other.mu.RLock() 331 defer other.mu.RUnlock() 332 } 333 for k, v := range other.data { 334 m.data[k] = v 335 } 336 } 337 338 // MarshalJSON implements the interface MarshalJSON for json.Marshal. 339 func (m *StrAnyMap) MarshalJSON() ([]byte, error) { 340 m.mu.RLock() 341 defer m.mu.RUnlock() 342 return json.Marshal(m.data) 343 }