2018-04-20 21:44:25 +00:00
|
|
|
# Copyright 2018 The Bazel Authors. All rights reserved.
|
|
|
|
#
|
|
|
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
|
|
# you may not use this file except in compliance with the License.
|
|
|
|
# You may obtain a copy of the License at
|
|
|
|
#
|
|
|
|
# http://www.apache.org/licenses/LICENSE-2.0
|
|
|
|
#
|
|
|
|
# Unless required by applicable law or agreed to in writing, software
|
|
|
|
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
|
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
|
|
# See the License for the specific language governing permissions and
|
|
|
|
# limitations under the License.
|
|
|
|
|
|
|
|
"""Skylib module containing common hash-set algorithms.
|
|
|
|
|
|
|
|
An empty set can be created using: `sets.make()`, or it can be created with some starting values
|
|
|
|
if you pass it an sequence: `sets.make([1, 2, 3])`. This returns a struct containing all of the
|
|
|
|
values as keys in a dictionary - this means that all passed in values must be hashable. The
|
|
|
|
values in the set can be retrieved using `sets.to_list(my_set)`.
|
|
|
|
"""
|
|
|
|
|
|
|
|
load(":dicts.bzl", "dicts")
|
|
|
|
|
2018-06-12 17:09:57 +00:00
|
|
|
def _make(elements = None):
|
|
|
|
"""Creates a new set.
|
2018-04-20 21:44:25 +00:00
|
|
|
|
2018-06-12 17:09:57 +00:00
|
|
|
All elements must be hashable.
|
2018-04-20 21:44:25 +00:00
|
|
|
|
2018-06-12 17:09:57 +00:00
|
|
|
Args:
|
|
|
|
elements: Optional sequence to construct the set out of.
|
2018-04-20 21:44:25 +00:00
|
|
|
|
2018-06-12 17:09:57 +00:00
|
|
|
Returns:
|
|
|
|
A set containing the passed in values.
|
|
|
|
"""
|
|
|
|
elements = elements if elements else []
|
|
|
|
return struct(_values = {e: None for e in elements})
|
2018-04-20 21:44:25 +00:00
|
|
|
|
|
|
|
def _copy(s):
|
2018-06-12 17:09:57 +00:00
|
|
|
"""Creates a new set from another set.
|
2018-04-20 21:44:25 +00:00
|
|
|
|
2018-06-12 17:09:57 +00:00
|
|
|
Args:
|
|
|
|
s: A set, as returned by `sets.make()`.
|
2018-04-20 21:44:25 +00:00
|
|
|
|
2018-06-12 17:09:57 +00:00
|
|
|
Returns:
|
|
|
|
A new set containing the same elements as `s`.
|
|
|
|
"""
|
|
|
|
return struct(_values = dict(s._values))
|
2018-04-20 21:44:25 +00:00
|
|
|
|
2018-04-26 16:08:01 +00:00
|
|
|
def _to_list(s):
|
2018-06-12 17:09:57 +00:00
|
|
|
"""Creates a list from the values in the set.
|
2018-04-26 16:08:01 +00:00
|
|
|
|
2018-06-12 17:09:57 +00:00
|
|
|
Args:
|
|
|
|
s: A set, as returned by `sets.make()`.
|
2018-04-20 21:44:25 +00:00
|
|
|
|
2018-06-12 17:09:57 +00:00
|
|
|
Returns:
|
|
|
|
A list of values inserted into the set.
|
|
|
|
"""
|
|
|
|
return s._values.keys()
|
2018-04-20 21:44:25 +00:00
|
|
|
|
|
|
|
def _insert(s, e):
|
2018-06-12 17:09:57 +00:00
|
|
|
"""Inserts an element into the set.
|
2018-04-20 21:44:25 +00:00
|
|
|
|
2019-05-01 17:38:59 +00:00
|
|
|
Element must be hashable. This mutates the original set.
|
2018-04-20 21:44:25 +00:00
|
|
|
|
2018-06-12 17:09:57 +00:00
|
|
|
Args:
|
|
|
|
s: A set, as returned by `sets.make()`.
|
|
|
|
e: The element to be inserted.
|
2018-04-20 21:44:25 +00:00
|
|
|
|
2018-06-12 17:09:57 +00:00
|
|
|
Returns:
|
|
|
|
The set `s` with `e` included.
|
|
|
|
"""
|
|
|
|
s._values[e] = None
|
|
|
|
return s
|
2018-04-20 21:44:25 +00:00
|
|
|
|
|
|
|
def _remove(s, e):
|
2018-06-12 17:09:57 +00:00
|
|
|
"""Removes an element from the set.
|
2018-04-20 21:44:25 +00:00
|
|
|
|
2019-05-01 17:38:59 +00:00
|
|
|
Element must be hashable. This mutates the original set.
|
2018-04-20 21:44:25 +00:00
|
|
|
|
2018-06-12 17:09:57 +00:00
|
|
|
Args:
|
|
|
|
s: A set, as returned by `sets.make()`.
|
|
|
|
e: The element to be removed.
|
2018-04-20 21:44:25 +00:00
|
|
|
|
2018-06-12 17:09:57 +00:00
|
|
|
Returns:
|
|
|
|
The set `s` with `e` removed.
|
|
|
|
"""
|
|
|
|
s._values.pop(e)
|
|
|
|
return s
|
2018-04-20 21:44:25 +00:00
|
|
|
|
|
|
|
def _contains(a, e):
|
2018-06-12 17:09:57 +00:00
|
|
|
"""Checks for the existence of an element in a set.
|
2018-04-20 21:44:25 +00:00
|
|
|
|
2018-06-12 17:09:57 +00:00
|
|
|
Args:
|
|
|
|
a: A set, as returned by `sets.make()`.
|
|
|
|
e: The element to look for.
|
2018-04-20 21:44:25 +00:00
|
|
|
|
2018-06-12 17:09:57 +00:00
|
|
|
Returns:
|
|
|
|
True if the element exists in the set, False if the element does not.
|
|
|
|
"""
|
|
|
|
return e in a._values
|
2018-04-20 21:44:25 +00:00
|
|
|
|
|
|
|
def _get_shorter_and_longer(a, b):
|
2018-06-12 17:09:57 +00:00
|
|
|
"""Returns two sets in the order of shortest and longest.
|
2018-04-26 16:08:01 +00:00
|
|
|
|
2018-06-12 17:09:57 +00:00
|
|
|
Args:
|
|
|
|
a: A set, as returned by `sets.make()`.
|
|
|
|
b: A set, as returned by `sets.make()`.
|
2018-04-20 21:44:25 +00:00
|
|
|
|
2018-06-12 17:09:57 +00:00
|
|
|
Returns:
|
|
|
|
`a`, `b` if `a` is shorter than `b` - or `b`, `a` if `b` is shorter than `a`.
|
|
|
|
"""
|
|
|
|
if _length(a) < _length(b):
|
|
|
|
return a, b
|
|
|
|
return b, a
|
2018-04-20 21:44:25 +00:00
|
|
|
|
|
|
|
def _is_equal(a, b):
|
2018-06-12 17:09:57 +00:00
|
|
|
"""Returns whether two sets are equal.
|
2018-04-20 21:44:25 +00:00
|
|
|
|
2018-06-12 17:09:57 +00:00
|
|
|
Args:
|
|
|
|
a: A set, as returned by `sets.make()`.
|
|
|
|
b: A set, as returned by `sets.make()`.
|
2018-04-20 21:44:25 +00:00
|
|
|
|
2018-06-12 17:09:57 +00:00
|
|
|
Returns:
|
|
|
|
True if `a` is equal to `b`, False otherwise.
|
|
|
|
"""
|
|
|
|
return a._values == b._values
|
2018-04-20 21:44:25 +00:00
|
|
|
|
|
|
|
def _is_subset(a, b):
|
2018-06-12 17:09:57 +00:00
|
|
|
"""Returns whether `a` is a subset of `b`.
|
2018-04-20 21:44:25 +00:00
|
|
|
|
2018-06-12 17:09:57 +00:00
|
|
|
Args:
|
|
|
|
a: A set, as returned by `sets.make()`.
|
|
|
|
b: A set, as returned by `sets.make()`.
|
2018-04-20 21:44:25 +00:00
|
|
|
|
2018-06-12 17:09:57 +00:00
|
|
|
Returns:
|
|
|
|
True if `a` is a subset of `b`, False otherwise.
|
|
|
|
"""
|
|
|
|
for e in a._values.keys():
|
|
|
|
if e not in b._values:
|
|
|
|
return False
|
|
|
|
return True
|
2018-04-20 21:44:25 +00:00
|
|
|
|
|
|
|
def _disjoint(a, b):
|
2018-06-12 17:09:57 +00:00
|
|
|
"""Returns whether two sets are disjoint.
|
2018-04-20 21:44:25 +00:00
|
|
|
|
2018-06-12 17:09:57 +00:00
|
|
|
Two sets are disjoint if they have no elements in common.
|
2018-04-20 21:44:25 +00:00
|
|
|
|
2018-06-12 17:09:57 +00:00
|
|
|
Args:
|
|
|
|
a: A set, as returned by `sets.make()`.
|
|
|
|
b: A set, as returned by `sets.make()`.
|
2018-04-20 21:44:25 +00:00
|
|
|
|
2018-06-12 17:09:57 +00:00
|
|
|
Returns:
|
|
|
|
True if `a` and `b` are disjoint, False otherwise.
|
|
|
|
"""
|
|
|
|
shorter, longer = _get_shorter_and_longer(a, b)
|
|
|
|
for e in shorter._values.keys():
|
|
|
|
if e in longer._values:
|
|
|
|
return False
|
|
|
|
return True
|
2018-04-20 21:44:25 +00:00
|
|
|
|
|
|
|
def _intersection(a, b):
|
2018-06-12 17:09:57 +00:00
|
|
|
"""Returns the intersection of two sets.
|
2018-04-20 21:44:25 +00:00
|
|
|
|
2018-06-12 17:09:57 +00:00
|
|
|
Args:
|
|
|
|
a: A set, as returned by `sets.make()`.
|
|
|
|
b: A set, as returned by `sets.make()`.
|
2018-04-20 21:44:25 +00:00
|
|
|
|
2018-06-12 17:09:57 +00:00
|
|
|
Returns:
|
|
|
|
A set containing the elements that are in both `a` and `b`.
|
|
|
|
"""
|
|
|
|
shorter, longer = _get_shorter_and_longer(a, b)
|
|
|
|
return struct(_values = {e: None for e in shorter._values.keys() if e in longer._values})
|
2018-04-20 21:44:25 +00:00
|
|
|
|
|
|
|
def _union(*args):
|
2018-06-12 17:09:57 +00:00
|
|
|
"""Returns the union of several sets.
|
2018-04-20 21:44:25 +00:00
|
|
|
|
2018-06-12 17:09:57 +00:00
|
|
|
Args:
|
|
|
|
*args: An arbitrary number of sets or lists.
|
2018-04-20 21:44:25 +00:00
|
|
|
|
2018-06-12 17:09:57 +00:00
|
|
|
Returns:
|
|
|
|
The set union of all sets or lists in `*args`.
|
|
|
|
"""
|
|
|
|
return struct(_values = dicts.add(*[s._values for s in args]))
|
2018-04-20 21:44:25 +00:00
|
|
|
|
|
|
|
def _difference(a, b):
|
2018-06-12 17:09:57 +00:00
|
|
|
"""Returns the elements in `a` that are not in `b`.
|
2018-04-20 21:44:25 +00:00
|
|
|
|
2018-06-12 17:09:57 +00:00
|
|
|
Args:
|
|
|
|
a: A set, as returned by `sets.make()`.
|
|
|
|
b: A set, as returned by `sets.make()`.
|
2018-04-20 21:44:25 +00:00
|
|
|
|
2018-06-12 17:09:57 +00:00
|
|
|
Returns:
|
|
|
|
A set containing the elements that are in `a` but not in `b`.
|
|
|
|
"""
|
|
|
|
return struct(_values = {e: None for e in a._values.keys() if e not in b._values})
|
2018-04-20 21:44:25 +00:00
|
|
|
|
|
|
|
def _length(s):
|
2018-06-12 17:09:57 +00:00
|
|
|
"""Returns the number of elements in a set.
|
2018-04-20 21:44:25 +00:00
|
|
|
|
2018-06-12 17:09:57 +00:00
|
|
|
Args:
|
|
|
|
s: A set, as returned by `sets.make()`.
|
2018-04-20 21:44:25 +00:00
|
|
|
|
2018-06-12 17:09:57 +00:00
|
|
|
Returns:
|
|
|
|
An integer representing the number of elements in the set.
|
|
|
|
"""
|
|
|
|
return len(s._values)
|
2018-04-20 21:44:25 +00:00
|
|
|
|
2018-05-04 22:39:54 +00:00
|
|
|
def _repr(s):
|
2018-06-12 17:09:57 +00:00
|
|
|
"""Returns a string value representing the set.
|
2018-05-04 22:39:54 +00:00
|
|
|
|
2018-06-12 17:09:57 +00:00
|
|
|
Args:
|
|
|
|
s: A set, as returned by `sets.make()`.
|
2018-05-04 22:39:54 +00:00
|
|
|
|
2018-06-12 17:09:57 +00:00
|
|
|
Returns:
|
|
|
|
A string representing the set.
|
|
|
|
"""
|
|
|
|
return repr(s._values.keys())
|
2018-04-20 21:44:25 +00:00
|
|
|
|
|
|
|
sets = struct(
|
2018-06-12 17:09:57 +00:00
|
|
|
make = _make,
|
|
|
|
copy = _copy,
|
|
|
|
to_list = _to_list,
|
|
|
|
insert = _insert,
|
|
|
|
contains = _contains,
|
|
|
|
is_equal = _is_equal,
|
|
|
|
is_subset = _is_subset,
|
|
|
|
disjoint = _disjoint,
|
|
|
|
intersection = _intersection,
|
|
|
|
union = _union,
|
|
|
|
difference = _difference,
|
|
|
|
length = _length,
|
|
|
|
remove = _remove,
|
|
|
|
repr = _repr,
|
|
|
|
str = _repr,
|
2018-04-20 21:44:25 +00:00
|
|
|
)
|