github.com/x-oss-byte/git-lfs@v2.5.2+incompatible/tools/ordered_set.go (about)

     1  package tools
     2  
     3  // OrderedSet is a unique set of strings that maintains insertion order.
     4  type OrderedSet struct {
     5  	// s is the set of strings that we're keeping track of.
     6  	s []string
     7  	// m is a mapping of string value "s" into the index "i" that that
     8  	// string is present in in the given "s".
     9  	m map[string]int
    10  }
    11  
    12  // NewOrderedSet creates an ordered set with no values.
    13  func NewOrderedSet() *OrderedSet {
    14  	return NewOrderedSetWithCapacity(0)
    15  }
    16  
    17  // NewOrderedSetWithCapacity creates a new ordered set with no values. The
    18  // returned ordered set can be appended to "capacity" number of times before it
    19  // grows internally.
    20  func NewOrderedSetWithCapacity(capacity int) *OrderedSet {
    21  	return &OrderedSet{
    22  		s: make([]string, 0, capacity),
    23  		m: make(map[string]int, capacity),
    24  	}
    25  }
    26  
    27  // NewOrderedSetFromSlice returns a new ordered set with the elements given in
    28  // the slice "s".
    29  func NewOrderedSetFromSlice(s []string) *OrderedSet {
    30  	set := NewOrderedSetWithCapacity(len(s))
    31  	for _, e := range s {
    32  		set.Add(e)
    33  	}
    34  
    35  	return set
    36  }
    37  
    38  // Add adds the given element "i" to the ordered set, unless the element is
    39  // already present. It returns whether or not the element was added.
    40  func (s *OrderedSet) Add(i string) bool {
    41  	if _, ok := s.m[i]; ok {
    42  		return false
    43  	}
    44  
    45  	s.s = append(s.s, i)
    46  	s.m[i] = len(s.s) - 1
    47  
    48  	return true
    49  }
    50  
    51  // Contains returns whether or not the given "i" is contained in this ordered
    52  // set. It is a constant-time operation.
    53  func (s *OrderedSet) Contains(i string) bool {
    54  	if _, ok := s.m[i]; ok {
    55  		return true
    56  	}
    57  	return false
    58  }
    59  
    60  // ContainsAll returns whether or not all of the given items in "i" are present
    61  // in the ordered set.
    62  func (s *OrderedSet) ContainsAll(i ...string) bool {
    63  	for _, item := range i {
    64  		if !s.Contains(item) {
    65  			return false
    66  		}
    67  	}
    68  	return true
    69  }
    70  
    71  // IsSubset returns whether other is a subset of this ordered set. In other
    72  // words, it returns whether or not all of the elements in "other" are also
    73  // present in this set.
    74  func (s *OrderedSet) IsSubset(other *OrderedSet) bool {
    75  	for _, i := range other.s {
    76  		if !s.Contains(i) {
    77  			return false
    78  		}
    79  	}
    80  	return true
    81  }
    82  
    83  // IsSuperset returns whether or not this set is a superset of "other". In other
    84  // words, it returns whether or not all of the elements in this set are also in
    85  // the set "other".
    86  func (s *OrderedSet) IsSuperset(other *OrderedSet) bool {
    87  	return other.IsSubset(s)
    88  }
    89  
    90  // Union returns a union of this set with the given set "other". It returns the
    91  // items that are in either set while maintaining uniqueness constraints. It
    92  // preserves ordered within each set, and orders the elements in this set before
    93  // the elements in "other".
    94  //
    95  // It is an O(n+m) operation.
    96  func (s *OrderedSet) Union(other *OrderedSet) *OrderedSet {
    97  	union := NewOrderedSetWithCapacity(other.Cardinality() + s.Cardinality())
    98  
    99  	for _, e := range s.s {
   100  		union.Add(e)
   101  	}
   102  	for _, e := range other.s {
   103  		union.Add(e)
   104  	}
   105  
   106  	return union
   107  }
   108  
   109  // Intersect returns the elements that are in both this set and then given
   110  // "ordered" set. It is an O(min(n, m)) (in other words, O(n)) operation.
   111  func (s *OrderedSet) Intersect(other *OrderedSet) *OrderedSet {
   112  	intersection := NewOrderedSetWithCapacity(MinInt(
   113  		s.Cardinality(), other.Cardinality()))
   114  
   115  	if s.Cardinality() < other.Cardinality() {
   116  		for _, elem := range s.s {
   117  			if other.Contains(elem) {
   118  				intersection.Add(elem)
   119  			}
   120  		}
   121  	} else {
   122  		for _, elem := range other.s {
   123  			if s.Contains(elem) {
   124  				intersection.Add(elem)
   125  			}
   126  		}
   127  	}
   128  
   129  	return intersection
   130  }
   131  
   132  // Difference returns the elements that are in this set, but not included in
   133  // other.
   134  func (s *OrderedSet) Difference(other *OrderedSet) *OrderedSet {
   135  	diff := NewOrderedSetWithCapacity(s.Cardinality())
   136  	for _, e := range s.s {
   137  		if !other.Contains(e) {
   138  			diff.Add(e)
   139  		}
   140  	}
   141  
   142  	return diff
   143  }
   144  
   145  // SymmetricDifference returns the elements that are not present in both sets.
   146  func (s *OrderedSet) SymmetricDifference(other *OrderedSet) *OrderedSet {
   147  	left := s.Difference(other)
   148  	right := other.Difference(s)
   149  
   150  	return left.Union(right)
   151  }
   152  
   153  // Clear removes all elements from this set.
   154  func (s *OrderedSet) Clear() {
   155  	s.s = make([]string, 0)
   156  	s.m = make(map[string]int, 0)
   157  }
   158  
   159  // Remove removes the given element "i" from this set.
   160  func (s *OrderedSet) Remove(i string) {
   161  	idx, ok := s.m[i]
   162  	if !ok {
   163  		return
   164  	}
   165  
   166  	rest := MinInt(idx+1, len(s.s)-1)
   167  
   168  	s.s = append(s.s[:idx], s.s[rest:]...)
   169  	for _, e := range s.s[rest:] {
   170  		s.m[e] = s.m[e] - 1
   171  	}
   172  	delete(s.m, i)
   173  }
   174  
   175  // Cardinality returns the cardinality of this set.
   176  func (s *OrderedSet) Cardinality() int {
   177  	return len(s.s)
   178  }
   179  
   180  // Iter returns a channel which yields the elements in this set in insertion
   181  // order.
   182  func (s *OrderedSet) Iter() <-chan string {
   183  	c := make(chan string)
   184  	go func() {
   185  		for _, i := range s.s {
   186  			c <- i
   187  		}
   188  		close(c)
   189  	}()
   190  
   191  	return c
   192  }
   193  
   194  // Equal returns whether this element has the same number, identity and ordering
   195  // elements as given in "other".
   196  func (s *OrderedSet) Equal(other *OrderedSet) bool {
   197  	if s.Cardinality() != other.Cardinality() {
   198  		return false
   199  	}
   200  
   201  	for e, i := range s.m {
   202  		if ci, ok := other.m[e]; !ok || ci != i {
   203  			return false
   204  		}
   205  	}
   206  
   207  	return true
   208  }
   209  
   210  // Clone returns a deep copy of this set.
   211  func (s *OrderedSet) Clone() *OrderedSet {
   212  	clone := NewOrderedSetWithCapacity(s.Cardinality())
   213  	for _, i := range s.s {
   214  		clone.Add(i)
   215  	}
   216  	return clone
   217  }