xref: /aosp_15_r20/external/licenseclassifier/internal/sets/stringset.go (revision 46c4c49da23cae783fa41bf46525a6505638499a)
1// Copyright 2017 Google Inc.
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.
14package sets
15
16import (
17	"fmt"
18	"sort"
19	"strings"
20)
21
22// StringSet stores a set of unique string elements.
23type StringSet struct {
24	set map[string]present
25}
26
27// NewStringSet creates a StringSet containing the supplied initial string elements.
28func NewStringSet(elements ...string) *StringSet {
29	s := &StringSet{}
30	s.set = make(map[string]present)
31	s.Insert(elements...)
32	return s
33}
34
35// Copy returns a newly allocated copy of the supplied StringSet.
36func (s *StringSet) Copy() *StringSet {
37	c := NewStringSet()
38	if s != nil {
39		for e := range s.set {
40			c.set[e] = present{}
41		}
42	}
43	return c
44}
45
46// Insert zero or more string elements into the StringSet.
47// As expected for a Set, elements already present in the StringSet are
48// simply ignored.
49func (s *StringSet) Insert(elements ...string) {
50	for _, e := range elements {
51		s.set[e] = present{}
52	}
53}
54
55// Delete zero or more string elements from the StringSet.
56// Any elements not present in the StringSet are simply ignored.
57func (s *StringSet) Delete(elements ...string) {
58	for _, e := range elements {
59		delete(s.set, e)
60	}
61}
62
63// Intersect returns a new StringSet containing the intersection of the
64// receiver and argument StringSets.  Returns an empty set if the argument is nil.
65func (s *StringSet) Intersect(other *StringSet) *StringSet {
66	if other == nil {
67		return NewStringSet()
68	}
69
70	// Point a and b to the maps, setting a to the smaller of the two.
71	a, b := s.set, other.set
72	if len(b) < len(a) {
73		a, b = b, a
74	}
75
76	// Perform the intersection.
77	intersect := NewStringSet()
78	for e := range a {
79		if _, ok := b[e]; ok {
80			intersect.set[e] = present{}
81		}
82	}
83	return intersect
84}
85
86// Disjoint returns true if the intersection of the receiver and the argument
87// StringSets is the empty set.  Returns true if the argument is nil or either
88// StringSet is the empty set.
89func (s *StringSet) Disjoint(other *StringSet) bool {
90	if other == nil || len(other.set) == 0 || len(s.set) == 0 {
91		return true
92	}
93
94	// Point a and b to the maps, setting a to the smaller of the two.
95	a, b := s.set, other.set
96	if len(b) < len(a) {
97		a, b = b, a
98	}
99
100	// Check for non-empty intersection.
101	for e := range a {
102		if _, ok := b[e]; ok {
103			return false // Early-exit because intersecting.
104		}
105	}
106	return true
107}
108
109// Difference returns a new StringSet containing the elements in the receiver
110// that are not present in the argument StringSet. Returns a copy of the
111// receiver if the argument is nil.
112func (s *StringSet) Difference(other *StringSet) *StringSet {
113	if other == nil {
114		return s.Copy()
115	}
116
117	// Insert only the elements in the receiver that are not present in the
118	// argument StringSet.
119	diff := NewStringSet()
120	for e := range s.set {
121		if _, ok := other.set[e]; !ok {
122			diff.set[e] = present{}
123		}
124	}
125	return diff
126}
127
128// Unique returns a new StringSet containing the elements in the receiver
129// that are not present in the argument StringSet *and* the elements in the
130// argument StringSet that are not in the receiver (which is the union of two
131// disjoint sets). Returns a copy of the
132// receiver if the argument is nil.
133func (s *StringSet) Unique(other *StringSet) *StringSet {
134	if other == nil {
135		return s.Copy()
136	}
137
138	sNotInOther := s.Difference(other)
139	otherNotInS := other.Difference(s)
140
141	// Duplicate Union implementation here to avoid extra Copy, since both
142	// sNotInOther and otherNotInS are already copies.
143	unique := sNotInOther
144	for e := range otherNotInS.set {
145		unique.set[e] = present{}
146	}
147	return unique
148}
149
150// Equal returns true if the receiver and the argument StringSet contain
151// exactly the same elements.
152func (s *StringSet) Equal(other *StringSet) bool {
153	if s == nil || other == nil {
154		return s == nil && other == nil
155	}
156
157	// Two sets of different length cannot have the exact same unique elements.
158	if len(s.set) != len(other.set) {
159		return false
160	}
161
162	// Only one loop is needed. If the two sets are known to be of equal
163	// length, then the two sets are equal only if exactly all of the elements
164	// in the first set are found in the second.
165	for e := range s.set {
166		if _, ok := other.set[e]; !ok {
167			return false
168		}
169	}
170
171	return true
172}
173
174// Union returns a new StringSet containing the union of the receiver and
175// argument StringSets.  Returns a copy of the receiver if the argument is nil.
176func (s *StringSet) Union(other *StringSet) *StringSet {
177	union := s.Copy()
178	if other != nil {
179		for e := range other.set {
180			union.set[e] = present{}
181		}
182	}
183	return union
184}
185
186// Contains returns true if element is in the StringSet.
187func (s *StringSet) Contains(element string) bool {
188	_, in := s.set[element]
189	return in
190}
191
192// Len returns the number of unique elements in the StringSet.
193func (s *StringSet) Len() int {
194	return len(s.set)
195}
196
197// Empty returns true if the receiver is the empty set.
198func (s *StringSet) Empty() bool {
199	return len(s.set) == 0
200}
201
202// Elements returns a []string of the elements in the StringSet, in no
203// particular (or consistent) order.
204func (s *StringSet) Elements() []string {
205	elements := []string{} // Return at least an empty slice rather than nil.
206	for e := range s.set {
207		elements = append(elements, e)
208	}
209	return elements
210}
211
212// Sorted returns a sorted []string of the elements in the StringSet.
213func (s *StringSet) Sorted() []string {
214	elements := s.Elements()
215	sort.Strings(elements)
216	return elements
217}
218
219// String formats the StringSet elements as sorted strings, representing them
220// in "array initializer" syntax.
221func (s *StringSet) String() string {
222	elements := s.Sorted()
223	var quoted []string
224	for _, e := range elements {
225		quoted = append(quoted, fmt.Sprintf("%q", e))
226	}
227	return fmt.Sprintf("{%s}", strings.Join(quoted, ", "))
228}
229