github.com/gogf/gf/v2@v2.7.4/container/gmap/gmap_list_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  	"bytes"
    11  	"fmt"
    12  
    13  	"github.com/gogf/gf/v2/container/glist"
    14  	"github.com/gogf/gf/v2/container/gvar"
    15  	"github.com/gogf/gf/v2/internal/deepcopy"
    16  	"github.com/gogf/gf/v2/internal/empty"
    17  	"github.com/gogf/gf/v2/internal/json"
    18  	"github.com/gogf/gf/v2/internal/rwmutex"
    19  	"github.com/gogf/gf/v2/util/gconv"
    20  )
    21  
    22  // ListMap is a map that preserves insertion-order.
    23  //
    24  // It is backed by a hash table to store values and doubly-linked list to store ordering.
    25  //
    26  // Structure is not thread safe.
    27  //
    28  // Reference: http://en.wikipedia.org/wiki/Associative_array
    29  type ListMap struct {
    30  	mu   rwmutex.RWMutex
    31  	data map[interface{}]*glist.Element
    32  	list *glist.List
    33  }
    34  
    35  type gListMapNode struct {
    36  	key   interface{}
    37  	value interface{}
    38  }
    39  
    40  // NewListMap returns an empty link map.
    41  // ListMap is backed by a hash table to store values and doubly-linked list to store ordering.
    42  // The parameter `safe` is used to specify whether using map in concurrent-safety,
    43  // which is false in default.
    44  func NewListMap(safe ...bool) *ListMap {
    45  	return &ListMap{
    46  		mu:   rwmutex.Create(safe...),
    47  		data: make(map[interface{}]*glist.Element),
    48  		list: glist.New(),
    49  	}
    50  }
    51  
    52  // NewListMapFrom returns a link map from given map `data`.
    53  // Note that, the param `data` map will be set as the underlying data map(no deep copy),
    54  // there might be some concurrent-safe issues when changing the map outside.
    55  func NewListMapFrom(data map[interface{}]interface{}, safe ...bool) *ListMap {
    56  	m := NewListMap(safe...)
    57  	m.Sets(data)
    58  	return m
    59  }
    60  
    61  // Iterator is alias of IteratorAsc.
    62  func (m *ListMap) Iterator(f func(key, value interface{}) bool) {
    63  	m.IteratorAsc(f)
    64  }
    65  
    66  // IteratorAsc iterates the map readonly in ascending order with given callback function `f`.
    67  // If `f` returns true, then it continues iterating; or false to stop.
    68  func (m *ListMap) IteratorAsc(f func(key interface{}, value interface{}) bool) {
    69  	m.mu.RLock()
    70  	defer m.mu.RUnlock()
    71  	if m.list != nil {
    72  		var node *gListMapNode
    73  		m.list.IteratorAsc(func(e *glist.Element) bool {
    74  			node = e.Value.(*gListMapNode)
    75  			return f(node.key, node.value)
    76  		})
    77  	}
    78  }
    79  
    80  // IteratorDesc iterates the map readonly in descending order with given callback function `f`.
    81  // If `f` returns true, then it continues iterating; or false to stop.
    82  func (m *ListMap) IteratorDesc(f func(key interface{}, value interface{}) bool) {
    83  	m.mu.RLock()
    84  	defer m.mu.RUnlock()
    85  	if m.list != nil {
    86  		var node *gListMapNode
    87  		m.list.IteratorDesc(func(e *glist.Element) bool {
    88  			node = e.Value.(*gListMapNode)
    89  			return f(node.key, node.value)
    90  		})
    91  	}
    92  }
    93  
    94  // Clone returns a new link map with copy of current map data.
    95  func (m *ListMap) Clone(safe ...bool) *ListMap {
    96  	return NewListMapFrom(m.Map(), safe...)
    97  }
    98  
    99  // Clear deletes all data of the map, it will remake a new underlying data map.
   100  func (m *ListMap) Clear() {
   101  	m.mu.Lock()
   102  	m.data = make(map[interface{}]*glist.Element)
   103  	m.list = glist.New()
   104  	m.mu.Unlock()
   105  }
   106  
   107  // Replace the data of the map with given `data`.
   108  func (m *ListMap) Replace(data map[interface{}]interface{}) {
   109  	m.mu.Lock()
   110  	m.data = make(map[interface{}]*glist.Element)
   111  	m.list = glist.New()
   112  	for key, value := range data {
   113  		if e, ok := m.data[key]; !ok {
   114  			m.data[key] = m.list.PushBack(&gListMapNode{key, value})
   115  		} else {
   116  			e.Value = &gListMapNode{key, value}
   117  		}
   118  	}
   119  	m.mu.Unlock()
   120  }
   121  
   122  // Map returns a copy of the underlying data of the map.
   123  func (m *ListMap) Map() map[interface{}]interface{} {
   124  	m.mu.RLock()
   125  	var node *gListMapNode
   126  	var data map[interface{}]interface{}
   127  	if m.list != nil {
   128  		data = make(map[interface{}]interface{}, len(m.data))
   129  		m.list.IteratorAsc(func(e *glist.Element) bool {
   130  			node = e.Value.(*gListMapNode)
   131  			data[node.key] = node.value
   132  			return true
   133  		})
   134  	}
   135  	m.mu.RUnlock()
   136  	return data
   137  }
   138  
   139  // MapStrAny returns a copy of the underlying data of the map as map[string]interface{}.
   140  func (m *ListMap) MapStrAny() map[string]interface{} {
   141  	m.mu.RLock()
   142  	var node *gListMapNode
   143  	var data map[string]interface{}
   144  	if m.list != nil {
   145  		data = make(map[string]interface{}, len(m.data))
   146  		m.list.IteratorAsc(func(e *glist.Element) bool {
   147  			node = e.Value.(*gListMapNode)
   148  			data[gconv.String(node.key)] = node.value
   149  			return true
   150  		})
   151  	}
   152  	m.mu.RUnlock()
   153  	return data
   154  }
   155  
   156  // FilterEmpty deletes all key-value pair of which the value is empty.
   157  func (m *ListMap) FilterEmpty() {
   158  	m.mu.Lock()
   159  	if m.list != nil {
   160  		var (
   161  			keys = make([]interface{}, 0)
   162  			node *gListMapNode
   163  		)
   164  		m.list.IteratorAsc(func(e *glist.Element) bool {
   165  			node = e.Value.(*gListMapNode)
   166  			if empty.IsEmpty(node.value) {
   167  				keys = append(keys, node.key)
   168  			}
   169  			return true
   170  		})
   171  		if len(keys) > 0 {
   172  			for _, key := range keys {
   173  				if e, ok := m.data[key]; ok {
   174  					delete(m.data, key)
   175  					m.list.Remove(e)
   176  				}
   177  			}
   178  		}
   179  	}
   180  	m.mu.Unlock()
   181  }
   182  
   183  // Set sets key-value to the map.
   184  func (m *ListMap) Set(key interface{}, value interface{}) {
   185  	m.mu.Lock()
   186  	if m.data == nil {
   187  		m.data = make(map[interface{}]*glist.Element)
   188  		m.list = glist.New()
   189  	}
   190  	if e, ok := m.data[key]; !ok {
   191  		m.data[key] = m.list.PushBack(&gListMapNode{key, value})
   192  	} else {
   193  		e.Value = &gListMapNode{key, value}
   194  	}
   195  	m.mu.Unlock()
   196  }
   197  
   198  // Sets batch sets key-values to the map.
   199  func (m *ListMap) Sets(data map[interface{}]interface{}) {
   200  	m.mu.Lock()
   201  	if m.data == nil {
   202  		m.data = make(map[interface{}]*glist.Element)
   203  		m.list = glist.New()
   204  	}
   205  	for key, value := range data {
   206  		if e, ok := m.data[key]; !ok {
   207  			m.data[key] = m.list.PushBack(&gListMapNode{key, value})
   208  		} else {
   209  			e.Value = &gListMapNode{key, value}
   210  		}
   211  	}
   212  	m.mu.Unlock()
   213  }
   214  
   215  // Search searches the map with given `key`.
   216  // Second return parameter `found` is true if key was found, otherwise false.
   217  func (m *ListMap) Search(key interface{}) (value interface{}, found bool) {
   218  	m.mu.RLock()
   219  	if m.data != nil {
   220  		if e, ok := m.data[key]; ok {
   221  			value = e.Value.(*gListMapNode).value
   222  			found = ok
   223  		}
   224  	}
   225  	m.mu.RUnlock()
   226  	return
   227  }
   228  
   229  // Get returns the value by given `key`.
   230  func (m *ListMap) Get(key interface{}) (value interface{}) {
   231  	m.mu.RLock()
   232  	if m.data != nil {
   233  		if e, ok := m.data[key]; ok {
   234  			value = e.Value.(*gListMapNode).value
   235  		}
   236  	}
   237  	m.mu.RUnlock()
   238  	return
   239  }
   240  
   241  // Pop retrieves and deletes an item from the map.
   242  func (m *ListMap) Pop() (key, value interface{}) {
   243  	m.mu.Lock()
   244  	defer m.mu.Unlock()
   245  	for k, e := range m.data {
   246  		value = e.Value.(*gListMapNode).value
   247  		delete(m.data, k)
   248  		m.list.Remove(e)
   249  		return k, value
   250  	}
   251  	return
   252  }
   253  
   254  // Pops retrieves and deletes `size` items from the map.
   255  // It returns all items if size == -1.
   256  func (m *ListMap) Pops(size int) map[interface{}]interface{} {
   257  	m.mu.Lock()
   258  	defer m.mu.Unlock()
   259  	if size > len(m.data) || size == -1 {
   260  		size = len(m.data)
   261  	}
   262  	if size == 0 {
   263  		return nil
   264  	}
   265  	index := 0
   266  	newMap := make(map[interface{}]interface{}, size)
   267  	for k, e := range m.data {
   268  		value := e.Value.(*gListMapNode).value
   269  		delete(m.data, k)
   270  		m.list.Remove(e)
   271  		newMap[k] = value
   272  		index++
   273  		if index == size {
   274  			break
   275  		}
   276  	}
   277  	return newMap
   278  }
   279  
   280  // doSetWithLockCheck checks whether value of the key exists with mutex.Lock,
   281  // if not exists, set value to the map with given `key`,
   282  // or else just return the existing value.
   283  //
   284  // When setting value, if `value` is type of `func() interface {}`,
   285  // it will be executed with mutex.Lock of the map,
   286  // and its return value will be set to the map with `key`.
   287  //
   288  // It returns value with given `key`.
   289  func (m *ListMap) doSetWithLockCheck(key interface{}, value interface{}) interface{} {
   290  	m.mu.Lock()
   291  	defer m.mu.Unlock()
   292  	if m.data == nil {
   293  		m.data = make(map[interface{}]*glist.Element)
   294  		m.list = glist.New()
   295  	}
   296  	if e, ok := m.data[key]; ok {
   297  		return e.Value.(*gListMapNode).value
   298  	}
   299  	if f, ok := value.(func() interface{}); ok {
   300  		value = f()
   301  	}
   302  	if value != nil {
   303  		m.data[key] = m.list.PushBack(&gListMapNode{key, value})
   304  	}
   305  	return value
   306  }
   307  
   308  // GetOrSet returns the value by key,
   309  // or sets value with given `value` if it does not exist and then returns this value.
   310  func (m *ListMap) GetOrSet(key interface{}, value interface{}) interface{} {
   311  	if v, ok := m.Search(key); !ok {
   312  		return m.doSetWithLockCheck(key, value)
   313  	} else {
   314  		return v
   315  	}
   316  }
   317  
   318  // GetOrSetFunc returns the value by key,
   319  // or sets value with returned value of callback function `f` if it does not exist
   320  // and then returns this value.
   321  func (m *ListMap) GetOrSetFunc(key interface{}, f func() interface{}) interface{} {
   322  	if v, ok := m.Search(key); !ok {
   323  		return m.doSetWithLockCheck(key, f())
   324  	} else {
   325  		return v
   326  	}
   327  }
   328  
   329  // GetOrSetFuncLock returns the value by key,
   330  // or sets value with returned value of callback function `f` if it does not exist
   331  // and then returns this value.
   332  //
   333  // GetOrSetFuncLock differs with GetOrSetFunc function is that it executes function `f`
   334  // with mutex.Lock of the map.
   335  func (m *ListMap) GetOrSetFuncLock(key interface{}, f func() interface{}) interface{} {
   336  	if v, ok := m.Search(key); !ok {
   337  		return m.doSetWithLockCheck(key, f)
   338  	} else {
   339  		return v
   340  	}
   341  }
   342  
   343  // GetVar returns a Var with the value by given `key`.
   344  // The returned Var is un-concurrent safe.
   345  func (m *ListMap) GetVar(key interface{}) *gvar.Var {
   346  	return gvar.New(m.Get(key))
   347  }
   348  
   349  // GetVarOrSet returns a Var with result from GetVarOrSet.
   350  // The returned Var is un-concurrent safe.
   351  func (m *ListMap) GetVarOrSet(key interface{}, value interface{}) *gvar.Var {
   352  	return gvar.New(m.GetOrSet(key, value))
   353  }
   354  
   355  // GetVarOrSetFunc returns a Var with result from GetOrSetFunc.
   356  // The returned Var is un-concurrent safe.
   357  func (m *ListMap) GetVarOrSetFunc(key interface{}, f func() interface{}) *gvar.Var {
   358  	return gvar.New(m.GetOrSetFunc(key, f))
   359  }
   360  
   361  // GetVarOrSetFuncLock returns a Var with result from GetOrSetFuncLock.
   362  // The returned Var is un-concurrent safe.
   363  func (m *ListMap) GetVarOrSetFuncLock(key interface{}, f func() interface{}) *gvar.Var {
   364  	return gvar.New(m.GetOrSetFuncLock(key, f))
   365  }
   366  
   367  // SetIfNotExist sets `value` to the map if the `key` does not exist, and then returns true.
   368  // It returns false if `key` exists, and `value` would be ignored.
   369  func (m *ListMap) SetIfNotExist(key interface{}, value interface{}) bool {
   370  	if !m.Contains(key) {
   371  		m.doSetWithLockCheck(key, value)
   372  		return true
   373  	}
   374  	return false
   375  }
   376  
   377  // SetIfNotExistFunc sets value with return value of callback function `f`, and then returns true.
   378  // It returns false if `key` exists, and `value` would be ignored.
   379  func (m *ListMap) SetIfNotExistFunc(key interface{}, f func() interface{}) bool {
   380  	if !m.Contains(key) {
   381  		m.doSetWithLockCheck(key, f())
   382  		return true
   383  	}
   384  	return false
   385  }
   386  
   387  // SetIfNotExistFuncLock sets value with return value of callback function `f`, and then returns true.
   388  // It returns false if `key` exists, and `value` would be ignored.
   389  //
   390  // SetIfNotExistFuncLock differs with SetIfNotExistFunc function is that
   391  // it executes function `f` with mutex.Lock of the map.
   392  func (m *ListMap) SetIfNotExistFuncLock(key interface{}, f func() interface{}) bool {
   393  	if !m.Contains(key) {
   394  		m.doSetWithLockCheck(key, f)
   395  		return true
   396  	}
   397  	return false
   398  }
   399  
   400  // Remove deletes value from map by given `key`, and return this deleted value.
   401  func (m *ListMap) Remove(key interface{}) (value interface{}) {
   402  	m.mu.Lock()
   403  	if m.data != nil {
   404  		if e, ok := m.data[key]; ok {
   405  			value = e.Value.(*gListMapNode).value
   406  			delete(m.data, key)
   407  			m.list.Remove(e)
   408  		}
   409  	}
   410  	m.mu.Unlock()
   411  	return
   412  }
   413  
   414  // Removes batch deletes values of the map by keys.
   415  func (m *ListMap) Removes(keys []interface{}) {
   416  	m.mu.Lock()
   417  	if m.data != nil {
   418  		for _, key := range keys {
   419  			if e, ok := m.data[key]; ok {
   420  				delete(m.data, key)
   421  				m.list.Remove(e)
   422  			}
   423  		}
   424  	}
   425  	m.mu.Unlock()
   426  }
   427  
   428  // Keys returns all keys of the map as a slice in ascending order.
   429  func (m *ListMap) Keys() []interface{} {
   430  	m.mu.RLock()
   431  	var (
   432  		keys  = make([]interface{}, m.list.Len())
   433  		index = 0
   434  	)
   435  	if m.list != nil {
   436  		m.list.IteratorAsc(func(e *glist.Element) bool {
   437  			keys[index] = e.Value.(*gListMapNode).key
   438  			index++
   439  			return true
   440  		})
   441  	}
   442  	m.mu.RUnlock()
   443  	return keys
   444  }
   445  
   446  // Values returns all values of the map as a slice.
   447  func (m *ListMap) Values() []interface{} {
   448  	m.mu.RLock()
   449  	var (
   450  		values = make([]interface{}, m.list.Len())
   451  		index  = 0
   452  	)
   453  	if m.list != nil {
   454  		m.list.IteratorAsc(func(e *glist.Element) bool {
   455  			values[index] = e.Value.(*gListMapNode).value
   456  			index++
   457  			return true
   458  		})
   459  	}
   460  	m.mu.RUnlock()
   461  	return values
   462  }
   463  
   464  // Contains checks whether a key exists.
   465  // It returns true if the `key` exists, or else false.
   466  func (m *ListMap) Contains(key interface{}) (ok bool) {
   467  	m.mu.RLock()
   468  	if m.data != nil {
   469  		_, ok = m.data[key]
   470  	}
   471  	m.mu.RUnlock()
   472  	return
   473  }
   474  
   475  // Size returns the size of the map.
   476  func (m *ListMap) Size() (size int) {
   477  	m.mu.RLock()
   478  	size = len(m.data)
   479  	m.mu.RUnlock()
   480  	return
   481  }
   482  
   483  // IsEmpty checks whether the map is empty.
   484  // It returns true if map is empty, or else false.
   485  func (m *ListMap) IsEmpty() bool {
   486  	return m.Size() == 0
   487  }
   488  
   489  // Flip exchanges key-value of the map to value-key.
   490  func (m *ListMap) Flip() {
   491  	data := m.Map()
   492  	m.Clear()
   493  	for key, value := range data {
   494  		m.Set(value, key)
   495  	}
   496  }
   497  
   498  // Merge merges two link maps.
   499  // The `other` map will be merged into the map `m`.
   500  func (m *ListMap) Merge(other *ListMap) {
   501  	m.mu.Lock()
   502  	defer m.mu.Unlock()
   503  	if m.data == nil {
   504  		m.data = make(map[interface{}]*glist.Element)
   505  		m.list = glist.New()
   506  	}
   507  	if other != m {
   508  		other.mu.RLock()
   509  		defer other.mu.RUnlock()
   510  	}
   511  	var node *gListMapNode
   512  	other.list.IteratorAsc(func(e *glist.Element) bool {
   513  		node = e.Value.(*gListMapNode)
   514  		if e, ok := m.data[node.key]; !ok {
   515  			m.data[node.key] = m.list.PushBack(&gListMapNode{node.key, node.value})
   516  		} else {
   517  			e.Value = &gListMapNode{node.key, node.value}
   518  		}
   519  		return true
   520  	})
   521  }
   522  
   523  // String returns the map as a string.
   524  func (m *ListMap) String() string {
   525  	if m == nil {
   526  		return ""
   527  	}
   528  	b, _ := m.MarshalJSON()
   529  	return string(b)
   530  }
   531  
   532  // MarshalJSON implements the interface MarshalJSON for json.Marshal.
   533  func (m ListMap) MarshalJSON() (jsonBytes []byte, err error) {
   534  	if m.data == nil {
   535  		return []byte("null"), nil
   536  	}
   537  	buffer := bytes.NewBuffer(nil)
   538  	buffer.WriteByte('{')
   539  	m.Iterator(func(key, value interface{}) bool {
   540  		valueBytes, valueJsonErr := json.Marshal(value)
   541  		if valueJsonErr != nil {
   542  			err = valueJsonErr
   543  			return false
   544  		}
   545  		if buffer.Len() > 1 {
   546  			buffer.WriteByte(',')
   547  		}
   548  		buffer.WriteString(fmt.Sprintf(`"%v":%s`, key, valueBytes))
   549  		return true
   550  	})
   551  	buffer.WriteByte('}')
   552  	return buffer.Bytes(), nil
   553  }
   554  
   555  // UnmarshalJSON implements the interface UnmarshalJSON for json.Unmarshal.
   556  func (m *ListMap) UnmarshalJSON(b []byte) error {
   557  	m.mu.Lock()
   558  	defer m.mu.Unlock()
   559  	if m.data == nil {
   560  		m.data = make(map[interface{}]*glist.Element)
   561  		m.list = glist.New()
   562  	}
   563  	var data map[string]interface{}
   564  	if err := json.UnmarshalUseNumber(b, &data); err != nil {
   565  		return err
   566  	}
   567  	for key, value := range data {
   568  		if e, ok := m.data[key]; !ok {
   569  			m.data[key] = m.list.PushBack(&gListMapNode{key, value})
   570  		} else {
   571  			e.Value = &gListMapNode{key, value}
   572  		}
   573  	}
   574  	return nil
   575  }
   576  
   577  // UnmarshalValue is an interface implement which sets any type of value for map.
   578  func (m *ListMap) UnmarshalValue(value interface{}) (err error) {
   579  	m.mu.Lock()
   580  	defer m.mu.Unlock()
   581  	if m.data == nil {
   582  		m.data = make(map[interface{}]*glist.Element)
   583  		m.list = glist.New()
   584  	}
   585  	for k, v := range gconv.Map(value) {
   586  		if e, ok := m.data[k]; !ok {
   587  			m.data[k] = m.list.PushBack(&gListMapNode{k, v})
   588  		} else {
   589  			e.Value = &gListMapNode{k, v}
   590  		}
   591  	}
   592  	return
   593  }
   594  
   595  // DeepCopy implements interface for deep copy of current type.
   596  func (m *ListMap) DeepCopy() interface{} {
   597  	if m == nil {
   598  		return nil
   599  	}
   600  	m.mu.RLock()
   601  	defer m.mu.RUnlock()
   602  	data := make(map[interface{}]interface{}, len(m.data))
   603  	if m.list != nil {
   604  		var node *gListMapNode
   605  		m.list.IteratorAsc(func(e *glist.Element) bool {
   606  			node = e.Value.(*gListMapNode)
   607  			data[node.key] = deepcopy.Copy(node.value)
   608  			return true
   609  		})
   610  	}
   611  	return NewListMapFrom(data, m.mu.IsSafe())
   612  }