001/* 002 * Copyright (C) 2016 The Guava Authors 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * http://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 */ 016 017package com.google.common.graph; 018 019import static com.google.common.base.Preconditions.checkNotNull; 020import static java.util.Objects.requireNonNull; 021 022import com.google.common.annotations.Beta; 023import com.google.common.base.Function; 024import com.google.common.collect.ImmutableMap; 025import com.google.common.collect.Maps; 026import com.google.errorprone.annotations.CanIgnoreReturnValue; 027import com.google.errorprone.annotations.Immutable; 028 029/** 030 * A {@link ValueGraph} whose elements and structural relationships will never change. Instances of 031 * this class may be obtained with {@link #copyOf(ValueGraph)}. 032 * 033 * <p>See the Guava User's Guide's <a 034 * href="https://github.com/google/guava/wiki/GraphsExplained#immutable-implementations">discussion 035 * of the {@code Immutable*} types</a> for more information on the properties and guarantees 036 * provided by this class. 037 * 038 * @author James Sexton 039 * @author Jens Nyman 040 * @param <N> Node parameter type 041 * @param <V> Value parameter type 042 * @since 20.0 043 */ 044@Beta 045@Immutable(containerOf = {"N", "V"}) 046@SuppressWarnings("Immutable") // Extends StandardValueGraph but uses ImmutableMaps. 047public final class ImmutableValueGraph<N, V> extends StandardValueGraph<N, V> { 048 049 private ImmutableValueGraph(ValueGraph<N, V> graph) { 050 super(ValueGraphBuilder.from(graph), getNodeConnections(graph), graph.edges().size()); 051 } 052 053 /** Returns an immutable copy of {@code graph}. */ 054 public static <N, V> ImmutableValueGraph<N, V> copyOf(ValueGraph<N, V> graph) { 055 return (graph instanceof ImmutableValueGraph) 056 ? (ImmutableValueGraph<N, V>) graph 057 : new ImmutableValueGraph<N, V>(graph); 058 } 059 060 /** 061 * Simply returns its argument. 062 * 063 * @deprecated no need to use this 064 */ 065 @Deprecated 066 public static <N, V> ImmutableValueGraph<N, V> copyOf(ImmutableValueGraph<N, V> graph) { 067 return checkNotNull(graph); 068 } 069 070 @Override 071 public ElementOrder<N> incidentEdgeOrder() { 072 return ElementOrder.stable(); 073 } 074 075 @Override 076 public ImmutableGraph<N> asGraph() { 077 return new ImmutableGraph<>(this); // safe because the view is effectively immutable 078 } 079 080 private static <N, V> ImmutableMap<N, GraphConnections<N, V>> getNodeConnections( 081 ValueGraph<N, V> graph) { 082 // ImmutableMap.Builder maintains the order of the elements as inserted, so the map will have 083 // whatever ordering the graph's nodes do, so ImmutableSortedMap is unnecessary even if the 084 // input nodes are sorted. 085 ImmutableMap.Builder<N, GraphConnections<N, V>> nodeConnections = ImmutableMap.builder(); 086 for (N node : graph.nodes()) { 087 nodeConnections.put(node, connectionsOf(graph, node)); 088 } 089 return nodeConnections.buildOrThrow(); 090 } 091 092 private static <N, V> GraphConnections<N, V> connectionsOf(ValueGraph<N, V> graph, N node) { 093 Function<N, V> successorNodeToValueFn = 094 (N successorNode) -> 095 // requireNonNull is safe because the endpoint pair comes from the graph. 096 requireNonNull(graph.edgeValueOrDefault(node, successorNode, null)); 097 return graph.isDirected() 098 ? DirectedGraphConnections.ofImmutable( 099 node, graph.incidentEdges(node), successorNodeToValueFn) 100 : UndirectedGraphConnections.ofImmutable( 101 Maps.asMap(graph.adjacentNodes(node), successorNodeToValueFn)); 102 } 103 104 /** 105 * A builder for creating {@link ImmutableValueGraph} instances, especially {@code static final} 106 * graphs. Example: 107 * 108 * <pre>{@code 109 * static final ImmutableValueGraph<City, Distance> CITY_ROAD_DISTANCE_GRAPH = 110 * ValueGraphBuilder.undirected() 111 * .<City, Distance>immutable() 112 * .putEdgeValue(PARIS, BERLIN, kilometers(1060)) 113 * .putEdgeValue(PARIS, BRUSSELS, kilometers(317)) 114 * .putEdgeValue(BERLIN, BRUSSELS, kilometers(764)) 115 * .addNode(REYKJAVIK) 116 * .build(); 117 * }</pre> 118 * 119 * <p>Builder instances can be reused; it is safe to call {@link #build} multiple times to build 120 * multiple graphs in series. Each new graph contains all the elements of the ones created before 121 * it. 122 * 123 * @since 28.0 124 */ 125 public static class Builder<N, V> { 126 127 private final MutableValueGraph<N, V> mutableValueGraph; 128 129 Builder(ValueGraphBuilder<N, V> graphBuilder) { 130 // The incidentEdgeOrder for immutable graphs is always stable. However, we don't want to 131 // modify this builder, so we make a copy instead. 132 this.mutableValueGraph = 133 graphBuilder.copy().incidentEdgeOrder(ElementOrder.<N>stable()).build(); 134 } 135 136 /** 137 * Adds {@code node} if it is not already present. 138 * 139 * <p><b>Nodes must be unique</b>, just as {@code Map} keys must be. They must also be non-null. 140 * 141 * @return this {@code Builder} object 142 */ 143 @CanIgnoreReturnValue 144 public ImmutableValueGraph.Builder<N, V> addNode(N node) { 145 mutableValueGraph.addNode(node); 146 return this; 147 } 148 149 /** 150 * Adds an edge connecting {@code nodeU} to {@code nodeV} if one is not already present, and 151 * sets a value for that edge to {@code value} (overwriting the existing value, if any). 152 * 153 * <p>If the graph is directed, the resultant edge will be directed; otherwise, it will be 154 * undirected. 155 * 156 * <p>Values do not have to be unique. However, values must be non-null. 157 * 158 * <p>If {@code nodeU} and {@code nodeV} are not already present in this graph, this method will 159 * silently {@link #addNode(Object) add} {@code nodeU} and {@code nodeV} to the graph. 160 * 161 * @return this {@code Builder} object 162 * @throws IllegalArgumentException if the introduction of the edge would violate {@link 163 * #allowsSelfLoops()} 164 */ 165 @CanIgnoreReturnValue 166 public ImmutableValueGraph.Builder<N, V> putEdgeValue(N nodeU, N nodeV, V value) { 167 mutableValueGraph.putEdgeValue(nodeU, nodeV, value); 168 return this; 169 } 170 171 /** 172 * Adds an edge connecting {@code endpoints} if one is not already present, and sets a value for 173 * that edge to {@code value} (overwriting the existing value, if any). 174 * 175 * <p>If the graph is directed, the resultant edge will be directed; otherwise, it will be 176 * undirected. 177 * 178 * <p>If this graph is directed, {@code endpoints} must be ordered. 179 * 180 * <p>Values do not have to be unique. However, values must be non-null. 181 * 182 * <p>If either or both endpoints are not already present in this graph, this method will 183 * silently {@link #addNode(Object) add} each missing endpoint to the graph. 184 * 185 * @return this {@code Builder} object 186 * @throws IllegalArgumentException if the introduction of the edge would violate {@link 187 * #allowsSelfLoops()} 188 * @throws IllegalArgumentException if the endpoints are unordered and the graph is directed 189 */ 190 @CanIgnoreReturnValue 191 public ImmutableValueGraph.Builder<N, V> putEdgeValue(EndpointPair<N> endpoints, V value) { 192 mutableValueGraph.putEdgeValue(endpoints, value); 193 return this; 194 } 195 196 /** 197 * Returns a newly-created {@code ImmutableValueGraph} based on the contents of this {@code 198 * Builder}. 199 */ 200 public ImmutableValueGraph<N, V> build() { 201 return ImmutableValueGraph.copyOf(mutableValueGraph); 202 } 203 } 204}