All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.google.common.graph.EndpointPair Maven / Gradle / Ivy

Go to download

This artifact provides a single jar that contains all classes required to use remote EJB and JMS, including all dependencies. It is intended for use by those not using maven, maven users should just import the EJB and JMS BOM's instead (shaded JAR's cause lots of problems with maven, as it is very easy to inadvertently end up with different versions on classes on the class path).

The newest version!
/*
 * Copyright (C) 2016 The Guava Authors
 *
 * 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.
 */

package com.google.common.graph;

import static com.google.common.base.Preconditions.checkNotNull;
import static com.google.common.graph.GraphConstants.NOT_AVAILABLE_ON_UNDIRECTED;

import com.google.common.annotations.Beta;
import com.google.common.base.Objects;
import com.google.common.collect.Iterators;
import com.google.common.collect.UnmodifiableIterator;
import com.google.errorprone.annotations.Immutable;
import javax.annotation.CheckForNull;

/**
 * An immutable pair representing the two endpoints of an edge in a graph. The {@link EndpointPair}
 * of a directed edge is an ordered pair of nodes ({@link #source()} and {@link #target()}). The
 * {@link EndpointPair} of an undirected edge is an unordered pair of nodes ({@link #nodeU()} and
 * {@link #nodeV()}).
 *
 * 

The edge is a self-loop if, and only if, the two endpoints are equal. * * @author James Sexton * @since 20.0 */ @Beta @Immutable(containerOf = {"N"}) @ElementTypesAreNonnullByDefault public abstract class EndpointPair implements Iterable { private final N nodeU; private final N nodeV; private EndpointPair(N nodeU, N nodeV) { this.nodeU = checkNotNull(nodeU); this.nodeV = checkNotNull(nodeV); } /** Returns an {@link EndpointPair} representing the endpoints of a directed edge. */ public static EndpointPair ordered(N source, N target) { return new Ordered<>(source, target); } /** Returns an {@link EndpointPair} representing the endpoints of an undirected edge. */ public static EndpointPair unordered(N nodeU, N nodeV) { // Swap nodes on purpose to prevent callers from relying on the "ordering" of an unordered pair. return new Unordered<>(nodeV, nodeU); } /** Returns an {@link EndpointPair} representing the endpoints of an edge in {@code graph}. */ static EndpointPair of(Graph graph, N nodeU, N nodeV) { return graph.isDirected() ? ordered(nodeU, nodeV) : unordered(nodeU, nodeV); } /** Returns an {@link EndpointPair} representing the endpoints of an edge in {@code network}. */ static EndpointPair of(Network network, N nodeU, N nodeV) { return network.isDirected() ? ordered(nodeU, nodeV) : unordered(nodeU, nodeV); } /** * If this {@link EndpointPair} {@link #isOrdered()}, returns the node which is the source. * * @throws UnsupportedOperationException if this {@link EndpointPair} is not ordered */ public abstract N source(); /** * If this {@link EndpointPair} {@link #isOrdered()}, returns the node which is the target. * * @throws UnsupportedOperationException if this {@link EndpointPair} is not ordered */ public abstract N target(); /** * If this {@link EndpointPair} {@link #isOrdered()} returns the {@link #source()}; otherwise, * returns an arbitrary (but consistent) endpoint of the origin edge. */ public final N nodeU() { return nodeU; } /** * Returns the node {@link #adjacentNode(Object) adjacent} to {@link #nodeU()} along the origin * edge. If this {@link EndpointPair} {@link #isOrdered()}, this is equal to {@link #target()}. */ public final N nodeV() { return nodeV; } /** * Returns the node that is adjacent to {@code node} along the origin edge. * * @throws IllegalArgumentException if this {@link EndpointPair} does not contain {@code node} * @since 20.0 (but the argument type was changed from {@code Object} to {@code N} in 31.0) */ public final N adjacentNode(N node) { if (node.equals(nodeU)) { return nodeV; } else if (node.equals(nodeV)) { return nodeU; } else { throw new IllegalArgumentException("EndpointPair " + this + " does not contain node " + node); } } /** * Returns {@code true} if this {@link EndpointPair} is an ordered pair (i.e. represents the * endpoints of a directed edge). */ public abstract boolean isOrdered(); /** Iterates in the order {@link #nodeU()}, {@link #nodeV()}. */ @Override public final UnmodifiableIterator iterator() { return Iterators.forArray(nodeU, nodeV); } /** * Two ordered {@link EndpointPair}s are equal if their {@link #source()} and {@link #target()} * are equal. Two unordered {@link EndpointPair}s are equal if they contain the same nodes. An * ordered {@link EndpointPair} is never equal to an unordered {@link EndpointPair}. */ @Override public abstract boolean equals(@CheckForNull Object obj); /** * The hashcode of an ordered {@link EndpointPair} is equal to {@code Objects.hashCode(source(), * target())}. The hashcode of an unordered {@link EndpointPair} is equal to {@code * nodeU().hashCode() + nodeV().hashCode()}. */ @Override public abstract int hashCode(); private static final class Ordered extends EndpointPair { private Ordered(N source, N target) { super(source, target); } @Override public N source() { return nodeU(); } @Override public N target() { return nodeV(); } @Override public boolean isOrdered() { return true; } @Override public boolean equals(@CheckForNull Object obj) { if (obj == this) { return true; } if (!(obj instanceof EndpointPair)) { return false; } EndpointPair other = (EndpointPair) obj; if (isOrdered() != other.isOrdered()) { return false; } return source().equals(other.source()) && target().equals(other.target()); } @Override public int hashCode() { return Objects.hashCode(source(), target()); } @Override public String toString() { return "<" + source() + " -> " + target() + ">"; } } private static final class Unordered extends EndpointPair { private Unordered(N nodeU, N nodeV) { super(nodeU, nodeV); } @Override public N source() { throw new UnsupportedOperationException(NOT_AVAILABLE_ON_UNDIRECTED); } @Override public N target() { throw new UnsupportedOperationException(NOT_AVAILABLE_ON_UNDIRECTED); } @Override public boolean isOrdered() { return false; } @Override public boolean equals(@CheckForNull Object obj) { if (obj == this) { return true; } if (!(obj instanceof EndpointPair)) { return false; } EndpointPair other = (EndpointPair) obj; if (isOrdered() != other.isOrdered()) { return false; } // Equivalent to the following simple implementation: // boolean condition1 = nodeU().equals(other.nodeU()) && nodeV().equals(other.nodeV()); // boolean condition2 = nodeU().equals(other.nodeV()) && nodeV().equals(other.nodeU()); // return condition1 || condition2; if (nodeU().equals(other.nodeU())) { // check condition1 // Here's the tricky bit. We don't have to explicitly check for condition2 in this case. // Why? The second half of condition2 requires that nodeV equals other.nodeU. // We already know that nodeU equals other.nodeU. Combined with the earlier statement, // and the transitive property of equality, this implies that nodeU equals nodeV. // If nodeU equals nodeV, condition1 == condition2, so checking condition1 is sufficient. return nodeV().equals(other.nodeV()); } return nodeU().equals(other.nodeV()) && nodeV().equals(other.nodeU()); // check condition2 } @Override public int hashCode() { return nodeU().hashCode() + nodeV().hashCode(); } @Override public String toString() { return "[" + nodeU() + ", " + nodeV() + "]"; } } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy