blob: 50f1a22e6a468a7aaffea2f0771bc2f3f5bc46e1 [file] [log] [blame]
/*
*******************************************************************************
* Copyright (C) 2002-2003, International Business Machines Corporation and *
* others. All Rights Reserved. *
*******************************************************************************
*
* $Source: /xsrl/Nsvn/icu/icu4j/src/com/ibm/icu/dev/tool/localeconverter/SortedVector.java,v $
* $Date: 2003/12/20 03:07:02 $
* $Revision: 1.3 $
*
*****************************************************************************************
*/
package com.ibm.icu.dev.tool.localeconverter;
import java.util.Vector;
import java.util.Enumeration;
/**
Implements a sorted vector. You can add anything to it; when you access any element, it sorts
the array internally when necessary.
<p>A Comparator is used to compare the elements, allowing arbitrary orderings.
If no Comparator is supplied, then one is constructed based on the type
of the first element added. Only Numbers and Comparables are handled.
<p>Duplicates are allowed.
*/
final public class SortedVector {
/**
Copies elements of vector, enumeration or array
Note: the objects in the source are NOT cloned.
Do not change them or the sorting will be invalid.
*/
public SortedVector(Object[] newValues, Comparator comparator) {
this.comparator = comparator;
addElements(newValues);
//{{INIT_CONTROLS
//}}
}
public SortedVector(Vector newValues, Comparator comparator) {
this.comparator = comparator;
addElements(newValues);
}
public SortedVector(Enumeration newValues, Comparator comparator) {
this.comparator = comparator;
addElements(newValues);
}
public SortedVector(Object[] newValues) {
addElements(newValues);
}
public SortedVector(Comparator comparator) {
this.comparator = comparator;
}
public SortedVector(Vector newValues) {
addElements(newValues);
}
public SortedVector(Enumeration newValues) {
addElements(newValues);
}
public SortedVector() {
}
/**
Adds one element.
*/
public void addElement(Object element) {
if (count >= dataArray.length) setCapacity(count*2 + 17);
dataArray[count++] = element;
isValid = false;
}
/**
Adds multiple elements. Faster than adding one at a time.
*/
public void addElements(Object[] newValues) {
int newCount = count + newValues.length;
if (newCount > dataArray.length) setCapacity(newCount);
for (int i = count; i < newCount; ++i)
dataArray[i] = newValues[i-count];
count = newCount;
isValid = false;
}
public void addElements(Vector newValues) {
int newCount = count + newValues.size();
if (newCount > dataArray.length) setCapacity(newCount);
for (int i = count; i < newCount; ++i)
dataArray[i] = newValues.elementAt(i-count);
count = newCount;
isValid = false;
}
public void addElements(Enumeration newValues) {
while (newValues.hasMoreElements()) {
addElement(newValues.nextElement());
}
}
/**
Removes elements at indices >= startIndex and < endIndex
*/
public void removeElements(int startIndex, int endIndex) {
if (!isValid) validate();
System.arraycopy(dataArray,endIndex,dataArray,startIndex,count - endIndex);
for (int i = count - (endIndex - startIndex); i < count;++i)
dataArray[i] = null; // free up storage
count -= (endIndex - startIndex);
}
/**
Sets comparator
*/
public void setComparator(Comparator comparator) {
this.comparator = comparator;
isValid = false;
}
public Comparator getComparator() {
if (comparator == null) validateComparator();
return this.comparator;
}
/**
Gets size, the actual number of elements.
*/
public int size() {
return count;
}
/**
Gets capacity, the number of elements you can have without growing the array.
*/
public int capacity() {
return dataArray.length;
}
/**
Sets capacity, the number of elements you can have without growing the array.
*/
public void setCapacity(int newSize) {
Object[] temp = new Object[newSize];
System.arraycopy(dataArray, 0, temp, 0, Math.min(count,newSize));
dataArray = temp;
}
/**
Trims the array.
*/
public void trimToSize() {
setCapacity(count);
}
/**
Gets the element at the index
*/
public Object elementAt (int index) {
if (!isValid) validate();
if (index >= count) return dataArray[dataArray.length];
return dataArray[index];
}
/**
Sees whether the vector contains the object
*/
public boolean contains (Object value) {
int index = indexOf(value);
return (index >= 0 && comparator.compare(value,dataArray[index]) == 0);
}
/**
Gets an enumeration
*/
public Enumeration elements() {
if (!isValid) validate();
return new ArrayEnumeration(dataArray,0,count);
}
public void copyInto(Object[] toFill) {
if (!isValid) validate();
System.arraycopy(dataArray,0,toFill,0,toFill.length);
}
/**
Finds first index whose value is greater than or equal to searchValue
If there are none, returns -1
*/
public int indexOf(Object searchValue)
{
if (!isValid) validate();
int index = startIndex;
if (0 <= comparator.compare(searchValue, dataArray[auxStart])) {
index += auxStart;
}
// very fast, completely unrolled binary search
// each case deliberately falls through to the next
switch (power) {
case 31: if (0 > comparator.compare(searchValue, dataArray[index-0x40000000])) index -= 0x40000000;
case 30: if (0 > comparator.compare(searchValue, dataArray[index-0x20000000])) index -= 0x20000000;
case 29: if (0 > comparator.compare(searchValue, dataArray[index-0x10000000])) index -= 0x10000000;
case 28: if (0 > comparator.compare(searchValue, dataArray[index-0x8000000])) index -= 0x8000000;
case 27: if (0 > comparator.compare(searchValue, dataArray[index-0x4000000])) index -= 0x4000000;
case 26: if (0 > comparator.compare(searchValue, dataArray[index-0x2000000])) index -= 0x2000000;
case 25: if (0 > comparator.compare(searchValue, dataArray[index-0x1000000])) index -= 0x1000000;
case 24: if (0 > comparator.compare(searchValue, dataArray[index-0x800000])) index -= 0x800000;
case 23: if (0 > comparator.compare(searchValue, dataArray[index-0x400000])) index -= 0x400000;
case 22: if (0 > comparator.compare(searchValue, dataArray[index-0x200000])) index -= 0x200000;
case 21: if (0 > comparator.compare(searchValue, dataArray[index-0x100000])) index -= 0x100000;
case 20: if (0 > comparator.compare(searchValue, dataArray[index-0x80000])) index -= 0x80000;
case 19: if (0 > comparator.compare(searchValue, dataArray[index-0x40000])) index -= 0x40000;
case 18: if (0 > comparator.compare(searchValue, dataArray[index-0x20000])) index -= 0x20000;
case 17: if (0 > comparator.compare(searchValue, dataArray[index-0x10000])) index -= 0x10000;
case 16: if (0 > comparator.compare(searchValue, dataArray[index-0x8000])) index -= 0x8000;
case 15: if (0 > comparator.compare(searchValue, dataArray[index-0x4000])) index -= 0x4000;
case 14: if (0 > comparator.compare(searchValue, dataArray[index-0x2000])) index -= 0x2000;
case 13: if (0 > comparator.compare(searchValue, dataArray[index-0x1000])) index -= 0x1000;
case 12: if (0 > comparator.compare(searchValue, dataArray[index-0x800])) index -= 0x800;
case 11: if (0 > comparator.compare(searchValue, dataArray[index-0x400])) index -= 0x400;
case 10: if (0 > comparator.compare(searchValue, dataArray[index-0x200])) index -= 0x200;
case 9: if (0 > comparator.compare(searchValue, dataArray[index-0x100])) index -= 0x100;
case 8: if (0 > comparator.compare(searchValue, dataArray[index-0x80])) index -= 0x80;
case 7: if (0 > comparator.compare(searchValue, dataArray[index-0x40])) index -= 0x40;
case 6: if (0 > comparator.compare(searchValue, dataArray[index-0x20])) index -= 0x20;
case 5: if (0 > comparator.compare(searchValue, dataArray[index-0x10])) index -= 0x10;
case 4: if (0 > comparator.compare(searchValue, dataArray[index-0x8])) index -= 8;
case 3: if (0 > comparator.compare(searchValue, dataArray[index-0x4])) index -= 4;
case 2: if (0 > comparator.compare(searchValue, dataArray[index-0x2])) index -= 2;
case 1: if (0 > comparator.compare(searchValue, dataArray[index-0x1])) index -= 1;
case 0: if (0 > comparator.compare(searchValue, dataArray[index])) index -= 1;
}
return index;
}
// ================= privates ==================
/** Only call if comparator is null
*/
private void validateComparator() {
try {
Object trial = dataArray[0];
if (trial instanceof Float || trial instanceof Double) {
comparator = new DoubleComparator();
} else if (trial instanceof Integer) {
comparator = new IntegerComparator();
} else if (trial instanceof Number) {
comparator = new LongComparator();
} else if (trial instanceof String) {
comparator = new StringComparator();
} else {
comparator = new ComparableComparator();
}
} catch (Exception e) {} // leave null
}
private void validate() {
if (isValid) return;
// if the Comparator is null, then pick a reasonable one
if (comparator == null) validateComparator();
// determine search parameters
// find least power of 2 greater than count
for (power = exp2.length-1; power > 0 && count < exp2[power]; power--) {}
// determine the starting point
if (exp2[power] != count) {
auxStart = count - exp2[power];
} else {
auxStart = 0;
}
startIndex = exp2[power]-1;
// shell sort. Later, make this a QuickSort
int lo = 0;
int up = count-1;
for (int step = up - lo + 1; step > 1;) {
if (step < 5)
step = 1;
else step = (5 * step - 1) / 11;
for (int i = up - step; i >= lo; --i) {
Object temp = dataArray[i];
int j;
for (j = i + step; j <= up && 0 > comparator.compare(dataArray[j],temp); j += step)
dataArray[j-step] = dataArray[j];
dataArray[j-step] = temp;
}
}
isValid = true;
}
private Object[] dataArray = new Object[16];
private Comparator comparator;
private int count = 0;
private boolean isValid = false;
private int auxStart;
private int startIndex;
private int power;
private static final int exp2[] = {
0x1, 0x2, 0x4, 0x8,
0x10, 0x20, 0x40, 0x80,
0x100, 0x200, 0x400, 0x800,
0x1000, 0x2000, 0x4000, 0x8000,
0x10000, 0x20000, 0x40000, 0x80000,
0x100000, 0x200000, 0x400000, 0x800000,
0x1000000, 0x2000000, 0x4000000, 0x8000000,
0x10000000, 0x20000000, 0x40000000};
// Utility Classes
public static final class LongComparator implements Comparator {
public int compare(Object a, Object b) {
long aa = ((Number)a).longValue();
long bb = ((Number)b).longValue();
return (aa < bb ? -1 : aa > bb ? 1 : 0);
}
}
public static final class IntegerComparator implements Comparator {
public int compare(Object a, Object b) {
return (((Number)a).intValue() - ((Number)b).intValue());
}
}
public static final class DoubleComparator implements Comparator {
public int compare(Object a, Object b) {
double aa = ((Number)a).doubleValue();
double bb = ((Number)b).doubleValue();
return (aa < bb ? -1 : aa > bb ? 1 : 0);
}
}
public static final class ComparableComparator implements Comparator {
public int compare(Object a, Object b) {
return ((Comparable)a).compareTo(b);
}
}
public static final class StringComparator implements Comparator {
public int compare(Object a, Object b) {
return ((String)a).compareTo((String)b);
};
}
//{{DECLARE_CONTROLS
//}}
}