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  }