github.com/wangyougui/gf/v2@v2.6.5/container/gmap/gmap_hash_int_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/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  // IntStrMap implements map[int]string with RWMutex that has switch.
    17  type IntStrMap struct {
    18  	mu   rwmutex.RWMutex
    19  	data map[int]string
    20  }
    21  
    22  // NewIntStrMap returns an empty IntStrMap object.
    23  // The parameter `safe` is used to specify whether using map in concurrent-safety,
    24  // which is false in default.
    25  func NewIntStrMap(safe ...bool) *IntStrMap {
    26  	return &IntStrMap{
    27  		mu:   rwmutex.Create(safe...),
    28  		data: make(map[int]string),
    29  	}
    30  }
    31  
    32  // NewIntStrMapFrom 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 NewIntStrMapFrom(data map[int]string, safe ...bool) *IntStrMap {
    36  	return &IntStrMap{
    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 *IntStrMap) Iterator(f func(k int, v string) 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 *IntStrMap) Clone() *IntStrMap {
    56  	return NewIntStrMapFrom(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 *IntStrMap) Map() map[int]string {
    63  	m.mu.RLock()
    64  	defer m.mu.RUnlock()
    65  	if !m.mu.IsSafe() {
    66  		return m.data
    67  	}
    68  	data := make(map[int]string, 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 *IntStrMap) 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 *IntStrMap) MapCopy() map[int]string {
    88  	m.mu.RLock()
    89  	defer m.mu.RUnlock()
    90  	data := make(map[int]string, 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 *IntStrMap) 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 *IntStrMap) Set(key int, val string) {
   111  	m.mu.Lock()
   112  	if m.data == nil {
   113  		m.data = make(map[int]string)
   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 *IntStrMap) Sets(data map[int]string) {
   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 *IntStrMap) Search(key int) (value string, 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 *IntStrMap) Get(key int) (value string) {
   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 *IntStrMap) Pop() (key int, value string) {
   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 *IntStrMap) Pops(size int) map[int]string {
   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]string, 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 *IntStrMap) doSetWithLockCheck(key int, value string) string {
   196  	m.mu.Lock()
   197  	defer m.mu.Unlock()
   198  	if m.data == nil {
   199  		m.data = make(map[int]string)
   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 *IntStrMap) GetOrSet(key int, value string) string {
   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 *IntStrMap) GetOrSetFunc(key int, 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 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 *IntStrMap) GetOrSetFuncLock(key int, f func() string) string {
   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]string)
   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 *IntStrMap) SetIfNotExist(key int, value string) 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 *IntStrMap) SetIfNotExistFunc(key int, f func() string) 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 *IntStrMap) SetIfNotExistFuncLock(key int, f func() string) 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]string)
   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 *IntStrMap) 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 *IntStrMap) Remove(key int) (value string) {
   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 *IntStrMap) 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 *IntStrMap) Values() []string {
   332  	m.mu.RLock()
   333  	var (
   334  		values = make([]string, 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 *IntStrMap) 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 *IntStrMap) 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 *IntStrMap) 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 *IntStrMap) Clear() {
   373  	m.mu.Lock()
   374  	m.data = make(map[int]string)
   375  	m.mu.Unlock()
   376  }
   377  
   378  // Replace the data of the map with given `data`.
   379  func (m *IntStrMap) Replace(data map[int]string) {
   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 *IntStrMap) LockFunc(f func(m map[int]string)) {
   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 *IntStrMap) RLockFunc(f func(m map[int]string)) {
   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 *IntStrMap) Flip() {
   401  	m.mu.Lock()
   402  	defer m.mu.Unlock()
   403  	n := make(map[int]string, len(m.data))
   404  	for k, v := range m.data {
   405  		n[gconv.Int(v)] = gconv.String(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 *IntStrMap) Merge(other *IntStrMap) {
   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 *IntStrMap) 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 IntStrMap) 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 *IntStrMap) UnmarshalJSON(b []byte) error {
   446  	m.mu.Lock()
   447  	defer m.mu.Unlock()
   448  	if m.data == nil {
   449  		m.data = make(map[int]string)
   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 *IntStrMap) 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]string)
   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.String(v)
   470  		}
   471  	}
   472  	return
   473  }
   474  
   475  // DeepCopy implements interface for deep copy of current type.
   476  func (m *IntStrMap) DeepCopy() interface{} {
   477  	if m == nil {
   478  		return nil
   479  	}
   480  	m.mu.RLock()
   481  	defer m.mu.RUnlock()
   482  	data := make(map[int]string, len(m.data))
   483  	for k, v := range m.data {
   484  		data[k] = v
   485  	}
   486  	return NewIntStrMapFrom(data, m.mu.IsSafe())
   487  }
   488  
   489  // IsSubOf checks whether the current map is a sub-map of `other`.
   490  func (m *IntStrMap) IsSubOf(other *IntStrMap) 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 *IntStrMap) Diff(other *IntStrMap) (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  }