xref: /aosp_15_r20/external/bazel-skylib/lib/new_sets.bzl (revision bcb5dc7965af6ee42bf2f21341a2ec00233a8c8a)
1*bcb5dc79SHONG Yifan# Copyright 2018 The Bazel Authors. All rights reserved.
2*bcb5dc79SHONG Yifan#
3*bcb5dc79SHONG Yifan# Licensed under the Apache License, Version 2.0 (the "License");
4*bcb5dc79SHONG Yifan# you may not use this file except in compliance with the License.
5*bcb5dc79SHONG Yifan# You may obtain a copy of the License at
6*bcb5dc79SHONG Yifan#
7*bcb5dc79SHONG Yifan#    http://www.apache.org/licenses/LICENSE-2.0
8*bcb5dc79SHONG Yifan#
9*bcb5dc79SHONG Yifan# Unless required by applicable law or agreed to in writing, software
10*bcb5dc79SHONG Yifan# distributed under the License is distributed on an "AS IS" BASIS,
11*bcb5dc79SHONG Yifan# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12*bcb5dc79SHONG Yifan# See the License for the specific language governing permissions and
13*bcb5dc79SHONG Yifan# limitations under the License.
14*bcb5dc79SHONG Yifan
15*bcb5dc79SHONG Yifan"""Skylib module containing common hash-set algorithms.
16*bcb5dc79SHONG Yifan
17*bcb5dc79SHONG Yifan  An empty set can be created using: `sets.make()`, or it can be created with some starting values
18*bcb5dc79SHONG Yifan  if you pass it an sequence: `sets.make([1, 2, 3])`. This returns a struct containing all of the
19*bcb5dc79SHONG Yifan  values as keys in a dictionary - this means that all passed in values must be hashable.  The
20*bcb5dc79SHONG Yifan  values in the set can be retrieved using `sets.to_list(my_set)`.
21*bcb5dc79SHONG Yifan
22*bcb5dc79SHONG Yifan  An arbitrary object can be tested whether it is a set generated by `sets.make()` or not with the
23*bcb5dc79SHONG Yifan  `types.is_set()` method in types.bzl.
24*bcb5dc79SHONG Yifan"""
25*bcb5dc79SHONG Yifan
26*bcb5dc79SHONG Yifanload(":dicts.bzl", "dicts")
27*bcb5dc79SHONG Yifan
28*bcb5dc79SHONG Yifandef _make(elements = None):
29*bcb5dc79SHONG Yifan    """Creates a new set.
30*bcb5dc79SHONG Yifan
31*bcb5dc79SHONG Yifan    All elements must be hashable.
32*bcb5dc79SHONG Yifan
33*bcb5dc79SHONG Yifan    Args:
34*bcb5dc79SHONG Yifan      elements: Optional sequence to construct the set out of.
35*bcb5dc79SHONG Yifan
36*bcb5dc79SHONG Yifan    Returns:
37*bcb5dc79SHONG Yifan      A set containing the passed in values.
38*bcb5dc79SHONG Yifan    """
39*bcb5dc79SHONG Yifan
40*bcb5dc79SHONG Yifan    # If you change the structure of a set, you need to also update the _is_set method
41*bcb5dc79SHONG Yifan    # in types.bzl.
42*bcb5dc79SHONG Yifan    elements = elements if elements else []
43*bcb5dc79SHONG Yifan    return struct(_values = {e: None for e in elements})
44*bcb5dc79SHONG Yifan
45*bcb5dc79SHONG Yifandef _copy(s):
46*bcb5dc79SHONG Yifan    """Creates a new set from another set.
47*bcb5dc79SHONG Yifan
48*bcb5dc79SHONG Yifan    Args:
49*bcb5dc79SHONG Yifan      s: A set, as returned by `sets.make()`.
50*bcb5dc79SHONG Yifan
51*bcb5dc79SHONG Yifan    Returns:
52*bcb5dc79SHONG Yifan      A new set containing the same elements as `s`.
53*bcb5dc79SHONG Yifan    """
54*bcb5dc79SHONG Yifan    return struct(_values = dict(s._values))
55*bcb5dc79SHONG Yifan
56*bcb5dc79SHONG Yifandef _to_list(s):
57*bcb5dc79SHONG Yifan    """Creates a list from the values in the set.
58*bcb5dc79SHONG Yifan
59*bcb5dc79SHONG Yifan    Args:
60*bcb5dc79SHONG Yifan      s: A set, as returned by `sets.make()`.
61*bcb5dc79SHONG Yifan
62*bcb5dc79SHONG Yifan    Returns:
63*bcb5dc79SHONG Yifan      A list of values inserted into the set.
64*bcb5dc79SHONG Yifan    """
65*bcb5dc79SHONG Yifan    return s._values.keys()
66*bcb5dc79SHONG Yifan
67*bcb5dc79SHONG Yifandef _insert(s, e):
68*bcb5dc79SHONG Yifan    """Inserts an element into the set.
69*bcb5dc79SHONG Yifan
70*bcb5dc79SHONG Yifan    Element must be hashable.  This mutates the original set.
71*bcb5dc79SHONG Yifan
72*bcb5dc79SHONG Yifan    Args:
73*bcb5dc79SHONG Yifan      s: A set, as returned by `sets.make()`.
74*bcb5dc79SHONG Yifan      e: The element to be inserted.
75*bcb5dc79SHONG Yifan
76*bcb5dc79SHONG Yifan    Returns:
77*bcb5dc79SHONG Yifan       The set `s` with `e` included.
78*bcb5dc79SHONG Yifan    """
79*bcb5dc79SHONG Yifan    s._values[e] = None
80*bcb5dc79SHONG Yifan    return s
81*bcb5dc79SHONG Yifan
82*bcb5dc79SHONG Yifandef _remove(s, e):
83*bcb5dc79SHONG Yifan    """Removes an element from the set.
84*bcb5dc79SHONG Yifan
85*bcb5dc79SHONG Yifan    Element must be hashable.  This mutates the original set.
86*bcb5dc79SHONG Yifan
87*bcb5dc79SHONG Yifan    Args:
88*bcb5dc79SHONG Yifan      s: A set, as returned by `sets.make()`.
89*bcb5dc79SHONG Yifan      e: The element to be removed.
90*bcb5dc79SHONG Yifan
91*bcb5dc79SHONG Yifan    Returns:
92*bcb5dc79SHONG Yifan       The set `s` with `e` removed.
93*bcb5dc79SHONG Yifan    """
94*bcb5dc79SHONG Yifan    s._values.pop(e)
95*bcb5dc79SHONG Yifan    return s
96*bcb5dc79SHONG Yifan
97*bcb5dc79SHONG Yifandef _contains(a, e):
98*bcb5dc79SHONG Yifan    """Checks for the existence of an element in a set.
99*bcb5dc79SHONG Yifan
100*bcb5dc79SHONG Yifan    Args:
101*bcb5dc79SHONG Yifan      a: A set, as returned by `sets.make()`.
102*bcb5dc79SHONG Yifan      e: The element to look for.
103*bcb5dc79SHONG Yifan
104*bcb5dc79SHONG Yifan    Returns:
105*bcb5dc79SHONG Yifan      True if the element exists in the set, False if the element does not.
106*bcb5dc79SHONG Yifan    """
107*bcb5dc79SHONG Yifan    return e in a._values
108*bcb5dc79SHONG Yifan
109*bcb5dc79SHONG Yifandef _get_shorter_and_longer(a, b):
110*bcb5dc79SHONG Yifan    """Returns two sets in the order of shortest and longest.
111*bcb5dc79SHONG Yifan
112*bcb5dc79SHONG Yifan    Args:
113*bcb5dc79SHONG Yifan      a: A set, as returned by `sets.make()`.
114*bcb5dc79SHONG Yifan      b: A set, as returned by `sets.make()`.
115*bcb5dc79SHONG Yifan
116*bcb5dc79SHONG Yifan    Returns:
117*bcb5dc79SHONG Yifan      `a`, `b` if `a` is shorter than `b` - or `b`, `a` if `b` is shorter than `a`.
118*bcb5dc79SHONG Yifan    """
119*bcb5dc79SHONG Yifan    if _length(a) < _length(b):
120*bcb5dc79SHONG Yifan        return a, b
121*bcb5dc79SHONG Yifan    return b, a
122*bcb5dc79SHONG Yifan
123*bcb5dc79SHONG Yifandef _is_equal(a, b):
124*bcb5dc79SHONG Yifan    """Returns whether two sets are equal.
125*bcb5dc79SHONG Yifan
126*bcb5dc79SHONG Yifan    Args:
127*bcb5dc79SHONG Yifan      a: A set, as returned by `sets.make()`.
128*bcb5dc79SHONG Yifan      b: A set, as returned by `sets.make()`.
129*bcb5dc79SHONG Yifan
130*bcb5dc79SHONG Yifan    Returns:
131*bcb5dc79SHONG Yifan      True if `a` is equal to `b`, False otherwise.
132*bcb5dc79SHONG Yifan    """
133*bcb5dc79SHONG Yifan    return a._values == b._values
134*bcb5dc79SHONG Yifan
135*bcb5dc79SHONG Yifandef _is_subset(a, b):
136*bcb5dc79SHONG Yifan    """Returns whether `a` is a subset of `b`.
137*bcb5dc79SHONG Yifan
138*bcb5dc79SHONG Yifan    Args:
139*bcb5dc79SHONG Yifan      a: A set, as returned by `sets.make()`.
140*bcb5dc79SHONG Yifan      b: A set, as returned by `sets.make()`.
141*bcb5dc79SHONG Yifan
142*bcb5dc79SHONG Yifan    Returns:
143*bcb5dc79SHONG Yifan      True if `a` is a subset of `b`, False otherwise.
144*bcb5dc79SHONG Yifan    """
145*bcb5dc79SHONG Yifan    for e in a._values.keys():
146*bcb5dc79SHONG Yifan        if e not in b._values:
147*bcb5dc79SHONG Yifan            return False
148*bcb5dc79SHONG Yifan    return True
149*bcb5dc79SHONG Yifan
150*bcb5dc79SHONG Yifandef _disjoint(a, b):
151*bcb5dc79SHONG Yifan    """Returns whether two sets are disjoint.
152*bcb5dc79SHONG Yifan
153*bcb5dc79SHONG Yifan    Two sets are disjoint if they have no elements in common.
154*bcb5dc79SHONG Yifan
155*bcb5dc79SHONG Yifan    Args:
156*bcb5dc79SHONG Yifan      a: A set, as returned by `sets.make()`.
157*bcb5dc79SHONG Yifan      b: A set, as returned by `sets.make()`.
158*bcb5dc79SHONG Yifan
159*bcb5dc79SHONG Yifan    Returns:
160*bcb5dc79SHONG Yifan      True if `a` and `b` are disjoint, False otherwise.
161*bcb5dc79SHONG Yifan    """
162*bcb5dc79SHONG Yifan    shorter, longer = _get_shorter_and_longer(a, b)
163*bcb5dc79SHONG Yifan    for e in shorter._values.keys():
164*bcb5dc79SHONG Yifan        if e in longer._values:
165*bcb5dc79SHONG Yifan            return False
166*bcb5dc79SHONG Yifan    return True
167*bcb5dc79SHONG Yifan
168*bcb5dc79SHONG Yifandef _intersection(a, b):
169*bcb5dc79SHONG Yifan    """Returns the intersection of two sets.
170*bcb5dc79SHONG Yifan
171*bcb5dc79SHONG Yifan    Args:
172*bcb5dc79SHONG Yifan      a: A set, as returned by `sets.make()`.
173*bcb5dc79SHONG Yifan      b: A set, as returned by `sets.make()`.
174*bcb5dc79SHONG Yifan
175*bcb5dc79SHONG Yifan    Returns:
176*bcb5dc79SHONG Yifan      A set containing the elements that are in both `a` and `b`.
177*bcb5dc79SHONG Yifan    """
178*bcb5dc79SHONG Yifan    shorter, longer = _get_shorter_and_longer(a, b)
179*bcb5dc79SHONG Yifan    return struct(_values = {e: None for e in shorter._values.keys() if e in longer._values})
180*bcb5dc79SHONG Yifan
181*bcb5dc79SHONG Yifandef _union(*args):
182*bcb5dc79SHONG Yifan    """Returns the union of several sets.
183*bcb5dc79SHONG Yifan
184*bcb5dc79SHONG Yifan    Args:
185*bcb5dc79SHONG Yifan      *args: An arbitrary number of sets.
186*bcb5dc79SHONG Yifan
187*bcb5dc79SHONG Yifan    Returns:
188*bcb5dc79SHONG Yifan      The set union of all sets in `*args`.
189*bcb5dc79SHONG Yifan    """
190*bcb5dc79SHONG Yifan    return struct(_values = dicts.add(*[s._values for s in args]))
191*bcb5dc79SHONG Yifan
192*bcb5dc79SHONG Yifandef _difference(a, b):
193*bcb5dc79SHONG Yifan    """Returns the elements in `a` that are not in `b`.
194*bcb5dc79SHONG Yifan
195*bcb5dc79SHONG Yifan    Args:
196*bcb5dc79SHONG Yifan      a: A set, as returned by `sets.make()`.
197*bcb5dc79SHONG Yifan      b: A set, as returned by `sets.make()`.
198*bcb5dc79SHONG Yifan
199*bcb5dc79SHONG Yifan    Returns:
200*bcb5dc79SHONG Yifan      A set containing the elements that are in `a` but not in `b`.
201*bcb5dc79SHONG Yifan    """
202*bcb5dc79SHONG Yifan    return struct(_values = {e: None for e in a._values.keys() if e not in b._values})
203*bcb5dc79SHONG Yifan
204*bcb5dc79SHONG Yifandef _length(s):
205*bcb5dc79SHONG Yifan    """Returns the number of elements in a set.
206*bcb5dc79SHONG Yifan
207*bcb5dc79SHONG Yifan    Args:
208*bcb5dc79SHONG Yifan      s: A set, as returned by `sets.make()`.
209*bcb5dc79SHONG Yifan
210*bcb5dc79SHONG Yifan    Returns:
211*bcb5dc79SHONG Yifan      An integer representing the number of elements in the set.
212*bcb5dc79SHONG Yifan    """
213*bcb5dc79SHONG Yifan    return len(s._values)
214*bcb5dc79SHONG Yifan
215*bcb5dc79SHONG Yifandef _repr(s):
216*bcb5dc79SHONG Yifan    """Returns a string value representing the set.
217*bcb5dc79SHONG Yifan
218*bcb5dc79SHONG Yifan    Args:
219*bcb5dc79SHONG Yifan      s: A set, as returned by `sets.make()`.
220*bcb5dc79SHONG Yifan
221*bcb5dc79SHONG Yifan    Returns:
222*bcb5dc79SHONG Yifan      A string representing the set.
223*bcb5dc79SHONG Yifan    """
224*bcb5dc79SHONG Yifan    return repr(s._values.keys())
225*bcb5dc79SHONG Yifan
226*bcb5dc79SHONG Yifansets = struct(
227*bcb5dc79SHONG Yifan    make = _make,
228*bcb5dc79SHONG Yifan    copy = _copy,
229*bcb5dc79SHONG Yifan    to_list = _to_list,
230*bcb5dc79SHONG Yifan    insert = _insert,
231*bcb5dc79SHONG Yifan    contains = _contains,
232*bcb5dc79SHONG Yifan    is_equal = _is_equal,
233*bcb5dc79SHONG Yifan    is_subset = _is_subset,
234*bcb5dc79SHONG Yifan    disjoint = _disjoint,
235*bcb5dc79SHONG Yifan    intersection = _intersection,
236*bcb5dc79SHONG Yifan    union = _union,
237*bcb5dc79SHONG Yifan    difference = _difference,
238*bcb5dc79SHONG Yifan    length = _length,
239*bcb5dc79SHONG Yifan    remove = _remove,
240*bcb5dc79SHONG Yifan    repr = _repr,
241*bcb5dc79SHONG Yifan    str = _repr,
242*bcb5dc79SHONG Yifan    # is_set is declared in types.bzl
243*bcb5dc79SHONG Yifan)
244