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

Class Method, % Line, %
EndpointPair 0% (0/10) 0% (0/16)
EndpointPair$Ordered 0% (0/8) 0% (0/15)
EndpointPair$Unordered 0% (0/8) 0% (0/17)
Total 0% (0/26) 0% (0/48)


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.checkNotNull; 20 import static com.google.common.graph.GraphConstants.NOT_AVAILABLE_ON_UNDIRECTED; 21  22 import com.google.common.annotations.Beta; 23 import com.google.common.base.Objects; 24 import com.google.common.collect.Iterators; 25 import com.google.common.collect.UnmodifiableIterator; 26 import com.google.errorprone.annotations.Immutable; 27 import javax.annotation.CheckForNull; 28  29 /** 30  * An immutable pair representing the two endpoints of an edge in a graph. The {@link EndpointPair} 31  * of a directed edge is an ordered pair of nodes ({@link #source()} and {@link #target()}). The 32  * {@link EndpointPair} of an undirected edge is an unordered pair of nodes ({@link #nodeU()} and 33  * {@link #nodeV()}). 34  * 35  * <p>The edge is a self-loop if, and only if, the two endpoints are equal. 36  * 37  * @author James Sexton 38  * @since 20.0 39  */ 40 @Beta 41 @Immutable(containerOf = {"N"}) 42 @ElementTypesAreNonnullByDefault 43 public abstract class EndpointPair<N> implements Iterable<N> { 44  private final N nodeU; 45  private final N nodeV; 46  47  private EndpointPair(N nodeU, N nodeV) { 48  this.nodeU = checkNotNull(nodeU); 49  this.nodeV = checkNotNull(nodeV); 50  } 51  52  /** Returns an {@link EndpointPair} representing the endpoints of a directed edge. */ 53  public static <N> EndpointPair<N> ordered(N source, N target) { 54  return new Ordered<N>(source, target); 55  } 56  57  /** Returns an {@link EndpointPair} representing the endpoints of an undirected edge. */ 58  public static <N> EndpointPair<N> unordered(N nodeU, N nodeV) { 59  // Swap nodes on purpose to prevent callers from relying on the "ordering" of an unordered pair. 60  return new Unordered<N>(nodeV, nodeU); 61  } 62  63  /** Returns an {@link EndpointPair} representing the endpoints of an edge in {@code graph}. */ 64  static <N> EndpointPair<N> of(Graph<?> graph, N nodeU, N nodeV) { 65  return graph.isDirected() ? ordered(nodeU, nodeV) : unordered(nodeU, nodeV); 66  } 67  68  /** Returns an {@link EndpointPair} representing the endpoints of an edge in {@code network}. */ 69  static <N> EndpointPair<N> of(Network<?, ?> network, N nodeU, N nodeV) { 70  return network.isDirected() ? ordered(nodeU, nodeV) : unordered(nodeU, nodeV); 71  } 72  73  /** 74  * If this {@link EndpointPair} {@link #isOrdered()}, returns the node which is the source. 75  * 76  * @throws UnsupportedOperationException if this {@link EndpointPair} is not ordered 77  */ 78  public abstract N source(); 79  80  /** 81  * If this {@link EndpointPair} {@link #isOrdered()}, returns the node which is the target. 82  * 83  * @throws UnsupportedOperationException if this {@link EndpointPair} is not ordered 84  */ 85  public abstract N target(); 86  87  /** 88  * If this {@link EndpointPair} {@link #isOrdered()} returns the {@link #source()}; otherwise, 89  * returns an arbitrary (but consistent) endpoint of the origin edge. 90  */ 91  public final N nodeU() { 92  return nodeU; 93  } 94  95  /** 96  * Returns the node {@link #adjacentNode(Object) adjacent} to {@link #nodeU()} along the origin 97  * edge. If this {@link EndpointPair} {@link #isOrdered()}, this is equal to {@link #target()}. 98  */ 99  public final N nodeV() { 100  return nodeV; 101  } 102  103  /** 104  * Returns the node that is adjacent to {@code node} along the origin edge. 105  * 106  * @throws IllegalArgumentException if this {@link EndpointPair} does not contain {@code node} 107  * @since 20.0 (but the argument type was changed from {@code Object} to {@code N} in 31.0) 108  */ 109  public final N adjacentNode(N node) { 110  if (node.equals(nodeU)) { 111  return nodeV; 112  } else if (node.equals(nodeV)) { 113  return nodeU; 114  } else { 115  throw new IllegalArgumentException("EndpointPair " + this + " does not contain node " + node); 116  } 117  } 118  119  /** 120  * Returns {@code true} if this {@link EndpointPair} is an ordered pair (i.e. represents the 121  * endpoints of a directed edge). 122  */ 123  public abstract boolean isOrdered(); 124  125  /** Iterates in the order {@link #nodeU()}, {@link #nodeV()}. */ 126  @Override 127  public final UnmodifiableIterator<N> iterator() { 128  return Iterators.forArray(nodeU, nodeV); 129  } 130  131  /** 132  * Two ordered {@link EndpointPair}s are equal if their {@link #source()} and {@link #target()} 133  * are equal. Two unordered {@link EndpointPair}s are equal if they contain the same nodes. An 134  * ordered {@link EndpointPair} is never equal to an unordered {@link EndpointPair}. 135  */ 136  @Override 137  public abstract boolean equals(@CheckForNull Object obj); 138  139  /** 140  * The hashcode of an ordered {@link EndpointPair} is equal to {@code Objects.hashCode(source(), 141  * target())}. The hashcode of an unordered {@link EndpointPair} is equal to {@code 142  * nodeU().hashCode() + nodeV().hashCode()}. 143  */ 144  @Override 145  public abstract int hashCode(); 146  147  private static final class Ordered<N> extends EndpointPair<N> { 148  private Ordered(N source, N target) { 149  super(source, target); 150  } 151  152  @Override 153  public N source() { 154  return nodeU(); 155  } 156  157  @Override 158  public N target() { 159  return nodeV(); 160  } 161  162  @Override 163  public boolean isOrdered() { 164  return true; 165  } 166  167  @Override 168  public boolean equals(@CheckForNull Object obj) { 169  if (obj == this) { 170  return true; 171  } 172  if (!(obj instanceof EndpointPair)) { 173  return false; 174  } 175  176  EndpointPair<?> other = (EndpointPair<?>) obj; 177  if (isOrdered() != other.isOrdered()) { 178  return false; 179  } 180  181  return source().equals(other.source()) && target().equals(other.target()); 182  } 183  184  @Override 185  public int hashCode() { 186  return Objects.hashCode(source(), target()); 187  } 188  189  @Override 190  public String toString() { 191  return "<" + source() + " -> " + target() + ">"; 192  } 193  } 194  195  private static final class Unordered<N> extends EndpointPair<N> { 196  private Unordered(N nodeU, N nodeV) { 197  super(nodeU, nodeV); 198  } 199  200  @Override 201  public N source() { 202  throw new UnsupportedOperationException(NOT_AVAILABLE_ON_UNDIRECTED); 203  } 204  205  @Override 206  public N target() { 207  throw new UnsupportedOperationException(NOT_AVAILABLE_ON_UNDIRECTED); 208  } 209  210  @Override 211  public boolean isOrdered() { 212  return false; 213  } 214  215  @Override 216  public boolean equals(@CheckForNull Object obj) { 217  if (obj == this) { 218  return true; 219  } 220  if (!(obj instanceof EndpointPair)) { 221  return false; 222  } 223  224  EndpointPair<?> other = (EndpointPair<?>) obj; 225  if (isOrdered() != other.isOrdered()) { 226  return false; 227  } 228  229  // Equivalent to the following simple implementation: 230  // boolean condition1 = nodeU().equals(other.nodeU()) && nodeV().equals(other.nodeV()); 231  // boolean condition2 = nodeU().equals(other.nodeV()) && nodeV().equals(other.nodeU()); 232  // return condition1 || condition2; 233  if (nodeU().equals(other.nodeU())) { // check condition1 234  // Here's the tricky bit. We don't have to explicitly check for condition2 in this case. 235  // Why? The second half of condition2 requires that nodeV equals other.nodeU. 236  // We already know that nodeU equals other.nodeU. Combined with the earlier statement, 237  // and the transitive property of equality, this implies that nodeU equals nodeV. 238  // If nodeU equals nodeV, condition1 == condition2, so checking condition1 is sufficient. 239  return nodeV().equals(other.nodeV()); 240  } 241  return nodeU().equals(other.nodeV()) && nodeV().equals(other.nodeU()); // check condition2 242  } 243  244  @Override 245  public int hashCode() { 246  return nodeU().hashCode() + nodeV().hashCode(); 247  } 248  249  @Override 250  public String toString() { 251  return "[" + nodeU() + ", " + nodeV() + "]"; 252  } 253  } 254 }