/******************************************************************************* * 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 v1.0 which * accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * 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 org.eclipse.jdt.annotation.Nullable; /** * Timed vertex for TmfGraph * * @author Francis Giraldeau * @author Geneviève Bastien */ public class TmfVertex implements Comparable<TmfVertex> { 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 = new Comparator<TmfVertex>() { @Override public int compare(@Nullable TmfVertex v1, @Nullable TmfVertex v2) { if (v1 == null) { return 1; } if (v2 == null) { return -1; } return v1.getTs() > v2.getTs() ? 1 : (v1.getTs() == v2.getTs() ? 0 : -1); } }; /** * Compare vertices by descending timestamps */ public static Comparator<TmfVertex> descending = new Comparator<TmfVertex>() { @Override public int compare(@Nullable TmfVertex v1, @Nullable TmfVertex v2) { if (v1 == null) { return -1; } if (v2 == null) { return 1; } return v1.getTs() < v2.getTs() ? 1 : (v1.getTs() == v2.getTs() ? 0 : -1); } }; 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); } 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); } 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); //$NON-NLS-1$ } } /** * 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); //$NON-NLS-1$ } } /** * 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); //$NON-NLS-1$ } } @Override public int compareTo(@Nullable TmfVertex other) { if (other == null) { return 1; } return this.fTimestamp > other.fTimestamp ? 1 : (this.fTimestamp == other.fTimestamp ? 0 : -1); } @Override public String toString() { return "[" + fId + "," + fTimestamp + "]"; //$NON-NLS-1$ //$NON-NLS-2$//$NON-NLS-3$ } }