go.etcd.io/etcd@v3.3.27+incompatible/pkg/types/set.go (about)

     1  // Copyright 2015 The etcd Authors
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //     http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  package types
    16  
    17  import (
    18  	"reflect"
    19  	"sort"
    20  	"sync"
    21  )
    22  
    23  type Set interface {
    24  	Add(string)
    25  	Remove(string)
    26  	Contains(string) bool
    27  	Equals(Set) bool
    28  	Length() int
    29  	Values() []string
    30  	Copy() Set
    31  	Sub(Set) Set
    32  }
    33  
    34  func NewUnsafeSet(values ...string) *unsafeSet {
    35  	set := &unsafeSet{make(map[string]struct{})}
    36  	for _, v := range values {
    37  		set.Add(v)
    38  	}
    39  	return set
    40  }
    41  
    42  func NewThreadsafeSet(values ...string) *tsafeSet {
    43  	us := NewUnsafeSet(values...)
    44  	return &tsafeSet{us, sync.RWMutex{}}
    45  }
    46  
    47  type unsafeSet struct {
    48  	d map[string]struct{}
    49  }
    50  
    51  // Add adds a new value to the set (no-op if the value is already present)
    52  func (us *unsafeSet) Add(value string) {
    53  	us.d[value] = struct{}{}
    54  }
    55  
    56  // Remove removes the given value from the set
    57  func (us *unsafeSet) Remove(value string) {
    58  	delete(us.d, value)
    59  }
    60  
    61  // Contains returns whether the set contains the given value
    62  func (us *unsafeSet) Contains(value string) (exists bool) {
    63  	_, exists = us.d[value]
    64  	return exists
    65  }
    66  
    67  // ContainsAll returns whether the set contains all given values
    68  func (us *unsafeSet) ContainsAll(values []string) bool {
    69  	for _, s := range values {
    70  		if !us.Contains(s) {
    71  			return false
    72  		}
    73  	}
    74  	return true
    75  }
    76  
    77  // Equals returns whether the contents of two sets are identical
    78  func (us *unsafeSet) Equals(other Set) bool {
    79  	v1 := sort.StringSlice(us.Values())
    80  	v2 := sort.StringSlice(other.Values())
    81  	v1.Sort()
    82  	v2.Sort()
    83  	return reflect.DeepEqual(v1, v2)
    84  }
    85  
    86  // Length returns the number of elements in the set
    87  func (us *unsafeSet) Length() int {
    88  	return len(us.d)
    89  }
    90  
    91  // Values returns the values of the Set in an unspecified order.
    92  func (us *unsafeSet) Values() (values []string) {
    93  	values = make([]string, 0)
    94  	for val := range us.d {
    95  		values = append(values, val)
    96  	}
    97  	return values
    98  }
    99  
   100  // Copy creates a new Set containing the values of the first
   101  func (us *unsafeSet) Copy() Set {
   102  	cp := NewUnsafeSet()
   103  	for val := range us.d {
   104  		cp.Add(val)
   105  	}
   106  
   107  	return cp
   108  }
   109  
   110  // Sub removes all elements in other from the set
   111  func (us *unsafeSet) Sub(other Set) Set {
   112  	oValues := other.Values()
   113  	result := us.Copy().(*unsafeSet)
   114  
   115  	for _, val := range oValues {
   116  		if _, ok := result.d[val]; !ok {
   117  			continue
   118  		}
   119  		delete(result.d, val)
   120  	}
   121  
   122  	return result
   123  }
   124  
   125  type tsafeSet struct {
   126  	us *unsafeSet
   127  	m  sync.RWMutex
   128  }
   129  
   130  func (ts *tsafeSet) Add(value string) {
   131  	ts.m.Lock()
   132  	defer ts.m.Unlock()
   133  	ts.us.Add(value)
   134  }
   135  
   136  func (ts *tsafeSet) Remove(value string) {
   137  	ts.m.Lock()
   138  	defer ts.m.Unlock()
   139  	ts.us.Remove(value)
   140  }
   141  
   142  func (ts *tsafeSet) Contains(value string) (exists bool) {
   143  	ts.m.RLock()
   144  	defer ts.m.RUnlock()
   145  	return ts.us.Contains(value)
   146  }
   147  
   148  func (ts *tsafeSet) Equals(other Set) bool {
   149  	ts.m.RLock()
   150  	defer ts.m.RUnlock()
   151  	return ts.us.Equals(other)
   152  }
   153  
   154  func (ts *tsafeSet) Length() int {
   155  	ts.m.RLock()
   156  	defer ts.m.RUnlock()
   157  	return ts.us.Length()
   158  }
   159  
   160  func (ts *tsafeSet) Values() (values []string) {
   161  	ts.m.RLock()
   162  	defer ts.m.RUnlock()
   163  	return ts.us.Values()
   164  }
   165  
   166  func (ts *tsafeSet) Copy() Set {
   167  	ts.m.RLock()
   168  	defer ts.m.RUnlock()
   169  	usResult := ts.us.Copy().(*unsafeSet)
   170  	return &tsafeSet{usResult, sync.RWMutex{}}
   171  }
   172  
   173  func (ts *tsafeSet) Sub(other Set) Set {
   174  	ts.m.RLock()
   175  	defer ts.m.RUnlock()
   176  	usResult := ts.us.Sub(other).(*unsafeSet)
   177  	return &tsafeSet{usResult, sync.RWMutex{}}
   178  }