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