MorphicVector.java

package edu.udel.cis.vsl.tass.morph;

import java.util.Arrays;
import java.util.EmptyStackException;
import java.util.Iterator;

public class MorphicVector<T extends Morphic> extends MorphicObject implements
		Iterable<T> {

	private static int initialLength = 2;

	private int size;

	/**
	 * Invariant: data.length >= size. Invariant: forall size <= j <
	 * data.length. data[j] == null.
	 */
	private Morphic[] data;

	/** Construct new component vector with size 0 (and initial length). */
	MorphicVector() {
		data = new Morphic[initialLength];
		size = 0;
	}

	/**
	 * Start a new component vector with this length and size. All entries
	 * initially null.
	 */
	MorphicVector(int size) {
		data = new Morphic[size];
		this.size = size;
	}

	MorphicVector(MorphicVector<T> oldVector) {
		size = oldVector.size;
		data = Arrays.copyOf(oldVector.data, size);
	}

	public int size() {
		return size;
	}

	public void add(T element) {
		assert !isCommitted();
		setElementExtend(size, element);
		size++;
	}

	@SuppressWarnings("unchecked")
	public T get(int index) throws ArrayIndexOutOfBoundsException {
		if (index >= size) {
			throw new ArrayIndexOutOfBoundsException(index);
		}
		return (T) data[index];
	}

	public void set(int index, T element) throws ArrayIndexOutOfBoundsException {
		assert !isCommitted();
		if (index >= size) {
			throw new ArrayIndexOutOfBoundsException(index);
		}
		data[index] = element;
	}

	public void push(T element) {
		add(element);
	}

	@SuppressWarnings("unchecked")
	public T pop() throws EmptyStackException {
		assert !isCommitted();
		if (size == 0) {
			throw new EmptyStackException();
		} else {
			size--;

			T result = (T) data[size];

			data[size] = null;
			return result;
		}
	}

	@SuppressWarnings("unchecked")
	public T peek() throws EmptyStackException {
		if (size == 0) {
			throw new EmptyStackException();
		} else {
			return (T) data[size - 1];
		}
	}

	public T removeElementAt(int position)
			throws ArrayIndexOutOfBoundsException {
		T result = get(position);

		for (int i = position; i < size - 1; i++)
			data[i] = data[i + 1];
		size--;
		data[size] = null;
		return result;
	}

	private void setElementExtend(int index, T value) {
		int length = data.length;

		if (length == 0)
			length = 1;
		while (index >= length)
			length *= 2;
		if (length != data.length) {
			data = Arrays.copyOf(data, length);
		}
		data[index] = value;
	}

	public void setExtend(int index, T value) {
		if (index >= size)
			setSize(index + 1);
		set(index, value);
	}

	public void setSize(int newSize) {
		if (newSize == size) {
			return;
		} else if (newSize < size) {
			for (int i = newSize; i < size; i++)
				data[i] = null;
		} else {
			setElementExtend(newSize - 1, null);
		}
		size = newSize;
	}

	@Override
	protected boolean computeEquals(Morphic component) {
		if (component instanceof MorphicVector<?>) {
			MorphicVector<?> that = (MorphicVector<?>) component;

			if (size != that.size())
				return false;
			for (int i = 0; i < size; i++) {
				Morphic thisElement = data[i];
				Morphic thatElement = that.data[i];

				if (thisElement == null) {
					if (thatElement != null)
						return false;
				} else {
					if (thatElement == null || !thisElement.equals(thatElement))
						return false;
				}
			}
			return true;
		}
		return false;
	}

	@Override
	protected int computeHashCode() {
		int result = 0;

		for (int i = 0; i < size; i++) {
			Morphic datum = data[i];

			if (datum != null)
				result += datum.hashCode();
		}
		return result;
	}

	@SuppressWarnings("unchecked")
	public void canonicalizeChildren(MorphicFactoryIF<? super T> elementFactory) {
		for (int i = 0; i < size; i++) {
			Morphic datum = data[i];

			if (datum != null) {
				Morphic newDatum = elementFactory.canonic((T) datum);

				if (datum != newDatum)
					data[i] = newDatum;
			}
		}
	}

	public int numChildren() {
		return size;
	}

	@Override
	protected void commitChildren() {
		for (Morphic datum : data) {
			if (datum != null)
				datum.commit();
		}
	}

	@Override
	public Iterator<T> iterator() {
		return new MorphicVectorIterator<T>(data, size);
	}

	@Override
	public String toString() {
		StringBuffer buffer = new StringBuffer();

		buffer.append("[");
		for (int i = 0; i < size; i++) {
			if (i > 0)
				buffer.append(", ");
			buffer.append(data[i]);
		}
		buffer.append("]");
		return buffer.toString();
	}

	class MorphicVectorIterator<S extends Morphic> implements Iterator<S> {
		Morphic[] data;
		int size;
		int index = 0;

		MorphicVectorIterator(Morphic[] data, int size) {
			this.data = data;
			this.size = size;
		}

		@Override
		public boolean hasNext() {
			return index < size;
		}

		@SuppressWarnings("unchecked")
		@Override
		public S next() {
			S result = (S) data[index];

			index++;
			return result;
		}

		@Override
		public void remove() {
			throw new UnsupportedOperationException();
		}
	}
}