go.ligato.io/vpp-agent/v3@v3.5.0/plugins/kvscheduler/internal/utils/keyset.go (about)

     1  // Copyright (c) 2018 Cisco and/or its affiliates.
     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 utils
    16  
    17  import (
    18  	"encoding/json"
    19  	"sort"
    20  	"strings"
    21  )
    22  
    23  // KeySet defines API for a set of keys.
    24  type KeySet interface {
    25  	// String return human-readable string representation of the key-set.
    26  	String() string
    27  
    28  	// Iterate exposes the set of keys as slice which can be iterated through.
    29  	// The returned slice should not be modified.
    30  	Iterate() []string
    31  
    32  	// Length returns the number of keys in the set.
    33  	Length() int
    34  
    35  	// Equals compares this set with <set2> for equality.
    36  	Equals(set2 KeySet) bool
    37  
    38  	// Has returns true if the given key is in the set.
    39  	Has(key string) bool
    40  
    41  	// Add adds key into the set.
    42  	Add(key string) (changed bool)
    43  
    44  	// Del removes key from the set.
    45  	Del(key string) (changed bool)
    46  
    47  	// Subtract removes keys from this set which are also in <ks2>.
    48  	Subtract(ks2 KeySet) (changed bool)
    49  
    50  	// Intersect removes keys from this set which are not in <ks2>.
    51  	Intersect(ks2 KeySet) (changed bool)
    52  
    53  	// CopyOnWrite returns first a shallow copy of the key set, which gets
    54  	// deep-copied when it is about to get modified.
    55  	CopyOnWrite() KeySet
    56  }
    57  
    58  /****************************** Singleton KeySet  ******************************/
    59  
    60  // singletonKeySet is the KeySet implementation for set which is guaranteed to
    61  // contain at most one key.
    62  type singletonKeySet struct {
    63  	set [1]string // empty string = empty set
    64  }
    65  
    66  // NewSingletonKeySet returns KeySet implementation for at most one key.
    67  func NewSingletonKeySet(key string) KeySet {
    68  	s := &singletonKeySet{}
    69  	s.set[0] = key
    70  	return s
    71  }
    72  
    73  // String return human-readable string representation of the key-set.
    74  func (s *singletonKeySet) String() string {
    75  	if s == nil {
    76  		return "{}"
    77  	}
    78  	return "{" + s.set[0] + "}"
    79  }
    80  
    81  // Iterate exposes the set of keys as slice which can be iterated through.
    82  // The returned slice should not be modified.
    83  func (s *singletonKeySet) Iterate() []string {
    84  	if s == nil {
    85  		return nil
    86  	}
    87  	return s.set[:s.Length()]
    88  }
    89  
    90  // Length returns the number of keys in the set.
    91  func (s *singletonKeySet) Length() int {
    92  	if s == nil {
    93  		return 0
    94  	}
    95  	if s.set[0] == "" {
    96  		return 0
    97  	}
    98  	return 1
    99  }
   100  
   101  // Equals compares this set with <set2> for equality.
   102  func (s *singletonKeySet) Equals(set2 KeySet) bool {
   103  	if s.Length() != set2.Length() {
   104  		return false
   105  	}
   106  	for _, elem := range s.Iterate() {
   107  		if !set2.Has(elem) {
   108  			return false
   109  		}
   110  	}
   111  	return true
   112  }
   113  
   114  // Has returns true if the given key is in the set.
   115  func (s *singletonKeySet) Has(key string) bool {
   116  	if s == nil {
   117  		return false
   118  	}
   119  	if s.set[0] == key {
   120  		return true
   121  	}
   122  	return false
   123  }
   124  
   125  // Add adds key into the set.
   126  func (s *singletonKeySet) Add(key string) (changed bool) {
   127  	if s.set[0] == key {
   128  		return false
   129  	}
   130  	s.set[0] = key
   131  	return true
   132  }
   133  
   134  // Del removes key from the set.
   135  func (s *singletonKeySet) Del(key string) (changed bool) {
   136  	if s.set[0] == key {
   137  		s.set[0] = ""
   138  		return true
   139  	}
   140  	return false
   141  }
   142  
   143  // Subtract removes keys from this set which are also in <ks2>.
   144  func (s *singletonKeySet) Subtract(ks2 KeySet) (changed bool) {
   145  	if s.set[0] == "" {
   146  		return false
   147  	}
   148  	if ks2.Has(s.set[0]) {
   149  		s.set[0] = ""
   150  		return true
   151  	}
   152  	return false
   153  }
   154  
   155  // Intersect removes keys from this set which are not in <ks2>.
   156  func (s *singletonKeySet) Intersect(ks2 KeySet) (changed bool) {
   157  	if s.set[0] == "" {
   158  		return false
   159  	}
   160  	if !ks2.Has(s.set[0]) {
   161  		s.set[0] = ""
   162  		return true
   163  	}
   164  	return false
   165  }
   166  
   167  // CopyOnWrite actually returns a deep copy, but that is super cheap for singleton.
   168  func (s *singletonKeySet) CopyOnWrite() KeySet {
   169  	return &singletonKeySet{set: s.set}
   170  }
   171  
   172  // MarshalJSON marshalls the set into JSON.
   173  func (s *singletonKeySet) MarshalJSON() ([]byte, error) {
   174  	if s.set[0] == "" {
   175  		return []byte("[]"), nil
   176  	}
   177  	return []byte("[\"" + s.set[0] + "\"]"), nil
   178  }
   179  
   180  /***************************** KeySet based on map *****************************/
   181  
   182  // mapKeySet implements KeySet using a map.
   183  // Quicker lookups in average than the slice-based implementation, but bigger
   184  // memory footprint and much slower copying.
   185  type mapKeySet struct {
   186  	shallowCopy bool
   187  	set         mapWithKeys
   188  	iter        []string
   189  	iterInSync  bool
   190  }
   191  
   192  // mapWithKeys is used to represent a set of keys using a map with empty values.
   193  type mapWithKeys map[string]struct{}
   194  
   195  // NewMapBasedKeySet returns KeySet implemented using map.
   196  func NewMapBasedKeySet(keys ...string) KeySet {
   197  	s := &mapKeySet{
   198  		set:        make(mapWithKeys),
   199  		iter:       []string{},
   200  		iterInSync: true,
   201  	}
   202  	for _, key := range keys {
   203  		s.Add(key)
   204  	}
   205  	return s
   206  }
   207  
   208  // String return human-readable string representation of the key-set.
   209  func (s *mapKeySet) String() string {
   210  	return s.string(false)
   211  }
   212  
   213  // string return human-readable string representation of the key-set.
   214  func (s *mapKeySet) string(json bool) string {
   215  	if s == nil {
   216  		if json {
   217  			return "[]"
   218  		}
   219  		return "{}"
   220  	}
   221  	str := "{"
   222  	if json {
   223  		str = "["
   224  	}
   225  	idx := 0
   226  	for key := range s.set {
   227  		if json {
   228  			str += "\"" + key + "\""
   229  		} else {
   230  			str += key
   231  		}
   232  		if idx < len(s.set)-1 {
   233  			str += ", "
   234  		}
   235  		idx++
   236  	}
   237  	if json {
   238  		str += "]"
   239  	} else {
   240  		str += "}"
   241  	}
   242  	return str
   243  }
   244  
   245  // Iterate exposes the set of keys as slice which can be iterated through.
   246  // The returned slice should not be modified.
   247  func (s *mapKeySet) Iterate() (keys []string) {
   248  	if s == nil {
   249  		return keys
   250  	}
   251  	if s.iterInSync {
   252  		return s.iter
   253  	}
   254  	s.iter = make([]string, len(s.set))
   255  	i := 0
   256  	for key := range s.set {
   257  		s.iter[i] = key
   258  		i++
   259  	}
   260  	s.iterInSync = true
   261  	return s.iter
   262  }
   263  
   264  // Length returns the number of keys in the set.
   265  func (s *mapKeySet) Length() int {
   266  	if s == nil {
   267  		return 0
   268  	}
   269  	return len(s.set)
   270  }
   271  
   272  // Equals compares this set with <set2> for equality.
   273  func (s *mapKeySet) Equals(set2 KeySet) bool {
   274  	if s.Length() != set2.Length() {
   275  		return false
   276  	}
   277  	for elem := range s.set {
   278  		if !set2.Has(elem) {
   279  			return false
   280  		}
   281  	}
   282  	return true
   283  }
   284  
   285  // Has returns true if the given key is in the set.
   286  func (s *mapKeySet) Has(key string) bool {
   287  	if s == nil {
   288  		return false
   289  	}
   290  	_, has := s.set[key]
   291  	return has
   292  }
   293  
   294  // Add adds key into the set.
   295  func (s *mapKeySet) Add(key string) (changed bool) {
   296  	if !s.Has(key) {
   297  		if s.shallowCopy {
   298  			s.set = s.deepCopyMap()
   299  			s.shallowCopy = false
   300  		}
   301  		s.set[key] = struct{}{}
   302  		if s.iterInSync {
   303  			s.iter = append(s.iter, key)
   304  		}
   305  		changed = true
   306  	}
   307  	return
   308  }
   309  
   310  // Del removes key from the set.
   311  func (s *mapKeySet) Del(key string) (changed bool) {
   312  	if s.Has(key) {
   313  		if s.shallowCopy {
   314  			s.set = s.deepCopyMap()
   315  			s.shallowCopy = false
   316  		}
   317  		delete(s.set, key)
   318  		s.iterInSync = false
   319  		changed = true
   320  	}
   321  	return
   322  }
   323  
   324  // Subtract removes keys from this set which are also in <ks2>.
   325  func (s *mapKeySet) Subtract(ks2 KeySet) (changed bool) {
   326  	for _, key := range ks2.Iterate() {
   327  		if s.Del(key) {
   328  			changed = true
   329  		}
   330  	}
   331  	return
   332  }
   333  
   334  // Intersect removes keys from this set which are not in <ks2>.
   335  func (s *mapKeySet) Intersect(ks2 KeySet) (changed bool) {
   336  	for key := range s.set {
   337  		if !ks2.Has(key) {
   338  			s.Del(key)
   339  			changed = true
   340  		}
   341  	}
   342  	return
   343  }
   344  
   345  // CopyOnWrite returns first a shallow copy of this key set, which gets deep-copied
   346  // when it is about to get modified.
   347  func (s *mapKeySet) CopyOnWrite() KeySet {
   348  	return &mapKeySet{
   349  		shallowCopy: true,
   350  		set:         s.set,
   351  	}
   352  }
   353  
   354  // deepCopyMap returns a deep-copy of the internal map representing the key set.
   355  func (s *mapKeySet) deepCopyMap() mapWithKeys {
   356  	c := make(mapWithKeys, len(s.set))
   357  	for key := range s.set {
   358  		c[key] = struct{}{}
   359  	}
   360  	return c
   361  }
   362  
   363  // MarshalJSON marshalls the set into JSON.
   364  func (s *mapKeySet) MarshalJSON() ([]byte, error) {
   365  	return []byte(s.string(true)), nil
   366  }
   367  
   368  /**************************** KeySet based on slice ****************************/
   369  
   370  // sliceKeySet implements KeySet using a slice with ordered keys.
   371  // The main advantage over the map-based implementation, is much smaller
   372  // memory footprint and quick (deep-)copying.
   373  type sliceKeySet struct {
   374  	shallowCopy bool
   375  	set         []string
   376  	length      int // len(set) can be > than length - the rest are empty strings
   377  }
   378  
   379  // NewSliceBasedKeySet returns KeySet implemented using a slice with ordered keys.
   380  func NewSliceBasedKeySet(keys ...string) KeySet {
   381  	s := &sliceKeySet{set: []string{}}
   382  	for _, key := range keys {
   383  		s.Add(key)
   384  	}
   385  	return s
   386  }
   387  
   388  // String return human-readable string representation of the key-set.
   389  func (s *sliceKeySet) String() string {
   390  	if s == nil {
   391  		return "{}"
   392  	}
   393  	return "{" + strings.Join(s.set[:s.length], ", ") + "}"
   394  }
   395  
   396  // Iterate exposes the set of keys as slice which can be iterated through.
   397  // The returned slice should not be modified.
   398  func (s *sliceKeySet) Iterate() (keys []string) {
   399  	if s == nil {
   400  		return keys
   401  	}
   402  	return s.set[:s.length]
   403  }
   404  
   405  // Length returns the number of keys in the set.
   406  func (s *sliceKeySet) Length() int {
   407  	if s == nil {
   408  		return 0
   409  	}
   410  	return s.length
   411  }
   412  
   413  // Equals compares this set with <set2> for equality.
   414  func (s *sliceKeySet) Equals(set2 KeySet) bool {
   415  	if s.Length() != set2.Length() {
   416  		return false
   417  	}
   418  	set2Slice, isSlice := set2.(*sliceKeySet)
   419  	if isSlice {
   420  		for i := 0; i < s.length; i++ {
   421  			if s.set[i] != set2Slice.set[i] {
   422  				return false
   423  			}
   424  		}
   425  	} else {
   426  		for _, elem := range s.Iterate() {
   427  			if !set2.Has(elem) {
   428  				return false
   429  			}
   430  		}
   431  	}
   432  	return true
   433  }
   434  
   435  // Has returns true if the given key is in the set.
   436  func (s *sliceKeySet) Has(key string) bool {
   437  	if s == nil {
   438  		return false
   439  	}
   440  	_, exists := s.getKeyIndex(key)
   441  	return exists
   442  }
   443  
   444  // Add adds key into the set.
   445  func (s *sliceKeySet) Add(key string) (changed bool) {
   446  	idx, exists := s.getKeyIndex(key)
   447  	if !exists {
   448  		if s.shallowCopy {
   449  			s.set = s.deepCopySlice()
   450  			s.shallowCopy = false
   451  		}
   452  		if s.length == len(s.set) {
   453  			// increase capacity
   454  			s.set = append(s.set, "")
   455  		}
   456  		if idx < s.length {
   457  			copy(s.set[idx+1:], s.set[idx:])
   458  		}
   459  		s.set[idx] = key
   460  		s.length++
   461  		changed = true
   462  	}
   463  	return
   464  }
   465  
   466  // Del removes key from the set.
   467  func (s *sliceKeySet) Del(key string) (changed bool) {
   468  	idx, exists := s.getKeyIndex(key)
   469  	if exists {
   470  		if s.shallowCopy {
   471  			s.set = s.deepCopySlice()
   472  			s.shallowCopy = false
   473  		}
   474  		if idx < s.length-1 {
   475  			copy(s.set[idx:], s.set[idx+1:])
   476  		}
   477  		s.length--
   478  		s.set[s.length] = ""
   479  		changed = true
   480  	}
   481  	return
   482  }
   483  
   484  // Subtract removes keys from this set which are also in <ks2>.
   485  func (s *sliceKeySet) Subtract(ks2 KeySet) (changed bool) {
   486  	s2, isSliceKeySet := ks2.(*sliceKeySet)
   487  	if isSliceKeySet {
   488  		// optimized case when both are slice-based
   489  		var i, j, newLen int
   490  		for ; i < s.length; i++ {
   491  			subtract := false
   492  			for ; j < s2.length; j++ {
   493  				if s.set[i] > s2.set[j] {
   494  					continue
   495  				}
   496  				if s.set[i] == s2.set[j] {
   497  					subtract = true
   498  				} else {
   499  					break
   500  				}
   501  			}
   502  			if subtract {
   503  				if s.shallowCopy {
   504  					s.set = s.deepCopySlice()
   505  					s.shallowCopy = false
   506  				}
   507  				changed = true
   508  			}
   509  			if !subtract {
   510  				if newLen != i {
   511  					s.set[newLen] = s.set[i]
   512  				}
   513  				newLen++
   514  			}
   515  		}
   516  		if newLen != s.length {
   517  			s.length = newLen
   518  		}
   519  		return
   520  	}
   521  	for _, key := range ks2.Iterate() {
   522  		if s.Del(key) {
   523  			changed = true
   524  		}
   525  	}
   526  	return
   527  }
   528  
   529  // Intersect removes keys from this set which are not in <ks2>.
   530  func (s *sliceKeySet) Intersect(ks2 KeySet) (changed bool) {
   531  	for i := 0; i < s.length; {
   532  		key := s.set[i]
   533  		if !ks2.Has(key) {
   534  			s.Del(key)
   535  			changed = true
   536  		} else {
   537  			i++
   538  		}
   539  	}
   540  	return
   541  }
   542  
   543  // CopyOnWrite returns first a shallow copy of this key set, which gets deep-copied
   544  // when it is about to get modified.
   545  func (s *sliceKeySet) CopyOnWrite() KeySet {
   546  	return &sliceKeySet{
   547  		shallowCopy: true,
   548  		set:         s.set,
   549  		length:      s.length,
   550  	}
   551  }
   552  
   553  // getKeyIndex returns index at which the given key would be stored.
   554  func (s *sliceKeySet) getKeyIndex(key string) (idx int, exists bool) {
   555  	if s.length <= 5 {
   556  		for idx = 0; idx < s.length; idx++ {
   557  			if key <= s.set[idx] {
   558  				break
   559  			}
   560  		}
   561  	} else {
   562  		idx = sort.Search(s.length,
   563  			func(i int) bool {
   564  				return key <= s.set[i]
   565  			})
   566  	}
   567  	return idx, idx < s.length && key == s.set[idx]
   568  }
   569  
   570  // deepCopyMap returns a deep-copy of the internal slice representing the key set.
   571  func (s *sliceKeySet) deepCopySlice() []string {
   572  	c := make([]string, s.length)
   573  	copy(c, s.set)
   574  	return c
   575  }
   576  
   577  // MarshalJSON marshalls the set into JSON.
   578  func (s *sliceKeySet) MarshalJSON() ([]byte, error) {
   579  	return json.Marshal(s.set[:s.length])
   580  }