Coverage Summary for Class: EndpointPairIterator (com.google.common.graph)

Class Method, % Line, %
EndpointPairIterator 0% (0/4) 0% (0/13)
EndpointPairIterator$Directed 0% (0/3) 0% (0/6)
EndpointPairIterator$Undirected 0% (0/3) 0% (0/13)
Total 0% (0/10) 0% (0/32)


1 /* 2  * Copyright (C) 2016 The Guava Authors 3  * 4  * Licensed under the Apache License, Version 2.0 (the "License"); 5  * you may not use this file except in compliance with the License. 6  * You may obtain a copy of the License at 7  * 8  * http://www.apache.org/licenses/LICENSE-2.0 9  * 10  * Unless required by applicable law or agreed to in writing, software 11  * distributed under the License is distributed on an "AS IS" BASIS, 12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13  * See the License for the specific language governing permissions and 14  * limitations under the License. 15  */ 16  17 package com.google.common.graph; 18  19 import static com.google.common.base.Preconditions.checkState; 20 import static java.util.Objects.requireNonNull; 21  22 import com.google.common.collect.AbstractIterator; 23 import com.google.common.collect.ImmutableSet; 24 import com.google.common.collect.Sets; 25 import java.util.Iterator; 26 import java.util.Set; 27 import javax.annotation.CheckForNull; 28 import org.checkerframework.checker.nullness.qual.Nullable; 29  30 /** 31  * A class to facilitate the set returned by {@link Graph#edges()}. 32  * 33  * @author James Sexton 34  */ 35 @ElementTypesAreNonnullByDefault 36 abstract class EndpointPairIterator<N> extends AbstractIterator<EndpointPair<N>> { 37  private final BaseGraph<N> graph; 38  private final Iterator<N> nodeIterator; 39  40  @CheckForNull 41  N node = null; // null is safe as an initial value because graphs don't allow null nodes 42  43  Iterator<N> successorIterator = ImmutableSet.<N>of().iterator(); 44  45  static <N> EndpointPairIterator<N> of(BaseGraph<N> graph) { 46  return graph.isDirected() ? new Directed<N>(graph) : new Undirected<N>(graph); 47  } 48  49  private EndpointPairIterator(BaseGraph<N> graph) { 50  this.graph = graph; 51  this.nodeIterator = graph.nodes().iterator(); 52  } 53  54  /** 55  * Called after {@link #successorIterator} is exhausted. Advances {@link #node} to the next node 56  * and updates {@link #successorIterator} to iterate through the successors of {@link #node}. 57  */ 58  final boolean advance() { 59  checkState(!successorIterator.hasNext()); 60  if (!nodeIterator.hasNext()) { 61  return false; 62  } 63  node = nodeIterator.next(); 64  successorIterator = graph.successors(node).iterator(); 65  return true; 66  } 67  68  /** 69  * If the graph is directed, each ordered [source, target] pair will be visited once if there is 70  * an edge connecting them. 71  */ 72  private static final class Directed<N> extends EndpointPairIterator<N> { 73  private Directed(BaseGraph<N> graph) { 74  super(graph); 75  } 76  77  @Override 78  protected EndpointPair<N> computeNext() { 79  while (true) { 80  if (successorIterator.hasNext()) { 81  // requireNonNull is safe because successorIterator is empty until we set this.node. 82  return EndpointPair.ordered(requireNonNull(node), successorIterator.next()); 83  } 84  if (!advance()) { 85  return endOfData(); 86  } 87  } 88  } 89  } 90  91  /** 92  * If the graph is undirected, each unordered [node, otherNode] pair (except self-loops) will be 93  * visited twice if there is an edge connecting them. To avoid returning duplicate {@link 94  * EndpointPair}s, we keep track of the nodes that we have visited. When processing endpoint 95  * pairs, we skip if the "other node" is in the visited set, as shown below: 96  * 97  * <pre> 98  * Nodes = {N1, N2, N3, N4} 99  * N2 __ 100  * / \ | | 101  * N1----N3 N4__| 102  * 103  * Visited Nodes = {} 104  * EndpointPair [N1, N2] - return 105  * EndpointPair [N1, N3] - return 106  * Visited Nodes = {N1} 107  * EndpointPair [N2, N1] - skip 108  * EndpointPair [N2, N3] - return 109  * Visited Nodes = {N1, N2} 110  * EndpointPair [N3, N1] - skip 111  * EndpointPair [N3, N2] - skip 112  * Visited Nodes = {N1, N2, N3} 113  * EndpointPair [N4, N4] - return 114  * Visited Nodes = {N1, N2, N3, N4} 115  * </pre> 116  */ 117  private static final class Undirected<N> extends EndpointPairIterator<N> { 118  // It's a little weird that we add `null` to this set, but it makes for slightly simpler code. 119  @CheckForNull private Set<@Nullable N> visitedNodes; 120  121  private Undirected(BaseGraph<N> graph) { 122  super(graph); 123  this.visitedNodes = Sets.newHashSetWithExpectedSize(graph.nodes().size() + 1); 124  } 125  126  @Override 127  protected EndpointPair<N> computeNext() { 128  while (true) { 129  /* 130  * requireNonNull is safe because visitedNodes isn't cleared until this method calls 131  * endOfData() (after which this method is never called again). 132  */ 133  requireNonNull(visitedNodes); 134  while (successorIterator.hasNext()) { 135  N otherNode = successorIterator.next(); 136  if (!visitedNodes.contains(otherNode)) { 137  // requireNonNull is safe because successorIterator is empty until we set node. 138  return EndpointPair.unordered(requireNonNull(node), otherNode); 139  } 140  } 141  // Add to visited set *after* processing neighbors so we still include self-loops. 142  visitedNodes.add(node); 143  if (!advance()) { 144  visitedNodes = null; 145  return endOfData(); 146  } 147  } 148  } 149  } 150 }