github.com/gogf/gf/v2@v2.7.4/container/gset/gset_str_set.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 this file,
     5  // You can obtain one at https://github.com/gogf/gf.
     6  //
     7  
     8  package gset
     9  
    10  import (
    11  	"bytes"
    12  	"strings"
    13  
    14  	"github.com/gogf/gf/v2/internal/json"
    15  	"github.com/gogf/gf/v2/internal/rwmutex"
    16  	"github.com/gogf/gf/v2/text/gstr"
    17  	"github.com/gogf/gf/v2/util/gconv"
    18  )
    19  
    20  // StrSet is consisted of string items.
    21  type StrSet struct {
    22  	mu   rwmutex.RWMutex
    23  	data map[string]struct{}
    24  }
    25  
    26  // NewStrSet create and returns a new set, which contains un-repeated items.
    27  // The parameter `safe` is used to specify whether using set in concurrent-safety,
    28  // which is false in default.
    29  func NewStrSet(safe ...bool) *StrSet {
    30  	return &StrSet{
    31  		mu:   rwmutex.Create(safe...),
    32  		data: make(map[string]struct{}),
    33  	}
    34  }
    35  
    36  // NewStrSetFrom returns a new set from `items`.
    37  func NewStrSetFrom(items []string, safe ...bool) *StrSet {
    38  	m := make(map[string]struct{})
    39  	for _, v := range items {
    40  		m[v] = struct{}{}
    41  	}
    42  	return &StrSet{
    43  		mu:   rwmutex.Create(safe...),
    44  		data: m,
    45  	}
    46  }
    47  
    48  // Iterator iterates the set readonly with given callback function `f`,
    49  // if `f` returns true then continue iterating; or false to stop.
    50  func (set *StrSet) Iterator(f func(v string) bool) {
    51  	for _, k := range set.Slice() {
    52  		if !f(k) {
    53  			break
    54  		}
    55  	}
    56  }
    57  
    58  // Add adds one or multiple items to the set.
    59  func (set *StrSet) Add(item ...string) {
    60  	set.mu.Lock()
    61  	if set.data == nil {
    62  		set.data = make(map[string]struct{})
    63  	}
    64  	for _, v := range item {
    65  		set.data[v] = struct{}{}
    66  	}
    67  	set.mu.Unlock()
    68  }
    69  
    70  // AddIfNotExist checks whether item exists in the set,
    71  // it adds the item to set and returns true if it does not exist in the set,
    72  // or else it does nothing and returns false.
    73  func (set *StrSet) AddIfNotExist(item string) bool {
    74  	if !set.Contains(item) {
    75  		set.mu.Lock()
    76  		defer set.mu.Unlock()
    77  		if set.data == nil {
    78  			set.data = make(map[string]struct{})
    79  		}
    80  		if _, ok := set.data[item]; !ok {
    81  			set.data[item] = struct{}{}
    82  			return true
    83  		}
    84  	}
    85  	return false
    86  }
    87  
    88  // AddIfNotExistFunc checks whether item exists in the set,
    89  // it adds the item to set and returns true if it does not exists in the set and
    90  // function `f` returns true, or else it does nothing and returns false.
    91  //
    92  // Note that, the function `f` is executed without writing lock.
    93  func (set *StrSet) AddIfNotExistFunc(item string, f func() bool) bool {
    94  	if !set.Contains(item) {
    95  		if f() {
    96  			set.mu.Lock()
    97  			defer set.mu.Unlock()
    98  			if set.data == nil {
    99  				set.data = make(map[string]struct{})
   100  			}
   101  			if _, ok := set.data[item]; !ok {
   102  				set.data[item] = struct{}{}
   103  				return true
   104  			}
   105  		}
   106  	}
   107  	return false
   108  }
   109  
   110  // AddIfNotExistFuncLock checks whether item exists in the set,
   111  // it adds the item to set and returns true if it does not exists in the set and
   112  // function `f` returns true, or else it does nothing and returns false.
   113  //
   114  // Note that, the function `f` is executed without writing lock.
   115  func (set *StrSet) AddIfNotExistFuncLock(item string, f func() bool) bool {
   116  	if !set.Contains(item) {
   117  		set.mu.Lock()
   118  		defer set.mu.Unlock()
   119  		if set.data == nil {
   120  			set.data = make(map[string]struct{})
   121  		}
   122  		if f() {
   123  			if _, ok := set.data[item]; !ok {
   124  				set.data[item] = struct{}{}
   125  				return true
   126  			}
   127  		}
   128  	}
   129  	return false
   130  }
   131  
   132  // Contains checks whether the set contains `item`.
   133  func (set *StrSet) Contains(item string) bool {
   134  	var ok bool
   135  	set.mu.RLock()
   136  	if set.data != nil {
   137  		_, ok = set.data[item]
   138  	}
   139  	set.mu.RUnlock()
   140  	return ok
   141  }
   142  
   143  // ContainsI checks whether a value exists in the set with case-insensitively.
   144  // Note that it internally iterates the whole set to do the comparison with case-insensitively.
   145  func (set *StrSet) ContainsI(item string) bool {
   146  	set.mu.RLock()
   147  	defer set.mu.RUnlock()
   148  	for k := range set.data {
   149  		if strings.EqualFold(k, item) {
   150  			return true
   151  		}
   152  	}
   153  	return false
   154  }
   155  
   156  // Remove deletes `item` from set.
   157  func (set *StrSet) Remove(item string) {
   158  	set.mu.Lock()
   159  	if set.data != nil {
   160  		delete(set.data, item)
   161  	}
   162  	set.mu.Unlock()
   163  }
   164  
   165  // Size returns the size of the set.
   166  func (set *StrSet) Size() int {
   167  	set.mu.RLock()
   168  	l := len(set.data)
   169  	set.mu.RUnlock()
   170  	return l
   171  }
   172  
   173  // Clear deletes all items of the set.
   174  func (set *StrSet) Clear() {
   175  	set.mu.Lock()
   176  	set.data = make(map[string]struct{})
   177  	set.mu.Unlock()
   178  }
   179  
   180  // Slice returns the an of items of the set as slice.
   181  func (set *StrSet) Slice() []string {
   182  	set.mu.RLock()
   183  	var (
   184  		i   = 0
   185  		ret = make([]string, len(set.data))
   186  	)
   187  	for item := range set.data {
   188  		ret[i] = item
   189  		i++
   190  	}
   191  
   192  	set.mu.RUnlock()
   193  	return ret
   194  }
   195  
   196  // Join joins items with a string `glue`.
   197  func (set *StrSet) Join(glue string) string {
   198  	set.mu.RLock()
   199  	defer set.mu.RUnlock()
   200  	if len(set.data) == 0 {
   201  		return ""
   202  	}
   203  	var (
   204  		l      = len(set.data)
   205  		i      = 0
   206  		buffer = bytes.NewBuffer(nil)
   207  	)
   208  	for k := range set.data {
   209  		buffer.WriteString(k)
   210  		if i != l-1 {
   211  			buffer.WriteString(glue)
   212  		}
   213  		i++
   214  	}
   215  	return buffer.String()
   216  }
   217  
   218  // String returns items as a string, which implements like json.Marshal does.
   219  func (set *StrSet) String() string {
   220  	if set == nil {
   221  		return ""
   222  	}
   223  	set.mu.RLock()
   224  	defer set.mu.RUnlock()
   225  	var (
   226  		l      = len(set.data)
   227  		i      = 0
   228  		buffer = bytes.NewBuffer(nil)
   229  	)
   230  	buffer.WriteByte('[')
   231  	for k := range set.data {
   232  		buffer.WriteString(`"` + gstr.QuoteMeta(k, `"\`) + `"`)
   233  		if i != l-1 {
   234  			buffer.WriteByte(',')
   235  		}
   236  		i++
   237  	}
   238  	buffer.WriteByte(']')
   239  	return buffer.String()
   240  }
   241  
   242  // LockFunc locks writing with callback function `f`.
   243  func (set *StrSet) LockFunc(f func(m map[string]struct{})) {
   244  	set.mu.Lock()
   245  	defer set.mu.Unlock()
   246  	f(set.data)
   247  }
   248  
   249  // RLockFunc locks reading with callback function `f`.
   250  func (set *StrSet) RLockFunc(f func(m map[string]struct{})) {
   251  	set.mu.RLock()
   252  	defer set.mu.RUnlock()
   253  	f(set.data)
   254  }
   255  
   256  // Equal checks whether the two sets equal.
   257  func (set *StrSet) Equal(other *StrSet) bool {
   258  	if set == other {
   259  		return true
   260  	}
   261  	set.mu.RLock()
   262  	defer set.mu.RUnlock()
   263  	other.mu.RLock()
   264  	defer other.mu.RUnlock()
   265  	if len(set.data) != len(other.data) {
   266  		return false
   267  	}
   268  	for key := range set.data {
   269  		if _, ok := other.data[key]; !ok {
   270  			return false
   271  		}
   272  	}
   273  	return true
   274  }
   275  
   276  // IsSubsetOf checks whether the current set is a sub-set of `other`.
   277  func (set *StrSet) IsSubsetOf(other *StrSet) bool {
   278  	if set == other {
   279  		return true
   280  	}
   281  	set.mu.RLock()
   282  	defer set.mu.RUnlock()
   283  	other.mu.RLock()
   284  	defer other.mu.RUnlock()
   285  	for key := range set.data {
   286  		if _, ok := other.data[key]; !ok {
   287  			return false
   288  		}
   289  	}
   290  	return true
   291  }
   292  
   293  // Union returns a new set which is the union of `set` and `other`.
   294  // Which means, all the items in `newSet` are in `set` or in `other`.
   295  func (set *StrSet) Union(others ...*StrSet) (newSet *StrSet) {
   296  	newSet = NewStrSet()
   297  	set.mu.RLock()
   298  	defer set.mu.RUnlock()
   299  	for _, other := range others {
   300  		if set != other {
   301  			other.mu.RLock()
   302  		}
   303  		for k, v := range set.data {
   304  			newSet.data[k] = v
   305  		}
   306  		if set != other {
   307  			for k, v := range other.data {
   308  				newSet.data[k] = v
   309  			}
   310  		}
   311  		if set != other {
   312  			other.mu.RUnlock()
   313  		}
   314  	}
   315  
   316  	return
   317  }
   318  
   319  // Diff returns a new set which is the difference set from `set` to `other`.
   320  // Which means, all the items in `newSet` are in `set` but not in `other`.
   321  func (set *StrSet) Diff(others ...*StrSet) (newSet *StrSet) {
   322  	newSet = NewStrSet()
   323  	set.mu.RLock()
   324  	defer set.mu.RUnlock()
   325  	for _, other := range others {
   326  		if set == other {
   327  			continue
   328  		}
   329  		other.mu.RLock()
   330  		for k, v := range set.data {
   331  			if _, ok := other.data[k]; !ok {
   332  				newSet.data[k] = v
   333  			}
   334  		}
   335  		other.mu.RUnlock()
   336  	}
   337  	return
   338  }
   339  
   340  // Intersect returns a new set which is the intersection from `set` to `other`.
   341  // Which means, all the items in `newSet` are in `set` and also in `other`.
   342  func (set *StrSet) Intersect(others ...*StrSet) (newSet *StrSet) {
   343  	newSet = NewStrSet()
   344  	set.mu.RLock()
   345  	defer set.mu.RUnlock()
   346  	for _, other := range others {
   347  		if set != other {
   348  			other.mu.RLock()
   349  		}
   350  		for k, v := range set.data {
   351  			if _, ok := other.data[k]; ok {
   352  				newSet.data[k] = v
   353  			}
   354  		}
   355  		if set != other {
   356  			other.mu.RUnlock()
   357  		}
   358  	}
   359  	return
   360  }
   361  
   362  // Complement returns a new set which is the complement from `set` to `full`.
   363  // Which means, all the items in `newSet` are in `full` and not in `set`.
   364  //
   365  // It returns the difference between `full` and `set`
   366  // if the given set `full` is not the full set of `set`.
   367  func (set *StrSet) Complement(full *StrSet) (newSet *StrSet) {
   368  	newSet = NewStrSet()
   369  	set.mu.RLock()
   370  	defer set.mu.RUnlock()
   371  	if set != full {
   372  		full.mu.RLock()
   373  		defer full.mu.RUnlock()
   374  	}
   375  	for k, v := range full.data {
   376  		if _, ok := set.data[k]; !ok {
   377  			newSet.data[k] = v
   378  		}
   379  	}
   380  	return
   381  }
   382  
   383  // Merge adds items from `others` sets into `set`.
   384  func (set *StrSet) Merge(others ...*StrSet) *StrSet {
   385  	set.mu.Lock()
   386  	defer set.mu.Unlock()
   387  	for _, other := range others {
   388  		if set != other {
   389  			other.mu.RLock()
   390  		}
   391  		for k, v := range other.data {
   392  			set.data[k] = v
   393  		}
   394  		if set != other {
   395  			other.mu.RUnlock()
   396  		}
   397  	}
   398  	return set
   399  }
   400  
   401  // Sum sums items.
   402  // Note: The items should be converted to int type,
   403  // or you'd get a result that you unexpected.
   404  func (set *StrSet) Sum() (sum int) {
   405  	set.mu.RLock()
   406  	defer set.mu.RUnlock()
   407  	for k := range set.data {
   408  		sum += gconv.Int(k)
   409  	}
   410  	return
   411  }
   412  
   413  // Pop randomly pops an item from set.
   414  func (set *StrSet) Pop() string {
   415  	set.mu.Lock()
   416  	defer set.mu.Unlock()
   417  	for k := range set.data {
   418  		delete(set.data, k)
   419  		return k
   420  	}
   421  	return ""
   422  }
   423  
   424  // Pops randomly pops `size` items from set.
   425  // It returns all items if size == -1.
   426  func (set *StrSet) Pops(size int) []string {
   427  	set.mu.Lock()
   428  	defer set.mu.Unlock()
   429  	if size > len(set.data) || size == -1 {
   430  		size = len(set.data)
   431  	}
   432  	if size <= 0 {
   433  		return nil
   434  	}
   435  	index := 0
   436  	array := make([]string, size)
   437  	for k := range set.data {
   438  		delete(set.data, k)
   439  		array[index] = k
   440  		index++
   441  		if index == size {
   442  			break
   443  		}
   444  	}
   445  	return array
   446  }
   447  
   448  // Walk applies a user supplied function `f` to every item of set.
   449  func (set *StrSet) Walk(f func(item string) string) *StrSet {
   450  	set.mu.Lock()
   451  	defer set.mu.Unlock()
   452  	m := make(map[string]struct{}, len(set.data))
   453  	for k, v := range set.data {
   454  		m[f(k)] = v
   455  	}
   456  	set.data = m
   457  	return set
   458  }
   459  
   460  // MarshalJSON implements the interface MarshalJSON for json.Marshal.
   461  func (set StrSet) MarshalJSON() ([]byte, error) {
   462  	return json.Marshal(set.Slice())
   463  }
   464  
   465  // UnmarshalJSON implements the interface UnmarshalJSON for json.Unmarshal.
   466  func (set *StrSet) UnmarshalJSON(b []byte) error {
   467  	set.mu.Lock()
   468  	defer set.mu.Unlock()
   469  	if set.data == nil {
   470  		set.data = make(map[string]struct{})
   471  	}
   472  	var array []string
   473  	if err := json.UnmarshalUseNumber(b, &array); err != nil {
   474  		return err
   475  	}
   476  	for _, v := range array {
   477  		set.data[v] = struct{}{}
   478  	}
   479  	return nil
   480  }
   481  
   482  // UnmarshalValue is an interface implement which sets any type of value for set.
   483  func (set *StrSet) UnmarshalValue(value interface{}) (err error) {
   484  	set.mu.Lock()
   485  	defer set.mu.Unlock()
   486  	if set.data == nil {
   487  		set.data = make(map[string]struct{})
   488  	}
   489  	var array []string
   490  	switch value.(type) {
   491  	case string, []byte:
   492  		err = json.UnmarshalUseNumber(gconv.Bytes(value), &array)
   493  	default:
   494  		array = gconv.SliceStr(value)
   495  	}
   496  	for _, v := range array {
   497  		set.data[v] = struct{}{}
   498  	}
   499  	return
   500  }
   501  
   502  // DeepCopy implements interface for deep copy of current type.
   503  func (set *StrSet) DeepCopy() interface{} {
   504  	if set == nil {
   505  		return nil
   506  	}
   507  	set.mu.RLock()
   508  	defer set.mu.RUnlock()
   509  	var (
   510  		slice = make([]string, len(set.data))
   511  		index = 0
   512  	)
   513  	for k := range set.data {
   514  		slice[index] = k
   515  		index++
   516  	}
   517  	return NewStrSetFrom(slice, set.mu.IsSafe())
   518  }