github.com/gogf/gf@v1.16.9/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  	"github.com/gogf/gf/internal/json"
    13  	"github.com/gogf/gf/internal/rwmutex"
    14  	"github.com/gogf/gf/text/gstr"
    15  	"github.com/gogf/gf/util/gconv"
    16  	"strings"
    17  )
    18  
    19  type StrSet struct {
    20  	mu   rwmutex.RWMutex
    21  	data map[string]struct{}
    22  }
    23  
    24  // NewStrSet create and returns a new set, which contains un-repeated items.
    25  // The parameter <safe> is used to specify whether using set in concurrent-safety,
    26  // which is false in default.
    27  func NewStrSet(safe ...bool) *StrSet {
    28  	return &StrSet{
    29  		mu:   rwmutex.Create(safe...),
    30  		data: make(map[string]struct{}),
    31  	}
    32  }
    33  
    34  // NewStrSetFrom returns a new set from <items>.
    35  func NewStrSetFrom(items []string, safe ...bool) *StrSet {
    36  	m := make(map[string]struct{})
    37  	for _, v := range items {
    38  		m[v] = struct{}{}
    39  	}
    40  	return &StrSet{
    41  		mu:   rwmutex.Create(safe...),
    42  		data: m,
    43  	}
    44  }
    45  
    46  // Iterator iterates the set readonly with given callback function <f>,
    47  // if <f> returns true then continue iterating; or false to stop.
    48  func (set *StrSet) Iterator(f func(v string) bool) {
    49  	set.mu.RLock()
    50  	defer set.mu.RUnlock()
    51  	for k, _ := range set.data {
    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 exists 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  // AddIfNotExistFunc 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 a 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  	set.mu.RLock()
   221  	defer set.mu.RUnlock()
   222  	var (
   223  		l      = len(set.data)
   224  		i      = 0
   225  		buffer = bytes.NewBuffer(nil)
   226  	)
   227  	for k, _ := range set.data {
   228  		buffer.WriteString(`"` + gstr.QuoteMeta(k, `"\`) + `"`)
   229  		if i != l-1 {
   230  			buffer.WriteByte(',')
   231  		}
   232  		i++
   233  	}
   234  	return buffer.String()
   235  }
   236  
   237  // LockFunc locks writing with callback function <f>.
   238  func (set *StrSet) LockFunc(f func(m map[string]struct{})) {
   239  	set.mu.Lock()
   240  	defer set.mu.Unlock()
   241  	f(set.data)
   242  }
   243  
   244  // RLockFunc locks reading with callback function <f>.
   245  func (set *StrSet) RLockFunc(f func(m map[string]struct{})) {
   246  	set.mu.RLock()
   247  	defer set.mu.RUnlock()
   248  	f(set.data)
   249  }
   250  
   251  // Equal checks whether the two sets equal.
   252  func (set *StrSet) Equal(other *StrSet) bool {
   253  	if set == other {
   254  		return true
   255  	}
   256  	set.mu.RLock()
   257  	defer set.mu.RUnlock()
   258  	other.mu.RLock()
   259  	defer other.mu.RUnlock()
   260  	if len(set.data) != len(other.data) {
   261  		return false
   262  	}
   263  	for key := range set.data {
   264  		if _, ok := other.data[key]; !ok {
   265  			return false
   266  		}
   267  	}
   268  	return true
   269  }
   270  
   271  // IsSubsetOf checks whether the current set is a sub-set of <other>.
   272  func (set *StrSet) IsSubsetOf(other *StrSet) bool {
   273  	if set == other {
   274  		return true
   275  	}
   276  	set.mu.RLock()
   277  	defer set.mu.RUnlock()
   278  	other.mu.RLock()
   279  	defer other.mu.RUnlock()
   280  	for key := range set.data {
   281  		if _, ok := other.data[key]; !ok {
   282  			return false
   283  		}
   284  	}
   285  	return true
   286  }
   287  
   288  // Union returns a new set which is the union of <set> and <other>.
   289  // Which means, all the items in <newSet> are in <set> or in <other>.
   290  func (set *StrSet) Union(others ...*StrSet) (newSet *StrSet) {
   291  	newSet = NewStrSet()
   292  	set.mu.RLock()
   293  	defer set.mu.RUnlock()
   294  	for _, other := range others {
   295  		if set != other {
   296  			other.mu.RLock()
   297  		}
   298  		for k, v := range set.data {
   299  			newSet.data[k] = v
   300  		}
   301  		if set != other {
   302  			for k, v := range other.data {
   303  				newSet.data[k] = v
   304  			}
   305  		}
   306  		if set != other {
   307  			other.mu.RUnlock()
   308  		}
   309  	}
   310  
   311  	return
   312  }
   313  
   314  // Diff returns a new set which is the difference set from <set> to <other>.
   315  // Which means, all the items in <newSet> are in <set> but not in <other>.
   316  func (set *StrSet) Diff(others ...*StrSet) (newSet *StrSet) {
   317  	newSet = NewStrSet()
   318  	set.mu.RLock()
   319  	defer set.mu.RUnlock()
   320  	for _, other := range others {
   321  		if set == other {
   322  			continue
   323  		}
   324  		other.mu.RLock()
   325  		for k, v := range set.data {
   326  			if _, ok := other.data[k]; !ok {
   327  				newSet.data[k] = v
   328  			}
   329  		}
   330  		other.mu.RUnlock()
   331  	}
   332  	return
   333  }
   334  
   335  // Intersect returns a new set which is the intersection from <set> to <other>.
   336  // Which means, all the items in <newSet> are in <set> and also in <other>.
   337  func (set *StrSet) Intersect(others ...*StrSet) (newSet *StrSet) {
   338  	newSet = NewStrSet()
   339  	set.mu.RLock()
   340  	defer set.mu.RUnlock()
   341  	for _, other := range others {
   342  		if set != other {
   343  			other.mu.RLock()
   344  		}
   345  		for k, v := range set.data {
   346  			if _, ok := other.data[k]; ok {
   347  				newSet.data[k] = v
   348  			}
   349  		}
   350  		if set != other {
   351  			other.mu.RUnlock()
   352  		}
   353  	}
   354  	return
   355  }
   356  
   357  // Complement returns a new set which is the complement from <set> to <full>.
   358  // Which means, all the items in <newSet> are in <full> and not in <set>.
   359  //
   360  // It returns the difference between <full> and <set>
   361  // if the given set <full> is not the full set of <set>.
   362  func (set *StrSet) Complement(full *StrSet) (newSet *StrSet) {
   363  	newSet = NewStrSet()
   364  	set.mu.RLock()
   365  	defer set.mu.RUnlock()
   366  	if set != full {
   367  		full.mu.RLock()
   368  		defer full.mu.RUnlock()
   369  	}
   370  	for k, v := range full.data {
   371  		if _, ok := set.data[k]; !ok {
   372  			newSet.data[k] = v
   373  		}
   374  	}
   375  	return
   376  }
   377  
   378  // Merge adds items from <others> sets into <set>.
   379  func (set *StrSet) Merge(others ...*StrSet) *StrSet {
   380  	set.mu.Lock()
   381  	defer set.mu.Unlock()
   382  	for _, other := range others {
   383  		if set != other {
   384  			other.mu.RLock()
   385  		}
   386  		for k, v := range other.data {
   387  			set.data[k] = v
   388  		}
   389  		if set != other {
   390  			other.mu.RUnlock()
   391  		}
   392  	}
   393  	return set
   394  }
   395  
   396  // Sum sums items.
   397  // Note: The items should be converted to int type,
   398  // or you'd get a result that you unexpected.
   399  func (set *StrSet) Sum() (sum int) {
   400  	set.mu.RLock()
   401  	defer set.mu.RUnlock()
   402  	for k, _ := range set.data {
   403  		sum += gconv.Int(k)
   404  	}
   405  	return
   406  }
   407  
   408  // Pops randomly pops an item from set.
   409  func (set *StrSet) Pop() string {
   410  	set.mu.Lock()
   411  	defer set.mu.Unlock()
   412  	for k, _ := range set.data {
   413  		delete(set.data, k)
   414  		return k
   415  	}
   416  	return ""
   417  }
   418  
   419  // Pops randomly pops <size> items from set.
   420  // It returns all items if size == -1.
   421  func (set *StrSet) Pops(size int) []string {
   422  	set.mu.Lock()
   423  	defer set.mu.Unlock()
   424  	if size > len(set.data) || size == -1 {
   425  		size = len(set.data)
   426  	}
   427  	if size <= 0 {
   428  		return nil
   429  	}
   430  	index := 0
   431  	array := make([]string, size)
   432  	for k, _ := range set.data {
   433  		delete(set.data, k)
   434  		array[index] = k
   435  		index++
   436  		if index == size {
   437  			break
   438  		}
   439  	}
   440  	return array
   441  }
   442  
   443  // Walk applies a user supplied function <f> to every item of set.
   444  func (set *StrSet) Walk(f func(item string) string) *StrSet {
   445  	set.mu.Lock()
   446  	defer set.mu.Unlock()
   447  	m := make(map[string]struct{}, len(set.data))
   448  	for k, v := range set.data {
   449  		m[f(k)] = v
   450  	}
   451  	set.data = m
   452  	return set
   453  }
   454  
   455  // MarshalJSON implements the interface MarshalJSON for json.Marshal.
   456  func (set *StrSet) MarshalJSON() ([]byte, error) {
   457  	return json.Marshal(set.Slice())
   458  }
   459  
   460  // UnmarshalJSON implements the interface UnmarshalJSON for json.Unmarshal.
   461  func (set *StrSet) UnmarshalJSON(b []byte) error {
   462  	set.mu.Lock()
   463  	defer set.mu.Unlock()
   464  	if set.data == nil {
   465  		set.data = make(map[string]struct{})
   466  	}
   467  	var array []string
   468  	if err := json.UnmarshalUseNumber(b, &array); err != nil {
   469  		return err
   470  	}
   471  	for _, v := range array {
   472  		set.data[v] = struct{}{}
   473  	}
   474  	return nil
   475  }
   476  
   477  // UnmarshalValue is an interface implement which sets any type of value for set.
   478  func (set *StrSet) UnmarshalValue(value interface{}) (err error) {
   479  	set.mu.Lock()
   480  	defer set.mu.Unlock()
   481  	if set.data == nil {
   482  		set.data = make(map[string]struct{})
   483  	}
   484  	var array []string
   485  	switch value.(type) {
   486  	case string, []byte:
   487  		err = json.UnmarshalUseNumber(gconv.Bytes(value), &array)
   488  	default:
   489  		array = gconv.SliceStr(value)
   490  	}
   491  	for _, v := range array {
   492  		set.data[v] = struct{}{}
   493  	}
   494  	return
   495  }