blob: c4700b38404ba1088b4709bc071f9d329c767028 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2015 École Polytechnique de Montréal
*
* All rights reserved. This program and the accompanying materials are made
* available under the terms of the Eclipse Public License 2.0 which
* accompanies this distribution, and is available at
* https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* Francis Giraldeau - Initial implementation and API
* Geneviève Bastien - Initial implementation and API
*******************************************************************************/
package org.eclipse.tracecompass.analysis.graph.core.base;
import java.util.Comparator;
import java.util.Objects;
import org.eclipse.jdt.annotation.Nullable;
import org.eclipse.tracecompass.analysis.graph.core.base.TmfEdge.EdgeType;
import org.eclipse.tracecompass.internal.analysis.graph.core.base.Messages;
/**
* Timed vertex for TmfGraph
*
* @author Francis Giraldeau
* @author Geneviève Bastien
*/
public class TmfVertex implements Comparable<TmfVertex> {
private static final String UNKNOWN_EDGE_DIRECTION_TYPE = "Unknown edge direction type : "; //$NON-NLS-1$
private static long count = 0;
/**
* Describe the four edges coming in and out of a vertex
*/
public enum EdgeDirection {
/**
* Constant for the outgoing vertical edge (to other object)
*/
OUTGOING_VERTICAL_EDGE,
/**
* Constant for the incoming vertical edge (from other object)
*/
INCOMING_VERTICAL_EDGE,
/**
* Constant for the outgoing horizontal edge (to same object)
*/
OUTGOING_HORIZONTAL_EDGE,
/**
* Constant for the incoming horizontal edge (from same object)
*/
INCOMING_HORIZONTAL_EDGE
}
/**
* Compare vertices by ascending timestamps
*/
public static Comparator<TmfVertex> ascending = Objects.requireNonNull(Comparator.nullsLast(Comparator.comparing(TmfVertex::getTs)));
/**
* Compare vertices by descending timestamps
*/
public static Comparator<TmfVertex> descending = Objects.requireNonNull(Comparator.nullsLast(Comparator.comparing(TmfVertex::getTs).reversed()));
private @Nullable TmfEdge fOutgoingVertical = null;
private @Nullable TmfEdge fIncomingVertical = null;
private @Nullable TmfEdge fOutgoingHorizontal = null;
private @Nullable TmfEdge fIncomingHorizontal = null;
private final long fTimestamp;
private final long fId;
/**
* Default Constructor
*/
public TmfVertex() {
this(0);
}
/**
* Constructor with timestamp
*
* @param ts
* The vertex's timestamp
*/
public TmfVertex(final long ts) {
fTimestamp = ts;
synchronized (TmfVertex.class) {
fId = count++;
}
}
/**
* Copy constructor. Keeps same timestamp, but does not keep edges
*
* @param node
* vertex to copy
*/
public TmfVertex(TmfVertex node) {
this(node.fTimestamp);
}
/**
* Copy constructor, but changes the timestamp
*
* @param node
* vertex to copy
* @param ts
* The timestamp of this new node
*/
public TmfVertex(TmfVertex node, final long ts) {
fTimestamp = ts;
synchronized (TmfVertex.class) {
fId = count++;
}
fOutgoingVertical = node.fOutgoingVertical;
fIncomingVertical = node.fIncomingVertical;
fOutgoingHorizontal = node.fOutgoingHorizontal;
fIncomingHorizontal = node.fIncomingHorizontal;
}
/*
* Getters and setters
*/
/**
* Returns the timestamps of this node
*
* @return the timstamp
*/
public long getTs() {
return fTimestamp;
}
/**
* Returns the unique ID of this node
*
* @return the vertex's id
*/
public long getID() {
return fId;
}
/**
* Adds an horizontal edge from the current vertex to the 'to' vertex
*
* @param to
* The vertex to link to, belongs to the same object
*
* @return The new edge
*/
public TmfEdge linkHorizontal(TmfVertex to) {
checkTimestamps(to);
checkNotSelf(to);
return linkHorizontalRaw(to);
}
/**
* Adds an horizontal edge from the current vertex to the 'to' vertex
*
* @param to
* The vertex to link to, belongs to the same object
* @param type
* The type of the link to add
* @param linkQualifier
* An optional qualifier to identify this link
*
* @return The new edge
* @since 2.1
*/
public TmfEdge linkHorizontal(TmfVertex to, EdgeType type, @Nullable String linkQualifier) {
checkTimestamps(to);
checkNotSelf(to);
TmfEdge link = linkHorizontalRaw(to);
link.setType(type, linkQualifier);
return link;
}
private TmfEdge linkHorizontalRaw(TmfVertex node) {
TmfEdge link = new TmfEdge(this, node);
fOutgoingHorizontal = link;
node.fIncomingHorizontal = link;
return link;
}
/**
* Adds a vertical edge from the current vertex to the 'to' vertex
*
* @param to
* The vertex to link to, belongs to a different object
* @return The new edge
*/
public TmfEdge linkVertical(TmfVertex to) {
checkTimestamps(to);
checkNotSelf(to);
return linkVerticalRaw(to);
}
/**
* Adds a vertical edge from the current vertex to the 'to' vertex
*
* @param to
* The vertex to link to, belongs to a different object
* @param type
* The type of the link to add
* @param linkQualifier
* An optional qualifier to identify this link
* @return The new edge
* @since 2.1
*/
public TmfEdge linkVertical(TmfVertex to, EdgeType type, @Nullable String linkQualifier) {
checkTimestamps(to);
checkNotSelf(to);
TmfEdge link = linkVerticalRaw(to);
link.setType(type, linkQualifier);
return link;
}
private TmfEdge linkVerticalRaw(TmfVertex to) {
TmfEdge link = new TmfEdge(this, to);
fOutgoingVertical = link;
to.fIncomingVertical = link;
return link;
}
private void checkTimestamps(TmfVertex to) {
if (this.fTimestamp > to.fTimestamp) {
throw new IllegalArgumentException(Messages.TmfVertex_ArgumentTimestampLower +
String.format(": (curr=%d,next=%d,elapsed=%d)", fTimestamp, to.fTimestamp, to.fTimestamp - fTimestamp)); //$NON-NLS-1$
}
}
private void checkNotSelf(TmfVertex to) {
if (this == to) {
throw new IllegalArgumentException(Messages.TmfVertex_CannotLinkToSelf);
}
}
/**
* Get an edge to or from this vertex in the appropriate direction
*
* @param dir
* The direction of the requested edge
* @return The edge from this vertex to the requested direction
*/
public @Nullable TmfEdge getEdge(EdgeDirection dir) {
switch (dir) {
case OUTGOING_VERTICAL_EDGE:
return fOutgoingVertical;
case INCOMING_VERTICAL_EDGE:
return fIncomingVertical;
case OUTGOING_HORIZONTAL_EDGE:
return fOutgoingHorizontal;
case INCOMING_HORIZONTAL_EDGE:
return fIncomingHorizontal;
default:
throw new IllegalStateException(UNKNOWN_EDGE_DIRECTION_TYPE + dir);
}
}
/**
* Removes a directed edge from this vertex. The edge in that direction will
* be null.
*
* @param dir
* The direction to remove the edge from
*/
public void removeEdge(EdgeDirection dir) {
switch (dir) {
case OUTGOING_VERTICAL_EDGE:
fOutgoingVertical = null;
break;
case INCOMING_VERTICAL_EDGE:
fIncomingVertical = null;
break;
case OUTGOING_HORIZONTAL_EDGE:
fOutgoingHorizontal = null;
break;
case INCOMING_HORIZONTAL_EDGE:
fIncomingHorizontal = null;
break;
default:
throw new IllegalStateException(UNKNOWN_EDGE_DIRECTION_TYPE + dir);
}
}
/**
* Get the neighbor of a vertex from a directed edge. Incoming edges will
* return the vertex from the edge and outgoing edges will return the vertex
* to. This method is a utility method that can be used in code where the
* direction is a variable. If the edge direction is known (using one of the
* EdgeDirection constant), it is preferable to use the
* {@link TmfEdge#getVertexFrom()} and {@link TmfEdge#getVertexTo()}
* directly.
*
* @param edge
* The edge for which to get the right neighbor
* @param dir
* The direction of this edge
* @return The vertex that neighbors another vertex in the requested
* direction
*/
public static TmfVertex getNeighborFromEdge(TmfEdge edge, EdgeDirection dir) {
switch (dir) {
case OUTGOING_VERTICAL_EDGE:
case OUTGOING_HORIZONTAL_EDGE:
return edge.getVertexTo();
case INCOMING_VERTICAL_EDGE:
case INCOMING_HORIZONTAL_EDGE:
return edge.getVertexFrom();
default:
throw new IllegalStateException(UNKNOWN_EDGE_DIRECTION_TYPE + dir);
}
}
@Override
public int compareTo(@Nullable TmfVertex other) {
if (other == null) {
return 1;
}
return Long.compare(fTimestamp, other.fTimestamp);
}
@Override
public String toString() {
return "[" + fId + "," + fTimestamp + "]"; //$NON-NLS-1$ //$NON-NLS-2$//$NON-NLS-3$
}
}