/** * Constructs a graph with the properties specified in {@code builder}, initialized with the given * node and edge maps. */ ConfigurableNetwork( NetworkBuilder<? super N, ? super E> builder, Map<N, NetworkConnections<N, E>> nodeConnections, Map<E, N> edgeToReferenceNode) { this.isDirected = builder.directed; this.allowsParallelEdges = builder.allowsParallelEdges; this.allowsSelfLoops = builder.allowsSelfLoops; this.nodeOrder = builder.nodeOrder.cast(); this.edgeOrder = builder.edgeOrder.cast(); // Prefer the heavier "MapRetrievalCache" for nodes if lookup is expensive. This optimizes // methods that access the same node(s) repeatedly, such as Graphs.removeEdgesConnecting(). this.nodeConnections = (nodeConnections instanceof TreeMap) ? new MapRetrievalCache<N, NetworkConnections<N, E>>(nodeConnections) : new MapIteratorCache<N, NetworkConnections<N, E>>(nodeConnections); this.edgeToReferenceNode = new MapIteratorCache<>(edgeToReferenceNode); }
@Override public boolean contains(@Nullable Object key) { return containsKey(key); } };
@Override @CanIgnoreReturnValue public boolean removeEdge(E edge) { checkNotNull(edge, "edge"); N nodeU = edgeToReferenceNode.get(edge); if (nodeU == null) { return false; } NetworkConnections<N, E> connectionsU = nodeConnections.get(nodeU); N nodeV = connectionsU.adjacentNode(edge); NetworkConnections<N, E> connectionsV = nodeConnections.get(nodeV); connectionsU.removeOutEdge(edge); connectionsV.removeInEdge(edge, allowsSelfLoops() && nodeU.equals(nodeV)); edgeToReferenceNode.remove(edge); return true; }
public V get(@Nullable Object key) { V value = getIfCached(key); return (value != null) ? value : getWithoutCaching(key); }
@Test public void testKeySetIterator() { mapCache.put("A", "A_value"); mapCache.put("B", "B_value"); mapCache.put("C", "C_value"); assertThat(mapCache.unmodifiableKeySet()).hasSize(3); for (String key : mapCache.unmodifiableKeySet()) { assertThat(mapCache.get(key)).isEqualTo(key + "_value"); } }
@Override @CanIgnoreReturnValue public boolean removeNode(N node) { checkNotNull(node, "node"); GraphConnections<N, V> connections = nodeConnections.get(node); if (connections == null) { return false; } if (allowsSelfLoops()) { // Remove self-loop (if any) first, so we don't get CME while removing incident edges. if (connections.removeSuccessor(node) != null) { connections.removePredecessor(node); --edgeCount; } } for (N successor : connections.successors()) { nodeConnections.getWithoutCaching(successor).removePredecessor(node); --edgeCount; } if (isDirected()) { // In undirected graphs, the successor and predecessor sets are equal. for (N predecessor : connections.predecessors()) { checkState(nodeConnections.getWithoutCaching(predecessor).removeSuccessor(node) != null); --edgeCount; } } nodeConnections.remove(node); checkNonNegative(edgeCount); return true; }
@Test public void testRemoveEqualKeyWithDifferentReference() { String fooReference1 = new String("foo"); String fooReference2 = new String("foo"); assertThat(fooReference1).isNotSameAs(fooReference2); assertThat(mapCache.put(fooReference1, "bar")).isNull(); assertThat(mapCache.get(fooReference1)).isEqualTo("bar"); // ensure first reference is cached assertThat(mapCache.remove(fooReference2)).isEqualTo("bar"); assertThat(mapCache.get(fooReference1)).isNull(); }
@Test public void testHandleNulls() { mapCache.put("foo", "bar"); mapCache.put("non-null key", null); mapCache.put(null, "non-null value"); assertThat(mapCache.get("foo")).isEqualTo("bar"); assertThat(mapCache.get("non-null key")).isNull(); assertThat(mapCache.get(null)).isEqualTo("non-null value"); assertThat(mapCache.containsKey("foo")).isTrue(); assertThat(mapCache.containsKey("bar")).isFalse(); assertThat(mapCache.containsKey("non-null key")).isTrue(); assertThat(mapCache.containsKey(null)).isTrue(); // Test again - in reverse order. assertThat(mapCache.get(null)).isEqualTo("non-null value"); assertThat(mapCache.get("non-null key")).isNull(); assertThat(mapCache.get("foo")).isEqualTo("bar"); } }
@Override public Set<N> nodes() { return nodeConnections.unmodifiableKeySet(); }
@Override protected void clearCache() { super.clearCache(); cacheEntry1 = null; cacheEntry2 = null; }
protected final GraphConnections<N, V> checkedConnections(N node) { GraphConnections<N, V> connections = nodeConnections.get(node); if (connections == null) { checkNotNull(node); throw new IllegalArgumentException("Node " + node + " is not an element of this graph."); } return connections; }
/** * Adds {@code node} to the graph and returns the associated {@link NetworkConnections}. * * @throws IllegalStateException if {@code node} is already present */ @CanIgnoreReturnValue private NetworkConnections<N, E> addNodeInternal(N node) { NetworkConnections<N, E> connections = newConnections(); checkState(nodeConnections.put(node, connections) == null); return connections; }
public final boolean containsKey(@Nullable Object key) { return getIfCached(key) != null || backingMap.containsKey(key); }
@Override @CanIgnoreReturnValue public boolean removeNode(N node) { checkNotNull(node, "node"); GraphConnections<N, V> connections = nodeConnections.get(node); if (connections == null) { return false; } if (allowsSelfLoops()) { // Remove self-loop (if any) first, so we don't get CME while removing incident edges. if (connections.removeSuccessor(node) != null) { connections.removePredecessor(node); --edgeCount; } } for (N successor : connections.successors()) { nodeConnections.getWithoutCaching(successor).removePredecessor(node); --edgeCount; } if (isDirected()) { // In undirected graphs, the successor and predecessor sets are equal. for (N predecessor : connections.predecessors()) { checkState(nodeConnections.getWithoutCaching(predecessor).removeSuccessor(node) != null); --edgeCount; } } nodeConnections.remove(node); checkNonNegative(edgeCount); return true; }
@Test public void testKeySetIterator() { mapCache.put("A", "A_value"); mapCache.put("B", "B_value"); mapCache.put("C", "C_value"); assertThat(mapCache.unmodifiableKeySet()).hasSize(3); for (String key : mapCache.unmodifiableKeySet()) { assertThat(mapCache.get(key)).isEqualTo(key + "_value"); } }
@Test public void testRemoveEqualKeyWithDifferentReference() { String fooReference1 = new String("foo"); String fooReference2 = new String("foo"); assertThat(fooReference1).isNotSameAs(fooReference2); assertThat(mapCache.put(fooReference1, "bar")).isNull(); assertThat(mapCache.get(fooReference1)).isEqualTo("bar"); // ensure first reference is cached assertThat(mapCache.remove(fooReference2)).isEqualTo("bar"); assertThat(mapCache.get(fooReference1)).isNull(); }
return false; NetworkConnections<N, E> connectionsU = nodeConnections.get(nodeU); if (!allowsParallelEdges()) { checkArgument( NetworkConnections<N, E> connectionsV = nodeConnections.get(nodeV); if (connectionsV == null) { connectionsV = addNodeInternal(nodeV); edgeToReferenceNode.put(edge, nodeU); return true;
public V get(@NullableDecl Object key) { V value = getIfCached(key); return (value != null) ? value : getWithoutCaching(key); }
@Override public Set<N> nodes() { return nodeConnections.unmodifiableKeySet(); }