ImmutableMemoryUnit.java

package dev.civl.mc.state.common.immutable;

import java.io.PrintStream;

import dev.civl.mc.state.IF.MemoryUnit;
import dev.civl.sarl.IF.SymbolicUniverse;
import dev.civl.sarl.IF.expr.ReferenceExpression;

public class ImmutableMemoryUnit implements MemoryUnit {

	/* ************************** Instance Fields ************************** */

	/**
	 * The ID of the dyscope that this memory unit belongs to.
	 */
	private int dyscopeID;

	/**
	 * The ID of the variable that this memory unit corresponds to.
	 */
	private int varID;

	/**
	 * The reference that describes how this memory unit relates to the
	 * corresponding variable, e.g., array element, tuple component, identity,
	 * etc.
	 */
	private ReferenceExpression reference;

	/**
	 * Is this instance the canonic representative of its equivalence class
	 * under the "equals" method?
	 */
	private boolean canonic = false;

	/**
	 * If the hash code has been computed, it is cached here.
	 */
	private int hashCode = -1;

	/**
	 * Has the hash code been computed?
	 */
	private boolean hashed = false;

	/* **************************** Constructor **************************** */

	/**
	 * Creates a new instance of memory unit.
	 * 
	 * @param dyscopeID
	 *            The ID of the dyscope that the new memory unit belongs to.
	 * @param varID
	 *            The ID of the variable that the new memory unit corresponds
	 *            to.
	 * @param reference
	 *            The reference that shows how the new memory unit relates to
	 *            the corresponding variable.
	 */
	ImmutableMemoryUnit(int dyscopeID, int varID,
			ReferenceExpression reference) {
		this.dyscopeID = dyscopeID;
		this.varID = varID;
		this.reference = reference;
	}

	/* ********************** Package-private Methods ********************** */
	/**
	 * Makes this instance the canonic representative of its equivalence class
	 * under "equals". Makes all the variable values canonic as well.
	 * 
	 * @param universe
	 *            the symbolic universe that is used to make the variable values
	 *            canonic
	 */
	void makeCanonic(SymbolicUniverse universe) {
		assert !canonic;
		canonic = true;
	}

	/**
	 * Is this instance the unique representative of its equivalence class?
	 * 
	 * @return true iff this is the canonic representative of its equivalence
	 *         class
	 */
	boolean isCanonic() {
		return this.canonic;
	}

	/* ********************** Methods from MemoryUnit ********************** */

	@Override
	public int dyscopeID() {
		return this.dyscopeID;
	}

	@Override
	public int varID() {
		return this.varID;
	}

	@Override
	public ReferenceExpression reference() {
		return this.reference;
	}

	/* ************************ Methods from Object ************************ */

	@Override
	public String toString() {
		return "(" + dyscopeID + ", " + varID + ", " + reference + ")";
	}

	@Override
	public boolean equals(Object obj) {
		if (this == obj)
			return true;
		if (obj instanceof ImmutableMemoryUnit) {
			ImmutableMemoryUnit that = (ImmutableMemoryUnit) obj;

			if (this.canonic && that.canonic)
				return false;
			if (this.dyscopeID != that.dyscopeID)
				return false;
			if (this.varID != that.varID)
				return false;
			return this.reference.equals(that.reference);
		}
		return false;
	}

	@Override
	public int hashCode() {
		if (!hashed) {
			hashCode = dyscopeID ^ (31 * varID) ^ reference.hashCode();
		}
		return hashCode;
	}

	@Override
	public void print(PrintStream out) {
		out.print(toString());
	}

	@Override
	public MemoryUnit setReference(ReferenceExpression ref) {
		return new ImmutableMemoryUnit(this.dyscopeID, this.varID, ref);
	}

}