MorphicObject.java
package edu.udel.cis.vsl.tass.morph;
/**
* A simple, partial implementation of Morphic, intended to be extended.
*
* @author siegel
*
*/
public abstract class MorphicObject implements Morphic {
/** Has this component been committed? */
private boolean isCommitted = false;
/**
* Is this a canonic version of this component? Invariant: isCanonic =>
* isCommitted.
*/
private boolean isCanonic = false;
/**
* Has the hash code been computed and cached since this object was
* committed? Invariant: hashed => isCommitted.
*/
private boolean hashed = false;
/** The cached hashCode, which is used only if hashed is true. */
private int hashCode = -1;
/**
* Determines whether the given component is equivalent to this one without
* relying on any special knowledge such as whether the objects are
* canonical. This method should be defined in the subclass. It does the
* "real work", comparing fields, and so on.
*/
protected abstract boolean computeEquals(Morphic component);
/**
* Computes and returns the hash code for this component. Must be overridden
* by the subclass.
*/
protected abstract int computeHashCode();
/**
* An optimized equals methods. If the two objects are canonical components,
* can use ==.
*/
@Override
public boolean equals(Object object) {
if (this == object)
return true;
if (object instanceof MorphicObject) {
MorphicObject that = (MorphicObject) object;
if (isCanonic && that.isCanonic)
return false;
if (hashed && that.hashed && hashCode != that.hashCode)
return false;
return computeEquals(that);
}
return false;
}
/**
* An optimized hashCode function. If the object is committed and the hash
* code has been cached, returns the cached copy.
*/
@Override
public int hashCode() {
if (hashed) {
return hashCode;
} else {
int result = computeHashCode();
if (isCommitted) {
hashed = true;
hashCode = result;
}
return result;
}
}
/**
* Sets the commit bit to true and commits all children.
*/
@Override
public void commit() {
if (isCommitted)
return;
isCommitted = true;
commitChildren();
}
protected abstract void commitChildren();
/**
* Sets the canonical bit to true. Requires that the object is already
* committed.
*/
protected void canonicalize() {
assert isCommitted;
isCanonic = true;
}
@Override
public boolean isCanonic() {
return isCanonic;
}
@Override
public boolean isCommitted() {
return isCommitted;
}
@Override
public String descriptor() {
if (!isCommitted) {
return "";
}
if (!isCanonic()) {
return "(committed)";
}
return "(canonic)";
}
}