ArrayProxy.java
/*
* Java Genetic Algorithm Library (@__identifier__@).
* Copyright (c) @__year__@ Franz Wilhelmstötter
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Author:
* Franz Wilhelmstötter (franz.wilhelmstoetter@gmx.at)
*/
package org.jenetics.internal.util;
import static java.lang.String.format;
import org.jenetics.util.Copyable;
/**
* Abstraction for an ordered and bounded sequence of elements.
*
* @author <a href="mailto:franz.wilhelmstoetter@gmx.at">Franz Wilhelmstötter</a>
* @since 1.4
* @version 1.5 — <em>$Date: 2014-02-15 $</em>
*/
public abstract class ArrayProxy<T> implements Copyable<ArrayProxy<T>> {
protected final int _start;
protected final int _end;
protected final int _length;
protected ArrayProxy(final int from, final int until) {
if (from < 0 || until < 0 || until < from) {
throw new IllegalArgumentException(format(
"Invalid indexes [%d, %d)", from, until
));
}
_start = from;
_end = until;
_length = _end - _start;
}
/**
* Return the <i>array</i> element at the specified, absolute position in
* the {@code ArrayProxy}. The array boundaries are not checked.
*
* @param absoluteIndex absolute index of the element to return
* @return the <i>array</i> element at the specified absolute position
*/
public abstract T __get(final int absoluteIndex);
/**
* Set the <i>array</i> element at the specified absolute position in the
* {@code ArrayProxy}. The array boundaries are not checked.
*
* @param absoluteIndex absolute index of the <i>array</i> element
*/
public abstract void __set(final int absoluteIndex, final T value);
/**
* Return the <i>array</i> element at the specified position in the
* {@code ArrayProxy}. The array boundaries are not checked.
*
* @param index index of the element to return
* @return the <i>array</i> element at the specified position
*/
public T uncheckedGet(final int index) {
return __get(index + _start);
}
/**
* Set the <i>array</i> element at the specified position in the
* {@code ArrayProxy}. The array boundaries are not checked.
*
* @param index index of the <i>array</i> element
*/
public void uncheckedSet(final int index, final T value) {
__set(index + _start, value);
}
/**
* Return the <i>array</i> element at the specified position in the
* {@code ArrayProxy}.
*
* @param index index of the element to return
* @return the <i>array</i> element at the specified position
* @throws IndexOutOfBoundsException if the index it out of range
* (index < 0 || index >= _length).
*/
public T get(final int index) {
checkIndex(index);
return __get(index + _start);
}
/**
* Set the <i>array</i> element at the specified position in the
* {@code ArrayProxy}
*
* @param index the index of the element to set
* @param value the <i>array</i> element
* @throws IndexOutOfBoundsException if the index it out of range
* (index < 0 || index >= _length).
*/
public void set(final int index, final T value) {
checkIndex(index);
__set(index + _start, value);
}
/**
* Return a new sub {@code ArrayProxy} object with the given start and end
* indexes. The underlying array storage is not copied. With the returned
* sub-array proxy it is possible to <i>write through</i> the original
* array.
*
* @param from the start index of the new sub {@code ArrayProxy} object,
* inclusively.
* @param until the end index of the new sub {@code ArrayProxy} object,
* exclusively.
* @return a new array proxy (view) with the given start and end index.
* @throws IndexOutOfBoundsException if the given indexes are out of bounds.
*/
public abstract ArrayProxy<T> slice(final int from, final int until);
/**
* Return a new sub {@code ArrayProxy} object with the given start index.
* The underlying array storage is not copied. With the returned sub-array
* proxy it is possible to <i>write through</i> the original array.
*
* @param from the start index of the new sub {@code ArrayProxy} object,
* inclusively.
* @return a new array proxy (view) with the given start index.
* @throws IndexOutOfBoundsException if the given indexes are out of bounds.
*/
public ArrayProxy<T> slice(final int from) {
return slice(from, _length);
}
/**
* Swap a given range with a range of the same size with another array.
* Implementations of this class should replace this with a optimized
* version, depending on the underlying data structure.
*
* <pre>
* from until
* | |
* this: +---+---+---+---+---+---+---+---+---+---+---+---+
* +---------------+
* +---------------+
* other: +---+---+---+---+---+---+---+---+---+---+---+---+
* |
* otherFrom
* </pre>
*
* @param from the start index of {@code this} range, inclusively.
* @param until the end index of {@code this} range, exclusively.
* @param other the other array to swap the elements with.
* @param otherFrom the start index of the {@code other} array.
* @throws IndexOutOfBoundsException if {@code start > end} or
* if {@code from < 0 || until >= this.length() || otherFrom < 0 ||
* otherFrom + (until - from) >= other.length()}
*/
public void swap(
final int from,
final int until,
final ArrayProxy<T> other,
final int otherFrom
) {
checkIndex(from, until);
other.checkIndex(otherFrom, otherFrom + (until - from));
cloneIfSealed();
other.cloneIfSealed();
for (int i = (until - from); --i >= 0;) {
final T temp = uncheckedGet(i + from);
uncheckedSet(i + from, other.uncheckedGet(otherFrom + i));
other.uncheckedSet(otherFrom + i, temp);
}
}
/**
* Clone the underlying data structure of this {@code ArrayProxy} if it is
* sealed.
* <p/>
* The <i>default</i> implementation will look like this:
* [code]
* public void cloneIfSealed() {
* if (_sealed) {
* _array = _array.clone();
* _sealed = false;
* }
* }
* [/code]
*/
public abstract void cloneIfSealed();
/**
* Set the seal flag for this {@code ArrayProxy} instance and return a new
* {@code ArrayProxy} object with an not set <i>seal</i> flag but with the
* same underlying data structure.
* <p/>
* The <i>default</i> implementation will look like this:
* [code]
* public MyArrayProxy<T> seal() {
* _sealed = true;
* return new MyArrayProxy(_array, _start, _end);
* }
* [code]
*
* @return a new {@code ArrayProxy} instance; for command chaining.
*/
public abstract ArrayProxy<T> seal();
/**
* Checks the given index.
*
* @param from the index to check.
* @throws java.lang.ArrayIndexOutOfBoundsException if the given index is
* not in the valid range.
*/
protected final void checkIndex(final int from) {
if (from < 0 || from >= _length) {
throw new ArrayIndexOutOfBoundsException(format(
"Index %s is out of bounds [0, %s)", from, _length
));
}
}
/**
* Check the given {@code from} and {@code until} indices.
*
* @param from the start index, inclusively.
* @param until the end index, exclusively.
* @throws java.lang.ArrayIndexOutOfBoundsException if the given index is
* not in the valid range.
*/
protected final void checkIndex(final int from, final int until) {
if (from > until) {
throw new ArrayIndexOutOfBoundsException(format(
"fromIndex(%d) > toIndex(%d)", from, until
));
}
if (from < 0 || until > _length) {
throw new ArrayIndexOutOfBoundsException(format(
"Invalid index range: [%d, %s)", from, until
));
}
}
}