/*********************************************************************************
* TotalCross Software Development Kit *
* Copyright (C) 1998, 1999 Wabasoft <www.wabasoft.com> *
* 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.*;
/**
* A vector is an array of object references. The vector grows
* dynamically as objects are added, but it never shrinks.
* The Vector class can also be used as a Stack class.
* <p>
* Here is an example showing a vector being used:
*
* <pre>
* ...
* Vector vec = new Vector();
* vec.addElement(obj1);
* vec.addElement(obj2);
* ...
* vec.insertElementAt(obj3, 3);
* vec.removeElementAt(2);
* if (vec.size() > 5)
* ...
* </pre>
* This Vector class does not support Generics; use the ArrayList class instead.
*/
public class Vector
{
/** This member is public for fast access. Always use the correct methods
* for add and remove, otherwise you'll be in trouble. */
public Object items[];
protected int count;
/** Constructs an empty vector. */
public Vector()
{
this(8);
}
/**
* Constructs an empty vector with a given initial size, which is
* the initial size of the vector's internal object array. The vector
* will grow as needed when objects are added.
*/
public Vector(int size)
{
if (size < 0) // flsobral@tc100b4_21: throw exception if size has invalid value. - guich@tc100_19: allow size=0
throw new IllegalArgumentException("The argument 'size' must be non-negative");
items = new Object[size];
}
/**
* Constructs a vector starting with the given elements. The vector can grow after this. Note that the given array
* must not have null elements.
*
* @param startingWith
*/
public Vector(Object[] startingWith) // guich@200b4_31
{
count = startingWith.length; // flsobral@tc100b4_21: fail-fast policy - throws NPE if startingWith is null.
items = startingWith;
}
/** Converts the vector to an array of objects.
* If there are no elements in this vector, returns null.
* Note that if the elements are Strings, you can cast the result to a String[] array.
*/
public Object []toObjectArray()
{
if (count == 0) return null; // guich@200b2
Object objs[];
if (items[0] instanceof String) // guich@220_32
objs = new String[count];
else
objs = new Object[count];
if (count > 0) // guich
Vm.arrayCopy(items, 0, objs, 0, count);
return objs;
}
/** Pushes an object. */ // guich@102
public void push(Object obj)
{
if (count < items.length)
items[count++] = obj;
else
insertElementAt(obj, count);
}
/** Returns the last object, removing it.
* @throws totalcross.util.ElementNotFoundException When the stack is empty.
*/ // guich@102
public Object pop() throws ElementNotFoundException
{
if (count > 0)
{
Object o = items[--count];
items[count] = null; // let gc do their work
return o;
}
throw new ElementNotFoundException("Empty stack");
}
/** Returns the last object, without removing it.
* @throws totalcross.util.ElementNotFoundException When the stack is empty.
*/ // guich@102
public Object peek() throws ElementNotFoundException
{
if (count > 0)
return items[count-1];
throw new ElementNotFoundException("Empty stack");
}
/** Returns the n-last object, without removing it.
* Note that <code>peek(0)</code> is the same of <code>peek()</code>.
* @param n How many elements to get from the top; must be a positive number.
* @throws totalcross.util.ElementNotFoundException When the stack is empty.
*/ // guich@102
public Object peek(int n) throws ElementNotFoundException
{
if (n < 0)
throw new IllegalArgumentException("Argument 'n' must be positive.");
if (count > 0)
return items[count-1-n];
throw new ElementNotFoundException("Empty stack");
}
/** Pops n last elements from the stack.
*/
public void pop(int n)
{
if (count >= n)
count -= n;
else
throw new IllegalArgumentException();
}
/** Returns if this Vector is empty.
* @since TotalCross 1.0.
*/
public boolean isEmpty()
{
return count == 0;
}
/** Returns the number of objects in the vector. */
public int size()
{
return count;
}
/**
* Sets the size of this vector. If the new size is greater than the current size, new null 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 beta 5
*/
public void setSize(int newSize) throws ArrayIndexOutOfBoundsException // flsobral@tc112: Throw AIOOBE instead of IllegalArgument to match the Java implementation.
{
if (newSize < 0)
throw new ArrayIndexOutOfBoundsException("Argument 'newSize' must be positive.");
if (newSize < count) // truncating
Convert.fill(items, newSize, items.length, null);
else // growing
{
// while (newSize > items.length)
grow(newSize); // grow buffer to reach newSize
}
count = newSize;
}
/**
* Finds the index of the given object. The list is searched using a O(n) linear
* search through all the objects in the vector.
*/
public int indexOf(Object elem)
{
return indexOf(elem, 0);
}
/**
* Finds the index of the given object. The list is searched using a O(n) linear
* search starting in startIndex up through all the objects in the vector.
*/
public int indexOf(Object obj, int startIndex)
{
if (obj != null)
{
Object []its = items; // guich@560_13: cache to speedup performance
int n = count;
for (int i = startIndex; i < n; i++)
if (its[i] != null && its[i].equals(obj)) //flsobral@tc114_93: changed Vector.indexOf(Object, int) to perform the comparison using the Vector's elements equals method, instead of the opposite.
return i;
}
return -1;
}
/** Deletes the object reference at the given index. */
public void removeElementAt(int index)
{
if (0 <= index && index < count) // guich@566_33
{
count--;
if (index != count)
Vm.arrayCopy(items, index + 1, items, index, count - index);
items[count] = null;
}
}
/** 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(Object obj, int index)
{
if (index < 0 || index > count) index = count; // guich@200b3: check if index is valid
if (count == items.length)
grow(items.length + 1);
if (index != count)
Vm.arrayCopy(items, index, items, index + 1, count - index);
items[index] = obj;
count++;
}
/** Adds an object to the end of the vector. */
public void addElement(Object obj)
{
if (count < items.length)
items[count++] = obj;
else
insertElementAt(obj, count);
}
/**
* Adds an array of objects at the end of the vector.
*
* @param objects
* array with the objects to be added to the vector.
* @since TotalCross 1.13
*/
public void addElements(Object[] objects) // flsobral@tc113_39: new method to add array of objects.
{
int newSize = count + objects.length;
if (items.length < newSize)
grow(newSize);
Vm.arrayCopy(objects, 0, items, count, objects.length); //flsobral@tc120_33: inserting elements one position higher than it should.
count += objects.length;
}
/**
* Adds an array of objects at the end of the vector
* (null objects are skipped).
*
* @param objects
* array with the objects to be added to the vector.
* @since TotalCross 1.24
*/
public void addElementsNotNull(Object[] objects) // guich@tc124_8
{
int newSize = count + objects.length;
if (items.length < newSize)
grow(newSize);
for (int i = 0; i < objects.length; i++)
if (objects[i] != null)
items[count++] = objects[i];
}
/** Deletes the object. */
public boolean removeElement(Object obj)
{
int i = indexOf(obj,0);
if (i >= 0)
{
removeElementAt(i);
return true;
}
return false;
}
/** Clears all elements in this vector and sets the count to 0. Note that this method sets all items in this vector to <code>null</code>,
* so, if you had directly assigned an array to this vector, all items inside it will be nulled. */
public void removeAllElements()
{
Convert.fill(items, 0, count, null);
count = 0;
}
/** Sorts the elements of this Vector. If they are Strings,
the sort will be much faster because a cast to String is done;
if they are not strings, the toString() method is used to return
the string that will be used for comparison. */
public void qsort() // flsobral@tc100b4_22: changed return type to void.
{
if (count > 0)
Convert.qsort(items, 0, count-1);
}
/** Dumps the contents of this vector and returns a string of it.
* If the number of elements is big, it can take a lot of memory!
*/
public String dump()
{
StringBuffer sb = new StringBuffer(1024);
sb.append(super.toString()).append('\n');
sb.append("Number of elements: ").append(count).append('\n');
for (int i =0; i < count; i++)
sb.append('[').append(i).append("] = ").append(items[i]).append('\n');
return sb.toString();
}
/** 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(Object[] out)
{
Vm.arrayCopy(items, 0, out, 0, count);
}
/**
* Grows the internal buffer.
*
* @param ensureSize
* minimum size for the new internal buffer
*/
private void grow(int ensureSize)
{
if (ensureSize > 0 && items.length < ensureSize)
{
// On device, grows 20% + 1. On Java, grows 100% + 1.
int newSize = (Settings.onJavaSE ? ensureSize*2 : ensureSize*12/10) + 1; // flsobral@tc110_5: new size is >= current size + 1.- guich@tc112_6: +1 in both cases
Object newItems[] = new Object[newSize];
Vm.arrayCopy(items, 0, newItems, 0, count);
items = newItems;
}
}
/** Returns the items of this vector separated by comma
* @since TotalCross 1.13
*/
public String toString()
{
return super.toString()+" size: "+count+", items: "+toString(",");
}
/** Returns the items of this vector separated by the given string.
* @since TotalCross 1.13
*/
public String toString(String separator)
{
StringBuffer sb = new StringBuffer(10*count);
for (int i = 0, n = count; i < n; i++)
if (items[i] != null)
sb.append(items[i].toString()).append(separator);
if (sb.length() > 0) // cut the last separator
sb.setLength(sb.length()-separator.length());
return sb.toString();
}
/**
* Returns true if this vector contains the specified element.
*
* @param o
* 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(Object o)
{
return indexOf(o) >= 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--)
{
Object temp = items[i];
items[i] = items[j];
items[j] = temp;
}
}
public Object elementAt(int i)
{
return items[i];
}
}