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