github.com/lingyao2333/mo-zero@v1.4.1/core/collection/set.go (about)

     1  package collection
     2  
     3  import (
     4  	"github.com/lingyao2333/mo-zero/core/lang"
     5  	"github.com/lingyao2333/mo-zero/core/logx"
     6  )
     7  
     8  const (
     9  	unmanaged = iota
    10  	untyped
    11  	intType
    12  	int64Type
    13  	uintType
    14  	uint64Type
    15  	stringType
    16  )
    17  
    18  // Set is not thread-safe, for concurrent use, make sure to use it with synchronization.
    19  type Set struct {
    20  	data map[interface{}]lang.PlaceholderType
    21  	tp   int
    22  }
    23  
    24  // NewSet returns a managed Set, can only put the values with the same type.
    25  func NewSet() *Set {
    26  	return &Set{
    27  		data: make(map[interface{}]lang.PlaceholderType),
    28  		tp:   untyped,
    29  	}
    30  }
    31  
    32  // NewUnmanagedSet returns an unmanaged Set, which can put values with different types.
    33  func NewUnmanagedSet() *Set {
    34  	return &Set{
    35  		data: make(map[interface{}]lang.PlaceholderType),
    36  		tp:   unmanaged,
    37  	}
    38  }
    39  
    40  // Add adds i into s.
    41  func (s *Set) Add(i ...interface{}) {
    42  	for _, each := range i {
    43  		s.add(each)
    44  	}
    45  }
    46  
    47  // AddInt adds int values ii into s.
    48  func (s *Set) AddInt(ii ...int) {
    49  	for _, each := range ii {
    50  		s.add(each)
    51  	}
    52  }
    53  
    54  // AddInt64 adds int64 values ii into s.
    55  func (s *Set) AddInt64(ii ...int64) {
    56  	for _, each := range ii {
    57  		s.add(each)
    58  	}
    59  }
    60  
    61  // AddUint adds uint values ii into s.
    62  func (s *Set) AddUint(ii ...uint) {
    63  	for _, each := range ii {
    64  		s.add(each)
    65  	}
    66  }
    67  
    68  // AddUint64 adds uint64 values ii into s.
    69  func (s *Set) AddUint64(ii ...uint64) {
    70  	for _, each := range ii {
    71  		s.add(each)
    72  	}
    73  }
    74  
    75  // AddStr adds string values ss into s.
    76  func (s *Set) AddStr(ss ...string) {
    77  	for _, each := range ss {
    78  		s.add(each)
    79  	}
    80  }
    81  
    82  // Contains checks if i is in s.
    83  func (s *Set) Contains(i interface{}) bool {
    84  	if len(s.data) == 0 {
    85  		return false
    86  	}
    87  
    88  	s.validate(i)
    89  	_, ok := s.data[i]
    90  	return ok
    91  }
    92  
    93  // Keys returns the keys in s.
    94  func (s *Set) Keys() []interface{} {
    95  	var keys []interface{}
    96  
    97  	for key := range s.data {
    98  		keys = append(keys, key)
    99  	}
   100  
   101  	return keys
   102  }
   103  
   104  // KeysInt returns the int keys in s.
   105  func (s *Set) KeysInt() []int {
   106  	var keys []int
   107  
   108  	for key := range s.data {
   109  		if intKey, ok := key.(int); ok {
   110  			keys = append(keys, intKey)
   111  		}
   112  	}
   113  
   114  	return keys
   115  }
   116  
   117  // KeysInt64 returns int64 keys in s.
   118  func (s *Set) KeysInt64() []int64 {
   119  	var keys []int64
   120  
   121  	for key := range s.data {
   122  		if intKey, ok := key.(int64); ok {
   123  			keys = append(keys, intKey)
   124  		}
   125  	}
   126  
   127  	return keys
   128  }
   129  
   130  // KeysUint returns uint keys in s.
   131  func (s *Set) KeysUint() []uint {
   132  	var keys []uint
   133  
   134  	for key := range s.data {
   135  		if intKey, ok := key.(uint); ok {
   136  			keys = append(keys, intKey)
   137  		}
   138  	}
   139  
   140  	return keys
   141  }
   142  
   143  // KeysUint64 returns uint64 keys in s.
   144  func (s *Set) KeysUint64() []uint64 {
   145  	var keys []uint64
   146  
   147  	for key := range s.data {
   148  		if intKey, ok := key.(uint64); ok {
   149  			keys = append(keys, intKey)
   150  		}
   151  	}
   152  
   153  	return keys
   154  }
   155  
   156  // KeysStr returns string keys in s.
   157  func (s *Set) KeysStr() []string {
   158  	var keys []string
   159  
   160  	for key := range s.data {
   161  		if strKey, ok := key.(string); ok {
   162  			keys = append(keys, strKey)
   163  		}
   164  	}
   165  
   166  	return keys
   167  }
   168  
   169  // Remove removes i from s.
   170  func (s *Set) Remove(i interface{}) {
   171  	s.validate(i)
   172  	delete(s.data, i)
   173  }
   174  
   175  // Count returns the number of items in s.
   176  func (s *Set) Count() int {
   177  	return len(s.data)
   178  }
   179  
   180  func (s *Set) add(i interface{}) {
   181  	switch s.tp {
   182  	case unmanaged:
   183  		// do nothing
   184  	case untyped:
   185  		s.setType(i)
   186  	default:
   187  		s.validate(i)
   188  	}
   189  	s.data[i] = lang.Placeholder
   190  }
   191  
   192  func (s *Set) setType(i interface{}) {
   193  	// s.tp can only be untyped here
   194  	switch i.(type) {
   195  	case int:
   196  		s.tp = intType
   197  	case int64:
   198  		s.tp = int64Type
   199  	case uint:
   200  		s.tp = uintType
   201  	case uint64:
   202  		s.tp = uint64Type
   203  	case string:
   204  		s.tp = stringType
   205  	}
   206  }
   207  
   208  func (s *Set) validate(i interface{}) {
   209  	if s.tp == unmanaged {
   210  		return
   211  	}
   212  
   213  	switch i.(type) {
   214  	case int:
   215  		if s.tp != intType {
   216  			logx.Errorf("Error: element is int, but set contains elements with type %d", s.tp)
   217  		}
   218  	case int64:
   219  		if s.tp != int64Type {
   220  			logx.Errorf("Error: element is int64, but set contains elements with type %d", s.tp)
   221  		}
   222  	case uint:
   223  		if s.tp != uintType {
   224  			logx.Errorf("Error: element is uint, but set contains elements with type %d", s.tp)
   225  		}
   226  	case uint64:
   227  		if s.tp != uint64Type {
   228  			logx.Errorf("Error: element is uint64, but set contains elements with type %d", s.tp)
   229  		}
   230  	case string:
   231  		if s.tp != stringType {
   232  			logx.Errorf("Error: element is string, but set contains elements with type %d", s.tp)
   233  		}
   234  	}
   235  }