package DPJRuntime;
/**
* <p>The {@code ArraySlice} class wraps and provides a slice of an
* ordinary Java array. <p>A {@code ArraySlice} stores a start
* position (indexed into the underlying array) and a length.
* Accesses to the {@code ArraySlice} are translated into accesses
* into the underlying array, offset by the start position. They are
* bounds-checked against the length of the {@code ArraySlice}.
*
* The {@code ArraySlice} class supports the creation of a
* <i>subslice</i>, which is a another slice of the original array.
* The subslice itself is a new {@code ArraySlice} object.
*
* For example:
*
* <p><blockquote><pre>
* // Create a Java array a of 10 int
* Array<Integer> a = new Array<Integer>(10);
* // Wrap a in an ArraySlice
* ArraySlice<Integer> A = new ArraySlice<Integer>(a)
* // Create a subslice of A
* ArraySlice<Integer> B = A.subslice(5,2);
* // Store value 1 into position 5 of a
* B.put(0,1);
* // Error: Out of bounds
* B.put(3,5);
* </pre></blockquote><p>
*
* @author Rob Bocchino
* @param <T> The type of an element of this {@code ArraySlice}
* @param <R> The region of a cell of this {@code ArraySlice}
*
*/
public class ArraySlice<type T,region R> {
/**
* The underlying array representation
*/
private final Array<T,R> elts in R;
/**
* The start index for indexing into the underlying array
*/
public final int start in R;
/**
* The number of elements in the {@code ArraySlice}
*/
public final int length in R;
/**
* Creates a {@code ArraySlice} of the specified length, wrapping a
* freshly created Java array with the same length.
*
* @param length The length of the {@code ArraySlice}
*/
public ArraySlice(int length) pure {
this.elts = (Array<T,R>) ((Object) new Object[length]);
this.start = 0;
this.length = length;
}
/**
* Creates a {@code ArraySlice} that wraps the given Java array.
*
* @param elts The Java array to wrap
*/
public ArraySlice(Array<T,R> elts) pure {
this.elts = elts;
this.start = 0;
this.length = elts.length;
}
private ArraySlice(Array<T,R> elts, int start, int length) pure {
this.elts = elts;
this.start = start;
this.length = length;
}
/**
* Returns the value stored at index {@code idx} of this {@code
* ArraySlice}.
*
* <p>Throws {@code ArrayIndexOutOfBoundsException} if {@code idx}
* is outside the bounds of this {@code ArraySlice} (even if it is
* in bounds for the underlying array).
*
* @param idx Index of value to return
* @param return Value stored at {@code idx}
*/
public T get(int idx) reads R {
if (idx < 0 || idx > length-1) {
throw new ArrayIndexOutOfBoundsException();
}
return elts[start+idx];
}
/**
* Replaces the value at index {@code idx} of this {@code
* ArraySlice} with value {@code val}.
*
* <p>Throws {@code ArrayIndexOutOfBoundsException} if {@code idx}
* is outside the bounds of this {@code ArraySlice} (even if it is
* in bounds for the underlying array).
*
* @param idx Index of value to replace
* @param val New value
*/
public void put(int idx, T val) writes R {
if (idx < 0 || idx > length-1) {
throw new ArrayIndexOutOfBoundsException();
}
elts[start+idx] = val;
}
/**
* Creates and returns a new {@code ArraySlice} starting at index
* {@code start} with length {@code length} that wraps the same
* underlying array as this {@code ArraySlice}. Index {@code i} of
* the new {@code ArraySlice} refers to the same cell of the
* underlying array as index {@code start+i} of {@code this}.
*
* <p>Throws {@code ArrayIndexOutOfBoundsException} if the
* interval {@code start,start+length-1]} is not in bounds for
* this {@code ArraySlice}.
*
* @param start Start index for the subslice
* @param length Length of the subslice
* @return Subslice of this {@code ArraySlice} defined by {@code
* start} and {@code length}
*/
public ArraySlice<T,R> subslice(int start, int length) pure {
if (start < 0 || length < 0 ||
start + length > this.length) {
throw new ArrayIndexOutOfBoundsException();
}
return new ArraySlice<T,R>(elts, this.start + start, length);
}
/**
* Returns the underlying Java array for this {@code ArraySlice}.
*
* @return The underlying Java array
*/
public Array<T,R> toArray() pure { return elts; }
/**
* Returns a string representation of this {@code ArraySlice}.
*
* @return A string representation
*/
public String toString() reads R {
StringBuffer sb = new StringBuffer();
if (length > 0) {
sb.append(this.get(0));
for (int i = 1; i < length; ++i) {
sb.append(" ");
sb.append(this.get(i));
}
}
return sb.toString();
}
/**
* Swaps the values at indices {@code i} and {@code j} of this
* {@code ArraySlice}.
*
* @param i First index to swap
* @param j Second index to swap
*/
public void swap(int i, int j) writes R {
T tmp = elts[start+i];
elts[start+i] = elts[start+j];
elts[start+j] = tmp;
}
}