CaRMtl/rene/util/MyVector.java

326 lines
7.1 KiB
Java

/*
Copyright 2006 Rene Grothmann, modified by Eric Hakenholz
This file is part of C.a.R. software.
C.a.R. is a free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, version 3 of the License.
C.a.R. is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package rene.util;
import java.util.Enumeration;
/**
* This is a more effective replacement of the Vector class. It is based on a
* growing array. If an object is removed, it is replaced by null. The class
* knows about the first null object (the gap). Searching for elements or other
* operations automatically compress the array by copying the elements upwards,
* but only as far as they need to go anyway.
*
* Accessing an element is very effective, at least the second time. If you want
* to make sure, it is always effective, compress first. The most effective way
* is to get the object array itself.
*
* The objects can be enumerated. The object returned by nextElement() is found
* very rapidly. E.g. it can be deleted at once.
*
* Enumeration is not reentrant. Do it only once each time.
*
* Nothing in this class is synchronized!
**/
public class MyVector implements Enumeration {
Object O[];
int OSize, ON, OLast, Gap;
int EN = 0;
public MyVector(final int initsize) {
O = new Object[initsize];
OSize = initsize;
OLast = ON = 0;
Gap = -1;
}
public MyVector() {
this(8);
}
/**
* Add an element. Extend the array, if necessary.
*/
public void addElement(final Object o) {
if (OLast >= OSize)
extend();
O[OLast++] = o;
ON++;
}
/**
* Extend the array, or get space by compressing it.
*/
public void extend() {
if (ON < OLast / 2) {
compress();
return;
}
final Object o[] = new Object[2 * OSize];
System.arraycopy(O, 0, o, 0, OLast);
OSize *= 2;
O = o;
}
/**
* Compress the array.
*/
public void compress() {
if (Gap < 0)
return;
int k = Gap;
for (int i = Gap; i < OLast; i++) {
if (O[i] == null)
continue;
O[k++] = O[i];
}
ON = k;
for (int i = k; i < OLast; i++)
O[i] = null;
Gap = -1;
OLast = ON;
}
/**
* Get an enumeration of this array.
*/
public Enumeration elements() {
compress();
EN = 0;
return this;
}
/**
* Method for Enumeration.
*/
public boolean hasMoreElements() {
while (EN < OLast && O[EN] == null)
EN++;
return EN < OLast;
}
/**
* Method for Enumeration.
*/
public Object nextElement() {
if (!hasMoreElements())
throw new ArrayIndexOutOfBoundsException(OLast);
return O[EN++];
}
/**
* Clear this array, but keep its memory!
*/
public void removeAllElements() {
for (int i = 0; i < OLast; i++)
O[i] = null;
ON = OLast = 0;
Gap = -1;
}
/**
* Remove a single element. This will also compress the part below the
* element, or all, if it is not found.
*/
public void removeElement(final Object o) {
final int i = indexOf(o);
if (i < 0)
return;
O[i] = null;
ON--;
if (Gap < 0 || Gap > i)
Gap = i;
if (i == OLast - 1)
OLast--;
while (OLast > 0 && O[OLast - 1] == null)
OLast--;
if (Gap >= OLast)
Gap = -1;
}
/**
* Find an element. Compress on the way. Check for the last element,
* returned by nextElement() first. Equality is checked with the equal()
* function.
*
* @return -1, if not found.
*/
public int indexOf(final Object o) {
if (EN > 0 && EN <= OLast && O[EN - 1].equals(o))
return EN - 1;
if (Gap < 0) {
for (int i = 0; i < OLast; i++) {
if (O[i].equals(o))
return i;
}
return -1;
}
for (int i = 0; i < Gap; i++) {
if (O[i].equals(o))
return i;
}
int k = Gap;
for (int i = Gap; i < OLast; i++) {
if (O[i] == null)
continue;
if (O[i].equals(o)) {
Gap = k;
return i;
}
O[k++] = O[i];
O[i] = null;
}
ON = k;
for (int i = k; i < OLast; i++)
O[i] = null;
Gap = -1;
OLast = ON;
return -1;
}
/**
* @return the number of objects in the vector.
*/
public int size() {
return ON;
}
/**
* Get the element at a given position. Second access will always be
* effective. First access compresses. Throws an exception, if the index is
* invalid.
*/
public Object elementAt(final int n) {
if (n < 0 || n >= ON)
throw new ArrayIndexOutOfBoundsException(n);
if (Gap < 0 || n < Gap)
return O[n];
int k = Gap;
for (int i = Gap; i < OLast; i++) {
if (O[i] == null)
continue;
O[k] = O[i];
O[i] = null;
if (k == n) {
final Object ret = O[k];
k++;
Gap = k;
if (Gap >= ON) {
for (int j = Gap; j < OLast; j++)
O[j] = null;
OLast = ON;
Gap = -1;
}
return ret;
}
k++;
}
// never happens
throw new ArrayIndexOutOfBoundsException(n);
}
/**
* Get the array itself (compressed). Make sure, you also use size() to
* determine the true length of the array. Do not change objects beyond the
* size! Do not set objects to null!
*/
public Object[] getArray() {
compress();
return O;
}
/**
* Copy the array into an object array of at least the same size.
*/
public void copyInto(final Object o[]) {
compress();
System.arraycopy(O, 0, o, 0, ON);
}
/**
* Test for equality with another vector, using equals.
*/
public boolean equals(final MyVector V) {
if (V.ON != ON)
return false;
V.compress();
compress();
for (int i = 0; i < ON; i++) {
if (!V.O[i].equals(O[i]))
return false;
}
return true;
}
/**
* Test for equality with another vector, using object equality.
*/
public boolean equalsIdentical(final MyVector V) {
if (V.ON != ON)
return false;
V.compress();
compress();
for (int i = 0; i < ON; i++) {
if (V.O[i] != O[i])
return false;
}
return true;
}
/**
* Trancate the vector to n elements, if it has more.
*/
public void truncate(final int n) {
if (n >= ON)
return;
compress();
for (int i = n; i < OLast; i++)
O[i] = null;
OLast = ON = n;
}
public static void main(final String args[]) {
final MyVector V = new MyVector();
for (int i = 1; i <= 10; i++)
V.addElement("Element " + i);
for (int i = 4; i <= 9; i++)
V.removeElement("Element " + i);
System.out.println("--> " + V.elementAt(3));
System.out.println(V.ON + " elements, " + V.OLast + " used, " + V.Gap
+ " gap.");
System.out.println("--> " + V.elementAt(3));
System.out.println(V.ON + " elements, " + V.OLast + " used, " + V.Gap
+ " gap.");
for (int i = 11; i <= 20; i++)
V.addElement("Element " + i);
System.out.println(V.ON + " elements, " + V.OLast + " used ," + V.Gap
+ " gap.");
final Enumeration E = V.elements();
while (E.hasMoreElements()) {
System.out.println((String) E.nextElement());
}
System.out.println(V.ON + " elements, " + V.OLast + " used, " + V.Gap
+ " gap.");
}
}