github.com/gogf/gf/v2@v2.7.4/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/gogf/gf.
     6  
     7  package gmap
     8  
     9  import (
    10  	"github.com/gogf/gf/v2/internal/empty"
    11  	"github.com/gogf/gf/v2/internal/json"
    12  	"github.com/gogf/gf/v2/internal/rwmutex"
    13  	"github.com/gogf/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  	for k, v := range m.Map() {
    46  		if !f(k, v) {
    47  			break
    48  		}
    49  	}
    50  }
    51  
    52  // Clone returns a new hash map with copy of current map data.
    53  func (m *IntStrMap) Clone() *IntStrMap {
    54  	return NewIntStrMapFrom(m.MapCopy(), m.mu.IsSafe())
    55  }
    56  
    57  // Map returns the underlying data map.
    58  // Note that, if it's in concurrent-safe usage, it returns a copy of underlying data,
    59  // or else a pointer to the underlying data.
    60  func (m *IntStrMap) Map() map[int]string {
    61  	m.mu.RLock()
    62  	defer m.mu.RUnlock()
    63  	if !m.mu.IsSafe() {
    64  		return m.data
    65  	}
    66  	data := make(map[int]string, len(m.data))
    67  	for k, v := range m.data {
    68  		data[k] = v
    69  	}
    70  	return data
    71  }
    72  
    73  // MapStrAny returns a copy of the underlying data of the map as map[string]interface{}.
    74  func (m *IntStrMap) MapStrAny() map[string]interface{} {
    75  	m.mu.RLock()
    76  	data := make(map[string]interface{}, len(m.data))
    77  	for k, v := range m.data {
    78  		data[gconv.String(k)] = v
    79  	}
    80  	m.mu.RUnlock()
    81  	return data
    82  }
    83  
    84  // MapCopy returns a copy of the underlying data of the hash map.
    85  func (m *IntStrMap) MapCopy() map[int]string {
    86  	m.mu.RLock()
    87  	defer m.mu.RUnlock()
    88  	data := make(map[int]string, len(m.data))
    89  	for k, v := range m.data {
    90  		data[k] = v
    91  	}
    92  	return data
    93  }
    94  
    95  // FilterEmpty deletes all key-value pair of which the value is empty.
    96  // Values like: 0, nil, false, "", len(slice/map/chan) == 0 are considered empty.
    97  func (m *IntStrMap) FilterEmpty() {
    98  	m.mu.Lock()
    99  	for k, v := range m.data {
   100  		if empty.IsEmpty(v) {
   101  			delete(m.data, k)
   102  		}
   103  	}
   104  	m.mu.Unlock()
   105  }
   106  
   107  // Set sets key-value to the hash map.
   108  func (m *IntStrMap) Set(key int, val string) {
   109  	m.mu.Lock()
   110  	if m.data == nil {
   111  		m.data = make(map[int]string)
   112  	}
   113  	m.data[key] = val
   114  	m.mu.Unlock()
   115  }
   116  
   117  // Sets batch sets key-values to the hash map.
   118  func (m *IntStrMap) Sets(data map[int]string) {
   119  	m.mu.Lock()
   120  	if m.data == nil {
   121  		m.data = data
   122  	} else {
   123  		for k, v := range data {
   124  			m.data[k] = v
   125  		}
   126  	}
   127  	m.mu.Unlock()
   128  }
   129  
   130  // Search searches the map with given `key`.
   131  // Second return parameter `found` is true if key was found, otherwise false.
   132  func (m *IntStrMap) Search(key int) (value string, found bool) {
   133  	m.mu.RLock()
   134  	if m.data != nil {
   135  		value, found = m.data[key]
   136  	}
   137  	m.mu.RUnlock()
   138  	return
   139  }
   140  
   141  // Get returns the value by given `key`.
   142  func (m *IntStrMap) Get(key int) (value string) {
   143  	m.mu.RLock()
   144  	if m.data != nil {
   145  		value = m.data[key]
   146  	}
   147  	m.mu.RUnlock()
   148  	return
   149  }
   150  
   151  // Pop retrieves and deletes an item from the map.
   152  func (m *IntStrMap) Pop() (key int, value string) {
   153  	m.mu.Lock()
   154  	defer m.mu.Unlock()
   155  	for key, value = range m.data {
   156  		delete(m.data, key)
   157  		return
   158  	}
   159  	return
   160  }
   161  
   162  // Pops retrieves and deletes `size` items from the map.
   163  // It returns all items if size == -1.
   164  func (m *IntStrMap) Pops(size int) map[int]string {
   165  	m.mu.Lock()
   166  	defer m.mu.Unlock()
   167  	if size > len(m.data) || size == -1 {
   168  		size = len(m.data)
   169  	}
   170  	if size == 0 {
   171  		return nil
   172  	}
   173  	var (
   174  		index  = 0
   175  		newMap = make(map[int]string, size)
   176  	)
   177  	for k, v := range m.data {
   178  		delete(m.data, k)
   179  		newMap[k] = v
   180  		index++
   181  		if index == size {
   182  			break
   183  		}
   184  	}
   185  	return newMap
   186  }
   187  
   188  // doSetWithLockCheck checks whether value of the key exists with mutex.Lock,
   189  // if not exists, set value to the map with given `key`,
   190  // or else just return the existing value.
   191  //
   192  // It returns value with given `key`.
   193  func (m *IntStrMap) doSetWithLockCheck(key int, value string) string {
   194  	m.mu.Lock()
   195  	defer m.mu.Unlock()
   196  	if m.data == nil {
   197  		m.data = make(map[int]string)
   198  	}
   199  	if v, ok := m.data[key]; ok {
   200  		return v
   201  	}
   202  	m.data[key] = value
   203  	return value
   204  }
   205  
   206  // GetOrSet returns the value by key,
   207  // or sets value with given `value` if it does not exist and then returns this value.
   208  func (m *IntStrMap) GetOrSet(key int, value string) string {
   209  	if v, ok := m.Search(key); !ok {
   210  		return m.doSetWithLockCheck(key, value)
   211  	} else {
   212  		return v
   213  	}
   214  }
   215  
   216  // GetOrSetFunc returns the value by key,
   217  // or sets value with returned value of callback function `f` if it does not exist and returns this value.
   218  func (m *IntStrMap) GetOrSetFunc(key int, f func() string) string {
   219  	if v, ok := m.Search(key); !ok {
   220  		return m.doSetWithLockCheck(key, f())
   221  	} else {
   222  		return v
   223  	}
   224  }
   225  
   226  // GetOrSetFuncLock returns the value by key,
   227  // or sets value with returned value of callback function `f` if it does not exist and returns this value.
   228  //
   229  // GetOrSetFuncLock differs with GetOrSetFunc function is that it executes function `f`
   230  // with mutex.Lock of the hash map.
   231  func (m *IntStrMap) GetOrSetFuncLock(key int, f func() string) string {
   232  	if v, ok := m.Search(key); !ok {
   233  		m.mu.Lock()
   234  		defer m.mu.Unlock()
   235  		if m.data == nil {
   236  			m.data = make(map[int]string)
   237  		}
   238  		if v, ok = m.data[key]; ok {
   239  			return v
   240  		}
   241  		v = f()
   242  		m.data[key] = v
   243  		return v
   244  	} else {
   245  		return v
   246  	}
   247  }
   248  
   249  // SetIfNotExist sets `value` to the map if the `key` does not exist, and then returns true.
   250  // It returns false if `key` exists, and `value` would be ignored.
   251  func (m *IntStrMap) SetIfNotExist(key int, value string) bool {
   252  	if !m.Contains(key) {
   253  		m.doSetWithLockCheck(key, value)
   254  		return true
   255  	}
   256  	return false
   257  }
   258  
   259  // SetIfNotExistFunc sets value with return value of callback function `f`, and then returns true.
   260  // It returns false if `key` exists, and `value` would be ignored.
   261  func (m *IntStrMap) SetIfNotExistFunc(key int, f func() string) bool {
   262  	if !m.Contains(key) {
   263  		m.doSetWithLockCheck(key, f())
   264  		return true
   265  	}
   266  	return false
   267  }
   268  
   269  // SetIfNotExistFuncLock sets value with return value of callback function `f`, and then returns true.
   270  // It returns false if `key` exists, and `value` would be ignored.
   271  //
   272  // SetIfNotExistFuncLock differs with SetIfNotExistFunc function is that
   273  // it executes function `f` with mutex.Lock of the hash map.
   274  func (m *IntStrMap) SetIfNotExistFuncLock(key int, f func() string) bool {
   275  	if !m.Contains(key) {
   276  		m.mu.Lock()
   277  		defer m.mu.Unlock()
   278  		if m.data == nil {
   279  			m.data = make(map[int]string)
   280  		}
   281  		if _, ok := m.data[key]; !ok {
   282  			m.data[key] = f()
   283  		}
   284  		return true
   285  	}
   286  	return false
   287  }
   288  
   289  // Removes batch deletes values of the map by keys.
   290  func (m *IntStrMap) Removes(keys []int) {
   291  	m.mu.Lock()
   292  	if m.data != nil {
   293  		for _, key := range keys {
   294  			delete(m.data, key)
   295  		}
   296  	}
   297  	m.mu.Unlock()
   298  }
   299  
   300  // Remove deletes value from map by given `key`, and return this deleted value.
   301  func (m *IntStrMap) Remove(key int) (value string) {
   302  	m.mu.Lock()
   303  	if m.data != nil {
   304  		var ok bool
   305  		if value, ok = m.data[key]; ok {
   306  			delete(m.data, key)
   307  		}
   308  	}
   309  	m.mu.Unlock()
   310  	return
   311  }
   312  
   313  // Keys returns all keys of the map as a slice.
   314  func (m *IntStrMap) Keys() []int {
   315  	m.mu.RLock()
   316  	var (
   317  		keys  = make([]int, len(m.data))
   318  		index = 0
   319  	)
   320  	for key := range m.data {
   321  		keys[index] = key
   322  		index++
   323  	}
   324  	m.mu.RUnlock()
   325  	return keys
   326  }
   327  
   328  // Values returns all values of the map as a slice.
   329  func (m *IntStrMap) Values() []string {
   330  	m.mu.RLock()
   331  	var (
   332  		values = make([]string, len(m.data))
   333  		index  = 0
   334  	)
   335  	for _, value := range m.data {
   336  		values[index] = value
   337  		index++
   338  	}
   339  	m.mu.RUnlock()
   340  	return values
   341  }
   342  
   343  // Contains checks whether a key exists.
   344  // It returns true if the `key` exists, or else false.
   345  func (m *IntStrMap) Contains(key int) bool {
   346  	var ok bool
   347  	m.mu.RLock()
   348  	if m.data != nil {
   349  		_, ok = m.data[key]
   350  	}
   351  	m.mu.RUnlock()
   352  	return ok
   353  }
   354  
   355  // Size returns the size of the map.
   356  func (m *IntStrMap) Size() int {
   357  	m.mu.RLock()
   358  	length := len(m.data)
   359  	m.mu.RUnlock()
   360  	return length
   361  }
   362  
   363  // IsEmpty checks whether the map is empty.
   364  // It returns true if map is empty, or else false.
   365  func (m *IntStrMap) IsEmpty() bool {
   366  	return m.Size() == 0
   367  }
   368  
   369  // Clear deletes all data of the map, it will remake a new underlying data map.
   370  func (m *IntStrMap) Clear() {
   371  	m.mu.Lock()
   372  	m.data = make(map[int]string)
   373  	m.mu.Unlock()
   374  }
   375  
   376  // Replace the data of the map with given `data`.
   377  func (m *IntStrMap) Replace(data map[int]string) {
   378  	m.mu.Lock()
   379  	m.data = data
   380  	m.mu.Unlock()
   381  }
   382  
   383  // LockFunc locks writing with given callback function `f` within RWMutex.Lock.
   384  func (m *IntStrMap) LockFunc(f func(m map[int]string)) {
   385  	m.mu.Lock()
   386  	defer m.mu.Unlock()
   387  	f(m.data)
   388  }
   389  
   390  // RLockFunc locks reading with given callback function `f` within RWMutex.RLock.
   391  func (m *IntStrMap) RLockFunc(f func(m map[int]string)) {
   392  	m.mu.RLock()
   393  	defer m.mu.RUnlock()
   394  	f(m.data)
   395  }
   396  
   397  // Flip exchanges key-value of the map to value-key.
   398  func (m *IntStrMap) Flip() {
   399  	m.mu.Lock()
   400  	defer m.mu.Unlock()
   401  	n := make(map[int]string, len(m.data))
   402  	for k, v := range m.data {
   403  		n[gconv.Int(v)] = gconv.String(k)
   404  	}
   405  	m.data = n
   406  }
   407  
   408  // Merge merges two hash maps.
   409  // The `other` map will be merged into the map `m`.
   410  func (m *IntStrMap) Merge(other *IntStrMap) {
   411  	m.mu.Lock()
   412  	defer m.mu.Unlock()
   413  	if m.data == nil {
   414  		m.data = other.MapCopy()
   415  		return
   416  	}
   417  	if other != m {
   418  		other.mu.RLock()
   419  		defer other.mu.RUnlock()
   420  	}
   421  	for k, v := range other.data {
   422  		m.data[k] = v
   423  	}
   424  }
   425  
   426  // String returns the map as a string.
   427  func (m *IntStrMap) String() string {
   428  	if m == nil {
   429  		return ""
   430  	}
   431  	b, _ := m.MarshalJSON()
   432  	return string(b)
   433  }
   434  
   435  // MarshalJSON implements the interface MarshalJSON for json.Marshal.
   436  func (m IntStrMap) MarshalJSON() ([]byte, error) {
   437  	m.mu.RLock()
   438  	defer m.mu.RUnlock()
   439  	return json.Marshal(m.data)
   440  }
   441  
   442  // UnmarshalJSON implements the interface UnmarshalJSON for json.Unmarshal.
   443  func (m *IntStrMap) UnmarshalJSON(b []byte) error {
   444  	m.mu.Lock()
   445  	defer m.mu.Unlock()
   446  	if m.data == nil {
   447  		m.data = make(map[int]string)
   448  	}
   449  	if err := json.UnmarshalUseNumber(b, &m.data); err != nil {
   450  		return err
   451  	}
   452  	return nil
   453  }
   454  
   455  // UnmarshalValue is an interface implement which sets any type of value for map.
   456  func (m *IntStrMap) UnmarshalValue(value interface{}) (err error) {
   457  	m.mu.Lock()
   458  	defer m.mu.Unlock()
   459  	if m.data == nil {
   460  		m.data = make(map[int]string)
   461  	}
   462  	switch value.(type) {
   463  	case string, []byte:
   464  		return json.UnmarshalUseNumber(gconv.Bytes(value), &m.data)
   465  	default:
   466  		for k, v := range gconv.Map(value) {
   467  			m.data[gconv.Int(k)] = gconv.String(v)
   468  		}
   469  	}
   470  	return
   471  }
   472  
   473  // DeepCopy implements interface for deep copy of current type.
   474  func (m *IntStrMap) DeepCopy() interface{} {
   475  	if m == nil {
   476  		return nil
   477  	}
   478  	m.mu.RLock()
   479  	defer m.mu.RUnlock()
   480  	data := make(map[int]string, len(m.data))
   481  	for k, v := range m.data {
   482  		data[k] = v
   483  	}
   484  	return NewIntStrMapFrom(data, m.mu.IsSafe())
   485  }
   486  
   487  // IsSubOf checks whether the current map is a sub-map of `other`.
   488  func (m *IntStrMap) IsSubOf(other *IntStrMap) bool {
   489  	if m == other {
   490  		return true
   491  	}
   492  	m.mu.RLock()
   493  	defer m.mu.RUnlock()
   494  	other.mu.RLock()
   495  	defer other.mu.RUnlock()
   496  	for key, value := range m.data {
   497  		otherValue, ok := other.data[key]
   498  		if !ok {
   499  			return false
   500  		}
   501  		if otherValue != value {
   502  			return false
   503  		}
   504  	}
   505  	return true
   506  }
   507  
   508  // Diff compares current map `m` with map `other` and returns their different keys.
   509  // The returned `addedKeys` are the keys that are in map `m` but not in map `other`.
   510  // The returned `removedKeys` are the keys that are in map `other` but not in map `m`.
   511  // The returned `updatedKeys` are the keys that are both in map `m` and `other` but their values and not equal (`!=`).
   512  func (m *IntStrMap) Diff(other *IntStrMap) (addedKeys, removedKeys, updatedKeys []int) {
   513  	m.mu.RLock()
   514  	defer m.mu.RUnlock()
   515  	other.mu.RLock()
   516  	defer other.mu.RUnlock()
   517  
   518  	for key := range m.data {
   519  		if _, ok := other.data[key]; !ok {
   520  			removedKeys = append(removedKeys, key)
   521  		} else if m.data[key] != other.data[key] {
   522  			updatedKeys = append(updatedKeys, key)
   523  		}
   524  	}
   525  	for key := range other.data {
   526  		if _, ok := m.data[key]; !ok {
   527  			addedKeys = append(addedKeys, key)
   528  		}
   529  	}
   530  	return
   531  }