/*
* Copyright 2009 Google Inc.
*
* 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.
*/
package org.cruxframework.crux.core.client.collection;
import java.util.Comparator;
import com.google.gwt.core.client.JavaScriptObject;
/**
* The root Array type that provides read-access to an array that might still be
* mutable by another actor.
*
* @param <E>
* The type stored in the array elements
*/
public class Array<E> extends JavaScriptObject
{
protected Array()
{
}
public final void add(E elem)
{
jsniAdd(elem);
}
public final void clear()
{
jsniClear();
}
public final E get(int index)
{
assert 0 < size() : "Attempt to access an element in an empty array";
assert (index >= 0 && index < size()) : "Index " + index + " was not in the acceptable range [" + 0 + ", " + size() + ")";
return jsniGet(index);
}
/**
* @param elem
* @return
*/
public final int indexOf(E elem)
{
if (elem == null)
{
return -1;
}
return jsniIndexOf(elem);
}
/**
* Inserts {@code elem} before the element residing at {@code index}.
*
* @param index
* in the range [0, this.size()], inclusive; if index is equal to
* the array's current size, the result is equivalent to calling
* {@link #add(Object)}
* @param elem
* the element to insert or {@code null}
*/
public final void insert(int index, E elem)
{
assert (index >= 0 && index < size() + 1) : "Index " + index + " was not in the acceptable range [" + 0 + ", " + (size() + 1) + ")";
jsniInsert(index, elem);
}
/**
* Removes the element.
*/
public final void remove(E elem)
{
int index = indexOf(elem);
if (index >= 0)
{
remove(index);
}
}
/**
* Removes the element at the specified index.
* @param index position to be removed
*/
public final void remove(int index)
{
assert 0 < size() : "Attempt to access an element in an empty array";
assert (index >= 0 && index < size()) : "Index " + index + " was not in the acceptable range [" + 0 + ", " + size() + ")";
jsniRemove(index);
}
/**
* Removes count elements starting at the specified index.
* @param index the first element to be removed
* @param count number of elements to be removed
*/
public final void remove(int index, int count)
{
assert 0 < size() : "Attempt to access an element in an empty array";
assert (index >= 0 && index < size()) : "Index " + index + " was not in the acceptable range [" + 0 + ", " + size() + ")";
jsniRemove(index, count);
}
/**
* Replaces the element at the specified index.
*
* @param index
* in the range [0, this.size()), exclusive
* @param elem
* the element to insert or {@code null}
*/
public final void set(int index, E elem)
{
assert 0 < size() : "Attempt to access an element in an empty array";
assert (index >= 0 && index < size()) : "Index " + index + " was not in the acceptable range [" + 0 + ", " + size() + ")";
jsniSet(index, elem);
}
/**
* Changes the array size. If {@code newSize} is less than the current size,
* the array is truncated. If {@code newSize} is greater than the current
* size the array is grown and the new elements of the array filled up with
* {@code fillValue}.
*/
public final void setSize(int newSize, E fillValue)
{
jsniSetSize(newSize, fillValue);
}
/**
* Retrieve the array size
* @return array size
*/
public final native int size() /*-{
return this ? this.length : 0;
}-*/;
/**
* Clone the current array
*/
public final native Array<E> clone()/*-{
return this.slice(0);
}-*/;
public final native void sort(Comparator<E> comparator)/*-{
this.sort(function(a,b){return comparator.@java.util.Comparator::compare(Ljava/lang/Object;Ljava/lang/Object;)(a,b)});
}-*/;
private native void jsniAdd(E elem) /*-{
this.push(elem);
}-*/;
private native void jsniClear() /*-{
this.length = 0;
}-*/;
private native E jsniGet(int index) /*-{
return this[index];
}-*/;
private native int jsniIndexOf(E elem)/*-{
for (var i = 0, len = this.length; i < len; i++) {
if (this[i] == elem){
return i;
}
}
return -1;
}-*/;
/**
* Inserts {@code element} before the element residing at {@code index}.
*
* @param index
* in the range [0, this.size()], inclusive; if index is equal to
* the array's current size, the result is equivalent to calling
* {@link #add(Object)}
* @param elem
* the element to insert or {@code null}
*/
private native void jsniInsert(int index, E elem) /*-{
this.splice(index, 0, elem);
}-*/;
/**
* Removes the element at the specified index.
*/
private native void jsniRemove(int index) /*-{
this.splice(index, 1);
}-*/;
/**
* Removes the element at the specified index.
*/
private native void jsniRemove(int index, int count) /*-{
this.splice(index, count);
}-*/;
/**
* Replaces the element at the specified index.
*
* @param index
* in the range [0, this.size()), exclusive
* @param elem
* the element to insert or {@code null}
*/
private native void jsniSet(int index, E elem) /*-{
this[index] = elem;
}-*/;
/**
* Changes the array size. If {@code newSize} is less than the current size,
* the array is truncated. If {@code newSize} is greater than the current
* size the array is grown and the new elements of the array filled up with
* {@code fillValue}.
*/
private native void jsniSetSize(int newSize, E fillValue) /*-{
if (fillValue == null) {
this.length = newSize;
} else {
for (var i = this.length; i < newSize; ++i) {
this[i] = fillValue;
}
}
}-*/;
}