# Copyright 2017 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 set algorithms. CAUTION: Operating on sets, particularly sets contained in providers, may asymptotically slow down the analysis phase. While constructing large sets with addition/union is fast (there is no linear-time copy involved), the `difference` function and various comparison predicates involve linear-time traversals. For convenience, the functions in this module can take either sets or lists as inputs; operations that take lists treat them as if they were sets (i.e., duplicate elements are ignored). Functions that return new sets always return them as the `set` type, regardless of the types of the inputs. """ _depset_type = type(depset()) _list_type = type([]) def _precondition_only_sets_or_lists(*args): """Verifies that all arguments are either sets or lists. The build will fail if any of the arguments is neither a set nor a list. Args: *args: A list of values that must be sets or lists. """ for a in args: t = type(a) if t not in (_depset_type, _list_type): fail("Expected arguments to be depset or list, but found type %s: %r" % (t, a)) def _depset_to_list(val): """Converts a depset to a list. If the given value is a depset, will return the list representation of the depset. Otherwise, will return the value itself. Args: val: The value to be optionally converted and returned. Returns: The converted value. """ if type(val) == _depset_type: return val.to_list() else: return val def _is_equal(a, b): """Returns whether two sets are equal. Args: a: A depset or a list. b: A depset or a list. Returns: True if `a` is equal to `b`, False otherwise. """ _precondition_only_sets_or_lists(a, b) # Convert both values to a depset then back to a list to remove duplicates. a = _depset_to_list(depset(a)) b = _depset_to_list(depset(b)) return sorted(a) == sorted(b) def _is_subset(a, b): """Returns whether `a` is a subset of `b`. Args: a: A depset or a list. b: A depset or a list. Returns: True if `a` is a subset of `b`, False otherwise. """ _precondition_only_sets_or_lists(a, b) for e in _depset_to_list(a): if e not in _depset_to_list(b): return False return True def _disjoint(a, b): """Returns whether two sets are disjoint. Two sets are disjoint if they have no elements in common. Args: a: A set or list. b: A set or list. Returns: True if `a` and `b` are disjoint, False otherwise. """ _precondition_only_sets_or_lists(a, b) for e in _depset_to_list(a): if e in _depset_to_list(b): return False return True def _intersection(a, b): """Returns the intersection of two sets. Args: a: A set or list. b: A set or list. Returns: A set containing the elements that are in both `a` and `b`. """ _precondition_only_sets_or_lists(a, b) return depset([e for e in _depset_to_list(a) if e in _depset_to_list(b)]) def _union(*args): """Returns the union of several sets. Args: *args: An arbitrary number of sets or lists. Returns: The set union of all sets or lists in `*args`. """ _precondition_only_sets_or_lists(*args) args_deps = [depset(x) if type(x) == _list_type else x for x in args] return depset(transitive = args_deps) def _difference(a, b): """Returns the elements in `a` that are not in `b`. Args: a: A set or list. b: A set or list. Returns: A set containing the elements that are in `a` but not in `b`. """ _precondition_only_sets_or_lists(a, b) return depset([e for e in _depset_to_list(a) if e not in _depset_to_list(b)]) sets = struct( difference = _difference, disjoint = _disjoint, intersection = _intersection, is_equal = _is_equal, is_subset = _is_subset, union = _union, )