blob: 8515673014558930b0d1984b4b17d91f7d275b42 [file] [log] [blame]
/* -*- Mode: java; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
*
* The contents of this file are subject to the Netscape Public
* License Version 1.1 (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.mozilla.org/NPL/
*
* Software distributed under the License is distributed on an "AS
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express oqr
* implied. See the License for the specific language governing
* rights and limitations under the License.
*
* The Original Code is Rhino code, released
* May 6, 1999.
*
* The Initial Developer of the Original Code is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1997-2000 Netscape Communications Corporation. All
* Rights Reserved.
*
* Contributor(s):
* Igor Bukanov
*
* Alternatively, the contents of this file may be used under the
* terms of the GNU Public License (the "GPL"), in which case the
* provisions of the GPL are applicable instead of those above.
* If you wish to allow use of your version of this file only
* under the terms of the GPL and not to allow others to use your
* version of this file under the NPL, indicate your decision by
* deleting the provisions above and replace them with the notice
* and other provisions required by the GPL. If you do not delete
* the provisions above, a recipient may use your version of this
* file under either the NPL or the GPL.
*/
// Modified by Google
package com.google.gwt.dev.js.rhino;
import java.io.Serializable;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
/**
Implementation of resizable array with focus on minimizing memory usage by storing few initial array elements in object fields. Can also be used as a stack.
*/
public class ObjArray implements Serializable {
public ObjArray() { }
public ObjArray(int capacityHint) {
if (capacityHint < 0) throw new IllegalArgumentException();
if (capacityHint > FIELDS_STORE_SIZE) {
data = new Object[capacityHint - FIELDS_STORE_SIZE];
}
}
public final boolean isEmpty() {
return size == 0;
}
public final int size() {
return size;
}
public final void setSize(int newSize) {
if (newSize < 0) throw new IllegalArgumentException();
int N = size;
if (newSize < N) {
for (int i = newSize; i != N; ++i) {
setImpl(i, null);
}
}else if (newSize > N) {
if (newSize > FIELDS_STORE_SIZE) {
ensureCapacity(newSize);
}
}
size = newSize;
}
public final Object get(int index) {
if (!(0 <= index && index < size)) throw invalidIndex(index, size);
return getImpl(index);
}
public final void set(int index, Object value) {
if (!(0 <= index && index < size)) throw invalidIndex(index, size);
setImpl(index, value);
}
private Object getImpl(int index) {
switch (index) {
case 0: return f0;
case 1: return f1;
case 2: return f2;
case 3: return f3;
case 4: return f4;
case 5: return f5;
}
return data[index - FIELDS_STORE_SIZE];
}
private void setImpl(int index, Object value) {
switch (index) {
case 0: f0 = value; break;
case 1: f1 = value; break;
case 2: f2 = value; break;
case 3: f3 = value; break;
case 4: f4 = value; break;
case 5: f5 = value; break;
default: data[index - FIELDS_STORE_SIZE] = value;
}
}
public int indexOf(Object obj) {
int N = size;
for (int i = 0; i != N; ++i) {
Object current = getImpl(i);
if (current == obj || (current != null && current.equals(obj))) {
return i;
}
}
return -1;
}
public int lastIndexOf(Object obj) {
for (int i = size; i != 0;) {
--i;
Object current = getImpl(i);
if (current == obj || (current != null && current.equals(obj))) {
return i;
}
}
return -1;
}
public final Object peek() {
int N = size;
if (N == 0) throw invalidEmptyStackAccess();
return getImpl(N - 1);
}
public final Object pop() {
int N = size;
--N;
Object top;
switch (N) {
case -1: throw invalidEmptyStackAccess();
case 0: top = f0; f0 = null; break;
case 1: top = f1; f1 = null; break;
case 2: top = f2; f2 = null; break;
case 3: top = f3; f3 = null; break;
case 4: top = f4; f4 = null; break;
case 5: top = f5; f5 = null; break;
default:
top = data[N - FIELDS_STORE_SIZE];
data[N - FIELDS_STORE_SIZE] = null;
}
size = N;
return top;
}
public final void push(Object value) {
add(value);
}
public final void add(Object value) {
int N = size;
if (N >= FIELDS_STORE_SIZE) {
ensureCapacity(N + 1);
}
size = N + 1;
setImpl(N, value);
}
public final void add(int index, Object value) {
Object tmp;
int N = size;
if (!(0 <= index && index <= N)) throw invalidIndex(index, N + 1);
switch (index) {
case 0:
if (N == 0) { f0 = value; break; }
tmp = f0; f0 = value; value = tmp;
case 1:
if (N == 1) { f1 = value; break; }
tmp = f1; f1 = value; value = tmp;
case 2:
if (N == 2) { f2 = value; break; }
tmp = f2; f2 = value; value = tmp;
case 3:
if (N == 3) { f3 = value; break; }
tmp = f3; f3 = value; value = tmp;
case 4:
if (N == 4) { f4 = value; break; }
tmp = f4; f4 = value; value = tmp;
case 5:
if (N == 5) { f5 = value; break; }
tmp = f5; f5 = value; value = tmp;
index = FIELDS_STORE_SIZE;
default:
ensureCapacity(N + 1);
if (index != N) {
System.arraycopy(data, index - FIELDS_STORE_SIZE,
data, index - FIELDS_STORE_SIZE + 1,
N - index);
}
data[index - FIELDS_STORE_SIZE] = value;
}
size = N + 1;
}
public final void remove(int index) {
int N = size;
if (!(0 <= index && index < N)) throw invalidIndex(index, N);
--N;
switch (index) {
case 0:
if (N == 0) { f0 = null; break; }
f0 = f1;
case 1:
if (N == 1) { f1 = null; break; }
f1 = f2;
case 2:
if (N == 2) { f2 = null; break; }
f2 = f3;
case 3:
if (N == 3) { f3 = null; break; }
f3 = f4;
case 4:
if (N == 4) { f4 = null; break; }
f4 = f5;
case 5:
if (N == 5) { f5 = null; break; }
f5 = data[0];
index = FIELDS_STORE_SIZE;
default:
if (index != N) {
System.arraycopy(data, index - FIELDS_STORE_SIZE + 1,
data, index - FIELDS_STORE_SIZE,
N - index);
}
data[N - FIELDS_STORE_SIZE] = null;
}
size = N;
}
public final void clear() {
int N = size;
for (int i = 0; i != N; ++i) {
setImpl(i, null);
}
size = 0;
}
public final Object[] toArray() {
Object[] array = new Object[size];
toArray(array, 0);
return array;
}
public final void toArray(Object[] array) {
toArray(array, 0);
}
public final void toArray(Object[] array, int offset) {
int N = size;
switch (N) {
default:
System.arraycopy(data, 0, array, offset + FIELDS_STORE_SIZE,
N - FIELDS_STORE_SIZE);
case 6: array[offset + 5] = f5;
case 5: array[offset + 4] = f4;
case 4: array[offset + 3] = f3;
case 3: array[offset + 2] = f2;
case 2: array[offset + 1] = f1;
case 1: array[offset + 0] = f0;
case 0: break;
}
}
private void ensureCapacity(int minimalCapacity) {
int required = minimalCapacity - FIELDS_STORE_SIZE;
if (required <= 0) throw new IllegalArgumentException();
if (data == null) {
int alloc = FIELDS_STORE_SIZE * 2;
if (alloc < required) {
alloc = required;
}
data = new Object[alloc];
} else {
int alloc = data.length;
if (alloc < required) {
if (alloc <= FIELDS_STORE_SIZE) {
alloc = FIELDS_STORE_SIZE * 2;
} else {
alloc *= 2;
}
if (alloc < required) {
alloc = required;
}
Object[] tmp = new Object[alloc];
if (size > FIELDS_STORE_SIZE) {
System.arraycopy(data, 0, tmp, 0,
size - FIELDS_STORE_SIZE);
}
data = tmp;
}
}
}
private static RuntimeException invalidIndex(int index, int upperBound) {
// \u2209 is "NOT ELEMENT OF"
String msg = index+" \u2209 [0, "+upperBound+')';
return new IndexOutOfBoundsException(msg);
}
private static RuntimeException invalidEmptyStackAccess() {
throw new RuntimeException("Empty stack");
}
private void writeObject(ObjectOutputStream os) throws IOException {
os.defaultWriteObject();
int N = size;
for (int i = 0; i != N; ++i) {
Object obj = getImpl(i);
os.writeObject(obj);
}
}
private void readObject(ObjectInputStream is)
throws IOException, ClassNotFoundException
{
is.defaultReadObject(); // It reads size
int N = size;
if (N > FIELDS_STORE_SIZE) {
data = new Object[N - FIELDS_STORE_SIZE];
}
for (int i = 0; i != N; ++i) {
Object obj = is.readObject();
setImpl(i, obj);
}
}
static final long serialVersionUID = 7448768847663119705L;
// Number of data elements
private int size;
private static final int FIELDS_STORE_SIZE = 6;
private transient Object f0, f1, f2, f3, f4, f5;
private transient Object[] data;
}