Process.java

/**
 * 
 */
package edu.udel.cis.vsl.civl.state;

import java.io.PrintStream;
import java.util.Arrays;

import edu.udel.cis.vsl.civl.model.IF.location.Location;

/**
 * An instance of Process represents the state of a process (thread of
 * execution) in a Chapel model. The process has an id.
 * 
 * @author Timothy K. Zirkel (zirkel)
 * @author Timothy J. McClory (tmcclory)
 * 
 */
public class Process {

	private boolean hashed = false;

	boolean canonic = false;

	private int hashCode = -1;

	private int id;

	/**
	 * A non-null array. Entry 0 is the TOP of the stack.
	 */
	private StackEntry[] callStack;

	/**
	 * A new process state with empty stack.
	 * 
	 * @param id
	 *            The unique process ID.
	 */
	Process(int id) {
		this.id = id;
		callStack = new StackEntry[0];
	}

	Process(int id, StackEntry[] stack) {
		assert stack != null;
		this.id = id;
		callStack = stack;
	}

	Process(Process oldProcess, int newPid) {
		this.id = newPid;
		this.callStack = oldProcess.callStack;
	}

	/**
	 * @return The unique process ID.
	 */
	public int id() {
		return id;
	}

	/**
	 * @param id
	 *            The unique process ID.
	 */
	void setId(int id) {
		this.id = id;
	}

	Process copy() {
		StackEntry[] newStack = new StackEntry[callStack.length];

		System.arraycopy(callStack, 0, newStack, 0, callStack.length);
		return new Process(id, newStack);
	}

	public boolean hasEmptyStack() {
		return callStack.length == 0;
	}

	/**
	 * @return The current location of this process.
	 */
	public Location location() {
		return callStack[0].location();
	}

	/**
	 * @return The id of the current dynamic scope of this process.
	 */
	public int scope() {
		return callStack[0].scope();
	}

	/**
	 * Look at the first entry on the call stack, but do not remove it.
	 * 
	 * @return The first entry on the call stack. Null if empty.
	 */

	public StackEntry peekStack() {
		return callStack[0];
	}

	public int stackSize() {
		return callStack.length;
	}

	/**
	 * Returns i-th entry on stack, where 0 is the TOP of the stack, and
	 * stackSize-1 is the BOTTOM of the stack.
	 * 
	 * @param i
	 *            int in [0,stackSize-1]
	 * @return i-th entry on stack
	 */
	public StackEntry getStackEntry(int i) {
		return callStack[i];
	}

	Process pop() {
		StackEntry[] newStack = new StackEntry[callStack.length - 1];

		System.arraycopy(callStack, 1, newStack, 0, callStack.length - 1);
		return new Process(id, newStack);
	}

	Process push(StackEntry newStackEntry) {
		StackEntry[] newStack = new StackEntry[callStack.length + 1];

		System.arraycopy(callStack, 0, newStack, 1, callStack.length);
		newStack[0] = newStackEntry;
		return new Process(id, newStack);
	}

	Process replaceTop(StackEntry newStackEntry) {
		int length = callStack.length;
		StackEntry[] newStack = new StackEntry[length];

		System.arraycopy(callStack, 1, newStack, 1, length - 1);
		newStack[0] = newStackEntry;
		return new Process(id, newStack);
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see java.lang.Object#hashCode()
	 */
	@Override
	public int hashCode() {
		if (!hashed) {
			final int prime = 31;

			hashCode = 1;
			hashCode = prime * hashCode + Arrays.hashCode(callStack);
			hashCode = prime * hashCode + id;
			hashed = true;
		}
		return hashCode;
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see java.lang.Object#equals(java.lang.Object)
	 */
	@Override
	public boolean equals(Object obj) {
		if (this == obj)
			return true;
		if (obj instanceof Process) {
			Process that = (Process) obj;

			if (canonic && that.canonic)
				return false;
			if (hashed && that.hashed && hashCode != that.hashCode)
				return false;
			if (!Arrays.equals(callStack, that.callStack))
				return false;
			if (id != that.id)
				return false;
			return true;
		}
		return false;
	}

	public void print(PrintStream out, String prefix) {
		out.println(prefix + "process " + id + " call stack");
		for (int i = 0; i < callStack.length; i++) {
			StackEntry frame = callStack[i];

			out.println(prefix + "| " + frame);
		}
		out.flush();
	}

	@Override
	public String toString() {
		return "State of process " + id + " (call stack length = "
				+ callStack.length + ")";
	}
}