/*
* Copyright (C) 2019 Claus Schätzle (schaetzc@tf.uni-freiburg.de)
* Copyright (C) 2019 University of Freiburg
*
* This file is part of the ULTIMATE Util Library.
*
* The ULTIMATE Util Library is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published
* by the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* The ULTIMATE Util Library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with the ULTIMATE Util Library. If not, see .
*
* Additional permission under GNU GPL version 3 section 7:
* If you modify the ULTIMATE Util Library, or any covered work, by linking
* or combining it with Eclipse RCP (or a modified version of Eclipse RCP),
* containing parts covered by the terms of the Eclipse Public License, the
* licensors of the ULTIMATE Util Library grant you additional permission
* to convey the resulting work.
*/
package de.uni_freiburg.informatik.ultimate.util;
import java.util.HashMap;
import java.util.Map;
import de.uni_freiburg.informatik.ultimate.util.datastructures.GraphToTgf;
/**
* Converts a list of edges into a string using the Trivial Graph Format (TGF) file format.
* TGF files can be interpreted as directed or undirected graphs –
* this information itself isn't stored in TGF files.
*
* The graph has to be enumerated manually using {@link #addEdge(N, Object, N)}
* (and {@link #addDisconnectedNode(N)} if there are any disconnected nodes).
* The resulting TGF is returned by {@link #toString()}.
*
* Nodes in the graph are identified by object equality according to {@link Object#equals(Object)}
* and labeled using the canonical string representation {@link Object#toString()}. The same edge
* can be added multiple times. {@code null} nodes and edge labels are supported.
*
*
* @param Type of the nodes in the graph. It is perfectly fine to use {@code Object} here.
* However, you might want to use a more concrete type to prevent accidentally using the wrong
* objects as nodes.
*
* @author schaetzc@tf.uni-freiburg.de
*
* @see GraphToTgf Converts a given graph to TGF without having to manually add edges and nodes
*/
public class TgfBuilder {
private final StringBuilder mTgfNodes = new StringBuilder();
private final StringBuilder mTgfEdges = new StringBuilder();
private final Map mNodeToId = new HashMap<>();
public TgfBuilder addEdge(final N sourceNode, final Object edgeLabel, final N targetNode) {
mTgfEdges
.append(nodeId(sourceNode)).append(' ')
.append(nodeId(targetNode)).append(' ')
.append(labelOf(edgeLabel)).append('\n');
return this;
}
public TgfBuilder addDisconnectedNode(final N node) {
nodeId(node);
return this;
}
private int nodeId(final N node) {
return mNodeToId.computeIfAbsent(node, this::computeNewNodeIdAndAddToTgf);
}
private int computeNewNodeIdAndAddToTgf(final N node) {
final int id = mNodeToId.size();
mTgfNodes.append(id).append(' ').append(labelOf(node)).append('\n');
return id;
}
private static String labelOf(final Object nodeOrEdge) {
// A newline in a label would break the TGF format
return nodeOrEdge.toString().replace('\n', '@');
}
@Override
public String toString() {
return new StringBuilder()
.append(mTgfNodes)
.append("#\n")
.append(mTgfEdges)
.toString();
}
public void reset() {
mTgfNodes.setLength(0);
mTgfEdges.setLength(0);
mNodeToId.clear();
}
}