github.com/zhongdalu/gf@v1.0.0/g/container/gset/gset_string_set.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 this file,
     5  // You can obtain one at https://github.com/zhongdalu/gf.
     6  //
     7  
     8  package gset
     9  
    10  import (
    11  	"github.com/zhongdalu/gf/g/internal/rwmutex"
    12  	"github.com/zhongdalu/gf/g/util/gconv"
    13  	"strings"
    14  )
    15  
    16  type StringSet struct {
    17  	mu *rwmutex.RWMutex
    18  	m  map[string]struct{}
    19  }
    20  
    21  // New create and returns a new set, which contains un-repeated items.
    22  // The parameter <unsafe> used to specify whether using set in un-concurrent-safety,
    23  // which is false in default.
    24  func NewStringSet(unsafe ...bool) *StringSet {
    25  	return &StringSet{
    26  		m:  make(map[string]struct{}),
    27  		mu: rwmutex.New(unsafe...),
    28  	}
    29  }
    30  
    31  // NewStringSetFrom returns a new set from <items>.
    32  func NewStringSetFrom(items []string, unsafe ...bool) *StringSet {
    33  	m := make(map[string]struct{})
    34  	for _, v := range items {
    35  		m[v] = struct{}{}
    36  	}
    37  	return &StringSet{
    38  		m:  m,
    39  		mu: rwmutex.New(unsafe...),
    40  	}
    41  }
    42  
    43  // Iterator iterates the set with given callback function <f>,
    44  // if <f> returns true then continue iterating; or false to stop.
    45  func (set *StringSet) Iterator(f func(v string) bool) *StringSet {
    46  	set.mu.RLock()
    47  	defer set.mu.RUnlock()
    48  	for k, _ := range set.m {
    49  		if !f(k) {
    50  			break
    51  		}
    52  	}
    53  	return set
    54  }
    55  
    56  // Add adds one or multiple items to the set.
    57  func (set *StringSet) Add(item ...string) *StringSet {
    58  	set.mu.Lock()
    59  	for _, v := range item {
    60  		set.m[v] = struct{}{}
    61  	}
    62  	set.mu.Unlock()
    63  	return set
    64  }
    65  
    66  // Contains checks whether the set contains <item>.
    67  func (set *StringSet) Contains(item string) bool {
    68  	set.mu.RLock()
    69  	_, exists := set.m[item]
    70  	set.mu.RUnlock()
    71  	return exists
    72  }
    73  
    74  // Remove deletes <item> from set.
    75  func (set *StringSet) Remove(item string) *StringSet {
    76  	set.mu.Lock()
    77  	delete(set.m, item)
    78  	set.mu.Unlock()
    79  	return set
    80  }
    81  
    82  // Size returns the size of the set.
    83  func (set *StringSet) Size() int {
    84  	set.mu.RLock()
    85  	l := len(set.m)
    86  	set.mu.RUnlock()
    87  	return l
    88  }
    89  
    90  // Clear deletes all items of the set.
    91  func (set *StringSet) Clear() *StringSet {
    92  	set.mu.Lock()
    93  	set.m = make(map[string]struct{})
    94  	set.mu.Unlock()
    95  	return set
    96  }
    97  
    98  // Slice returns the a of items of the set as slice.
    99  func (set *StringSet) Slice() []string {
   100  	set.mu.RLock()
   101  	ret := make([]string, len(set.m))
   102  	i := 0
   103  	for item := range set.m {
   104  		ret[i] = item
   105  		i++
   106  	}
   107  
   108  	set.mu.RUnlock()
   109  	return ret
   110  }
   111  
   112  // Join joins items with a string <glue>.
   113  func (set *StringSet) Join(glue string) string {
   114  	return strings.Join(set.Slice(), ",")
   115  }
   116  
   117  // String returns items as a string, which are joined by char ','.
   118  func (set *StringSet) String() string {
   119  	return set.Join(",")
   120  }
   121  
   122  // LockFunc locks writing with callback function <f>.
   123  func (set *StringSet) LockFunc(f func(m map[string]struct{})) {
   124  	set.mu.Lock()
   125  	defer set.mu.Unlock()
   126  	f(set.m)
   127  }
   128  
   129  // RLockFunc locks reading with callback function <f>.
   130  func (set *StringSet) RLockFunc(f func(m map[string]struct{})) {
   131  	set.mu.RLock()
   132  	defer set.mu.RUnlock()
   133  	f(set.m)
   134  }
   135  
   136  // Equal checks whether the two sets equal.
   137  func (set *StringSet) Equal(other *StringSet) bool {
   138  	if set == other {
   139  		return true
   140  	}
   141  	set.mu.RLock()
   142  	defer set.mu.RUnlock()
   143  	other.mu.RLock()
   144  	defer other.mu.RUnlock()
   145  	if len(set.m) != len(other.m) {
   146  		return false
   147  	}
   148  	for key := range set.m {
   149  		if _, ok := other.m[key]; !ok {
   150  			return false
   151  		}
   152  	}
   153  	return true
   154  }
   155  
   156  // IsSubsetOf checks whether the current set is a sub-set of <other>.
   157  func (set *StringSet) IsSubsetOf(other *StringSet) bool {
   158  	if set == other {
   159  		return true
   160  	}
   161  	set.mu.RLock()
   162  	defer set.mu.RUnlock()
   163  	other.mu.RLock()
   164  	defer other.mu.RUnlock()
   165  	for key := range set.m {
   166  		if _, ok := other.m[key]; !ok {
   167  			return false
   168  		}
   169  	}
   170  	return true
   171  }
   172  
   173  // Union returns a new set which is the union of <set> and <other>.
   174  // Which means, all the items in <newSet> are in <set> or in <other>.
   175  func (set *StringSet) Union(others ...*StringSet) (newSet *StringSet) {
   176  	newSet = NewStringSet(true)
   177  	set.mu.RLock()
   178  	defer set.mu.RUnlock()
   179  	for _, other := range others {
   180  		if set != other {
   181  			other.mu.RLock()
   182  		}
   183  		for k, v := range set.m {
   184  			newSet.m[k] = v
   185  		}
   186  		if set != other {
   187  			for k, v := range other.m {
   188  				newSet.m[k] = v
   189  			}
   190  		}
   191  		if set != other {
   192  			other.mu.RUnlock()
   193  		}
   194  	}
   195  
   196  	return
   197  }
   198  
   199  // Diff returns a new set which is the difference set from <set> to <other>.
   200  // Which means, all the items in <newSet> are in <set> but not in <other>.
   201  func (set *StringSet) Diff(others ...*StringSet) (newSet *StringSet) {
   202  	newSet = NewStringSet(true)
   203  	set.mu.RLock()
   204  	defer set.mu.RUnlock()
   205  	for _, other := range others {
   206  		if set == other {
   207  			continue
   208  		}
   209  		other.mu.RLock()
   210  		for k, v := range set.m {
   211  			if _, ok := other.m[k]; !ok {
   212  				newSet.m[k] = v
   213  			}
   214  		}
   215  		other.mu.RUnlock()
   216  	}
   217  	return
   218  }
   219  
   220  // Intersect returns a new set which is the intersection from <set> to <other>.
   221  // Which means, all the items in <newSet> are in <set> and also in <other>.
   222  func (set *StringSet) Intersect(others ...*StringSet) (newSet *StringSet) {
   223  	newSet = NewStringSet(true)
   224  	set.mu.RLock()
   225  	defer set.mu.RUnlock()
   226  	for _, other := range others {
   227  		if set != other {
   228  			other.mu.RLock()
   229  		}
   230  		for k, v := range set.m {
   231  			if _, ok := other.m[k]; ok {
   232  				newSet.m[k] = v
   233  			}
   234  		}
   235  		if set != other {
   236  			other.mu.RUnlock()
   237  		}
   238  	}
   239  	return
   240  }
   241  
   242  // Complement returns a new set which is the complement from <set> to <full>.
   243  // Which means, all the items in <newSet> are in <full> and not in <set>.
   244  //
   245  // It returns the difference between <full> and <set>
   246  // if the given set <full> is not the full set of <set>.
   247  func (set *StringSet) Complement(full *StringSet) (newSet *StringSet) {
   248  	newSet = NewStringSet(true)
   249  	set.mu.RLock()
   250  	defer set.mu.RUnlock()
   251  	if set != full {
   252  		full.mu.RLock()
   253  		defer full.mu.RUnlock()
   254  	}
   255  	for k, v := range full.m {
   256  		if _, ok := set.m[k]; !ok {
   257  			newSet.m[k] = v
   258  		}
   259  	}
   260  	return
   261  }
   262  
   263  // Merge adds items from <others> sets into <set>.
   264  func (set *StringSet) Merge(others ...*StringSet) *StringSet {
   265  	set.mu.Lock()
   266  	defer set.mu.Unlock()
   267  	for _, other := range others {
   268  		if set != other {
   269  			other.mu.RLock()
   270  		}
   271  		for k, v := range other.m {
   272  			set.m[k] = v
   273  		}
   274  		if set != other {
   275  			other.mu.RUnlock()
   276  		}
   277  	}
   278  	return set
   279  }
   280  
   281  // Sum sums items.
   282  // Note: The items should be converted to int type,
   283  // or you'd get a result that you unexpected.
   284  func (set *StringSet) Sum() (sum int) {
   285  	set.mu.RLock()
   286  	defer set.mu.RUnlock()
   287  	for k, _ := range set.m {
   288  		sum += gconv.Int(k)
   289  	}
   290  	return
   291  }
   292  
   293  // Pops randomly pops an item from set.
   294  func (set *StringSet) Pop(size int) string {
   295  	set.mu.RLock()
   296  	defer set.mu.RUnlock()
   297  	for k, _ := range set.m {
   298  		return k
   299  	}
   300  	return ""
   301  }
   302  
   303  // Pops randomly pops <size> items from set.
   304  func (set *StringSet) Pops(size int) []string {
   305  	set.mu.RLock()
   306  	defer set.mu.RUnlock()
   307  	if size > len(set.m) {
   308  		size = len(set.m)
   309  	}
   310  	index := 0
   311  	array := make([]string, size)
   312  	for k, _ := range set.m {
   313  		array[index] = k
   314  		index++
   315  		if index == size {
   316  			break
   317  		}
   318  	}
   319  	return array
   320  }