User:Chase-san/VDA

From Robowiki
Jump to navigation Jump to search

A variable dimension array I wrote up trying to figure out a way I could have a variable number of segment buffers without having to know how many I had in advance. It turned out pretty well!

This and all my other code in which I display on the robowiki falls under the ZLIB License.

package org.csdgn.utils;

import java.io.Serializable;
import java.util.Arrays;

/**
 * Variable Dimension Array, an array class with flexible dimensionality.
 * 
 * Just remember (int ... x) means it accepts (0,0,0) and new int[]{0,0,0}.
 * 
 * @author Chase
 * 
 * @param <T>
 *            Type of data contained
 */
public class VDA<T> implements Serializable, Cloneable {
	private static final long serialVersionUID = 3816532930303382063L;

	private T[] data = null;
	private int[] dims = null;
	private boolean constructed = false;

	/**
	 * Initializes the VDA with 0 dimensions.
	 */
	public VDA() {
		dims = new int[0];
	}

	/**
	 * Initializes the VDA with the given number of dimensions
	 * 
	 * @param dimensions
	 */
	public VDA(int... dimensions) {
		if(dimensions == null)
			throw new NullPointerException();
		dims = (int[])dimensions.clone();
	}

	/**
	 * @param size
	 *            Must be at least 2
	 */
	public void add(int size) {
		if(size < 2)
			throw new IllegalArgumentException("Dimension size must be at least 2.");
		dims = Arrays.copyOf(dims, dims.length + 1);
		dims[dims.length - 1] = size;
		constructed = false;
	}

	/**
	 * @param index
	 *            Must be between 0 and number of dimensions
	 */
	public void remove(int index) {
		if(index < 0 || index >= dims.length)
			throw new IndexOutOfBoundsException();
		int[] tmp = dims;
		dims = Arrays.copyOf(dims, dims.length - 1);
		if(index < dims.length) {
			System.arraycopy(tmp, index + 1, dims, index, dims.length - index);
		}
		constructed = false;
	}

	/**
	 * Get the value at the given dimension
	 */
	public T get(int... pos) {
		if(pos == null)
			throw new NullPointerException();
		if(dims.length == 0 || pos.length != dims.length)
			throw new IllegalArgumentException("Incorrect or Bad Dimensionality.");
		if(!constructed)
			construct();
		return data[getIndex(pos)];
	}

	/**
	 * Set the value at the given dimension
	 */
	public void set(T value, int... pos) {
		if(pos == null)
			throw new NullPointerException();
		if(dims.length == 0 || pos.length != dims.length)
			throw new IllegalArgumentException("Incorrect or Bad Dimensionality.");
		if(!constructed)
			construct();
		data[getIndex(pos)] = value;
	}
	
	/**
	 * Returns the size of this VDA
	 * @return
	 */
	public int[] getSize() {
		return dims.clone();
	}

	/**
	 * Returns the bottom array at the given position
	 */
	public Object[] getSubArray(int... pos) {
		if(pos.length != dims.length - 1)
			throw new UnsupportedOperationException("Dimensionality must be one less than the total supported.");
		if(!constructed)
			construct();
		int start = getIndex(pos);
		int length = dims[dims.length - 1];
		T[] output = createArray(length);
		System.arraycopy(data, start, output, 0, length);
		return output;
	}

	/**
	 * Sets the bottom array at the given position
	 */
	public void setSubArray(T[] array, int... pos) {
		if(pos.length != dims.length - 1)
			throw new UnsupportedOperationException("Dimensionality must be one less than the total supported.");
		if(!constructed)
			construct();
		int start = getIndex(pos);
		int length = Math.min(dims[dims.length - 1], array.length);
		System.arraycopy(array, 0, data, start, length);
	}

	/**
	 * @return the array that backs this VDA
	 */
	public Object[] getBackingArray() {
		if(!constructed)
			construct();
		return data;
	}

	/**
	 * Returns an array containing all of the elements in this VDA
	 */
	public Object[] toArray() {
		if(!constructed)
			construct();
		return data.clone();
	}

	/**
	 * Returns an array containing all of the elements in this VDA
	 */
	@SuppressWarnings("unchecked")
	public T[] toArray(T[] a) {
		if(!constructed)
			construct();
		return (T[])Arrays.copyOf(data, data.length, a.getClass());
	}

	/**
	 * Sets this VDA to be equal to the given VDA. Data and dimensions are
	 * copied.
	 */
	public void set(VDA<T> vda) {
		data = (T[])vda.data.clone();
		dims = (int[])vda.dims.clone();
		constructed = vda.constructed;
	}

	/**
	 * Returns a shallow copy of this VDA (dimensions but not data)
	 */
	public Object clone() {
		return new VDA<T>(dims);
	}

	/**
	 * Creates the final data array
	 */
	private void construct() {
		Integer size = 1;
		for(Integer i : dims)
			size *= i;
		data = createArray(size);
		constructed = true;
	}

	@SuppressWarnings("unchecked")
	private T[] createArray(int size) {
		// Warning: Dangerous
		return (T[])new Object[size];
	}

	/**
	 * Gets the main arrays index from pos
	 */
	public int getIndex(int[] pos) {
		Integer index = 0;
		for(int i = 0; i < pos.length; ++i) {
			if(pos[i] < 0 || pos[i] >= dims[i])
				throw new IndexOutOfBoundsException("Index " + pos[i] + " is out of bounds for dimension " + i + ".");

			index += sizeUnder(i) * pos[i];
		}
		System.out.println("Index " + index);
		return index;
	}

	/**
	 * Gets the number of elements under the given level
	 */
	private int sizeUnder(int level) {
		Integer size = 1;
		for(int i = level + 1; i < dims.length; ++i) {
			size *= dims[i];
		}
		return size;
	}
}