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