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