def get_views(variables, node): """Get all possible views of the given variables at a particular node. For performance reasons, this method uses node.CanHaveCombination for filtering. For a more precise check, you can call node.HasCombination(list(view.values())). Do so judiciously, as the latter method can be very slow. This function can be used either as a regular generator or in an optimized way to yield only functionally unique views: views = get_views(...) skip_future = None while True: try: view = views.send(skip_future) except StopIteration: break ... The caller should set `skip_future` to True when it is safe to skip equivalent future views and False otherwise. Args: variables: The variables. node: The node. Yields: A datatypes.AcessTrackingDict mapping variables to bindings. """ try: combinations = cfg_utils.deep_variable_product(variables) except cfg_utils.TooComplexError: combinations = ((var.AddBinding(node.program.default_data, [], node) for var in variables), ) seen = [] # the accessed subsets of previously seen views for combination in combinations: view = {value.variable: value for value in combination} if any(subset <= six.viewitems(view) for subset in seen): # Optimization: This view can be skipped because it matches the accessed # subset of a previous one. log.info("Skipping view (already seen): %r", view) continue combination = list(view.values()) if not node.CanHaveCombination(combination): log.info("Skipping combination (unreachable): %r", combination) continue view = datatypes.AccessTrackingDict(view) skip_future = yield view if skip_future: # Skip future views matching this accessed subset. seen.append(six.viewitems(view.accessed_subset))
def setUp(self): super().setUp() self.d = datatypes.AccessTrackingDict({"a": 1, "b": 2})