/*********************************************************************************
* TotalCross Software Development Kit *
* Copyright (C) 2000-2012 SuperWaba Ltda. *
* All Rights Reserved *
* *
* This library and virtual machine 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. *
* *
* This file is covered by the GNU LESSER GENERAL PUBLIC LICENSE VERSION 3.0 *
* A copy of this license is located in file license.txt at the root of this *
* SDK or can be downloaded here: *
* http://www.gnu.org/licenses/lgpl-3.0.txt *
* *
*********************************************************************************/
package totalcross.util;
import totalcross.sys.*;
/**
* An int vector is an array of int's. The vector grows
* dynamically as ints are added, but it never shrinks.
* The IntVector can also be used as an IntStack or a bit vector.
* <p>
* Here is an example showing a vector being used:
*
* <pre>
* ...
* IntVector vec = new IntVector();
* vec.addElement(int1);
* vec.addElement(int22);
* ...
* vec.insertElementAt(int3, 3);
* vec.removeElementAt(2);
* if (vec.size() > 5)
* ...
* </pre>
* <br>For efficiency, get and set is made directly through the <items> public array.
* <b>Please use the add and remove methods to manipulate the IntVector.</b>
*/
public class IntVector
{
/** This member is public for fast access. Always use the correct methods
* for add and remove, otherwise you'll be in trouble. */
public int items[];
protected int count;
/** Constructs an empty vector. */
public IntVector()
{
this(20);
}
/**
* Constructs an empty vector with a given initial size. The size is
* the initial size of the vector's internal int array. The vector
* will grow as needed when ints are added. SIZE CANNOT BE 0!
*/
public IntVector(int size)
{
if (size < 0) // flsobral@tc100b4_21: throw exception if size has invalid value.
throw new IllegalArgumentException("The argument 'size' must be non-negative");
items = new int[size];
}
/** Constructs a vector by directly assigning the given int array. Changes on the
* original array will reflect the items of this array and vice-versa.
* @since SuperWaba 5.11
*/
public IntVector(int []items) // guich@511_11
{
count = items.length; // flsobral@tc100b4: fail-fast policy - throws NPE if items is null.
this.items = items;
}
/** Useful method to use when this IntVector will act like a bit vector, through
* the methods <code>isBitSet</code> and <code>setBit</code>. Just call it
* with the maximum bit index what will be used (starting from 0); then
* you can safely use the two methods. This must be done because those methods
* does not check the bounds of the array.
*/
public void ensureBit(int index) // guich@400_5
{
int newCount = (index >> 5)+1; // convert from bits to int
if (newCount >= items.length)
{
if (count == 0) // no items yet? just assign a new vector
items = new int[newCount];
else
{
int newItems[] = new int[newCount];
Vm.arrayCopy(items, 0, newItems, 0, count);
items = newItems;
}
}
count = newCount;
}
/** Used to let this int vector act like a bit vector.
* @return true if the bit specified is set. you must guarantee that the index exists in the vector.
*/
public boolean isBitSet(int index) // guich@400_5
{
return (items[index>>5] & ((int)1 << (index & 31))) != 0; // guich@321_7
}
/** Used to let this int vector act like a bit vector.
* you must guarantee that the index exists in the vector.
*/
public void setBit(int index, boolean on) // guich@400_5
{
if (on)
items[index>>5] |= ((int)1 << (index & 31)); // set
else
items[index>>5] &= ~((int)1 << (index & 31)); // reset
}
// methods to let the vector act like a stack
/** Pushes an int. */
public void push(int obj)
{
if (count < items.length)
items[count++] = obj;
else
insertElementAt(obj, count);
}
/** Pops the given number of elements from this vector.
* @since SuperWaba 5.0
*/
public void pop(int howMany) // guich@500_4
{
this.count -= howMany;
if (this.count < 0)
this.count = 0;
}
/** Returns the last int, removing it.
* @throws totalcross.util.ElementNotFoundException When the stack is empty.
*/
public int pop() throws ElementNotFoundException
{
if (count > 0)
return items[--count];
throw new ElementNotFoundException("Empty stack");
}
/** Returns the last int, without removing it.
* @throws totalcross.util.ElementNotFoundException When the stack is empty.
*/
public int peek() throws ElementNotFoundException
{
if (count > 0)
return items[count-1];
throw new ElementNotFoundException("Empty stack");
}
/** Returns if this IntVector is empty.
* @since TotalCross 1.0.
*/
public boolean isEmpty()
{
return count == 0;
}
/** Returns the number of ints in the vector. */
public int size()
{
return count;
}
/**
* Finds the index of the given int. The list is searched using a O(n) linear
* search through all the ints in the vector.
* @return -1 if the object is not found.
*/
public int indexOf(int elem)
{
return indexOf(elem, 0);
}
/**
* Finds the index of the given int. The list is searched using a O(n) linear
* search starting in startIndex up through all the ints in the vector.
* @return -1 if the object is not found.
*/
public int indexOf(int elem, int index)
{
int n = count;
for (int i = index; i < n; i++)
if (items[i] == elem)
return i;
return -1;
}
/** Deletes the int reference at the given index. */
public void removeElementAt(int index)
{
if (0 <= index && index < count) // guich@566_33
{
if (index != count - 1)
Vm.arrayCopy(items, index + 1, items, index, count - index - 1);
items[count - 1] = 0;
count--;
}
}
/** Inserts the object at the given index. If index is less than 0 or above the number of elements, it is inserted at the end. */
public void insertElementAt(int obj, int index)
{
if (index < 0 || index > count) index = count; // guich@200b3: check if index is valid
if (count == items.length)
{
// On device, grows 20% + 1. On Java, grows 100% + 1.
int newSize = (Settings.onJavaSE ? items.length*2 : items.length*12/10) + 1; // flsobral@tc110_5: new size is >= current size + 1. - guich@tc112_6: +1 in both cases
int newItems[] = new int[newSize];
Vm.arrayCopy(items, 0, newItems, 0, count);
items = newItems;
}
if (index != count)
Vm.arrayCopy(items, index, items, index + 1, count - index);
items[index] = obj;
count++;
}
/** Adds an int to the end of the vector. */
public void addElement(int obj)
{
if (count < items.length)
items[count++] = obj;
else
insertElementAt(obj, count);
}
/**
* Appends an array of integers at the end of this vector.
*
* @param elements
* array of integers to be added to this vector.
* @since TotalCross 1.2
*/
public void addElements(int[] elements) // flsobral@tc120_34: new method to add array of integers.
{
int newSize = count + elements.length;
if (items.length < newSize)
{
int newItems[] = new int[newSize];
Vm.arrayCopy(items, 0, newItems, 0, count);
items = newItems;
}
Vm.arrayCopy(elements, 0, items, count, elements.length);
count += elements.length;
}
/** Deletes the given integer from this vector. */
public void removeElement(int obj)
{
removeElementAt(indexOf(obj, 0));
}
/** Sets all elements in this vector to 0 and its size to 0. */
public void removeAllElements()
{
Convert.fill(items, 0, count, 0);
count = 0;
}
/** Does a quick sort in the elements of this IntVector */
public void qsort()
{
qsort(0, count-1);
}
private void qsort(int first, int last)
{
int[] items = this.items;
int low = first;
int high = last;
if (first >= last)
return;
int mid = items[(first+last) >> 1];
while (true)
{
while (high >= low && items[low] < mid) // guich@566_25: added "high > low" here and below - guich@568_5: changed to >=
low++;
while (high >= low && items[high] > mid)
high--;
if (low <= high)
{
int temp = items[low];
items[low++] = items[high];
items[high--] = temp;
}
else break;
}
if (first < high)
qsort(first,high);
if (low < last)
qsort(low,last);
}
/** Returns a new array with the added elements
* @since SuperWaba 5.54
*/
public int[] toIntArray() // guich@554_34
{
int[] a = new int[count];
Vm.arrayCopy(items, 0, a, 0, count);
return a;
}
/**
* Sets the size of this vector. If the new size is greater than the current size, new items are added to the end of
* the vector. If the new size is less than the current size, all components at index newSize and greater are
* discarded.
*
* @param newSize
* the new size of this vector
* @throws ArrayIndexOutOfBoundsException
* if the new size is negative
* @since TotalCross 1.0
*/
public void setSize(int newSize) throws ArrayIndexOutOfBoundsException //flsobral@tc112_11: removed boolean argument "copyOldData". The original content is always kept now.
{
if (newSize < 0)
throw new ArrayIndexOutOfBoundsException("Argument 'newSize' must be positive.");
if (newSize > items.length) // grow buffer to reach newSize
{
int newItems[] = new int[((int)(newSize * 1.2) + 1)];
Vm.arrayCopy(items, 0, newItems, 0, count);
items = newItems;
}
count = newSize;
}
/** Copies the items of this vector into the given array, which must have at least the current size of this vector.
* If the out vector is greater than the current size, the remaining positions will remain unchanged.
* @since TotalCross 1.0 beta 4
*/
public void copyInto(int[] out)
{
Vm.arrayCopy(items, 0, out, 0, count);
}
/**
* Returns true if this vector contains the specified element.
*
* @param v
* element whose presence in this vector is to be tested
* @return true if this vector contains the specified element
* @since TotalCross 1.15
*/
public boolean contains(int v)
{
return indexOf(v) >= 0;
}
/**
* Reverses the order of the elements in this vector.<br>
* In a vector with n elements, the element of index 0 is moved to the index n-1, the element of index 1 is moved to
* the index n-2, and so on.
*
* @since TotalCross 1.15
*/
public void reverse() // guich@tc115_70
{
for (int i = 0, j = count - 1; i < j; i++, j--)
{
int temp = items[i];
items[i] = items[j];
items[j] = temp;
}
}
}