/**
* Copyright (c) 2003-2009, Xith3D Project Group all rights reserved.
*
* Portions based on the Java3D interface, Copyright by Sun Microsystems.
* Many thanks to the developers of Java3D and Sun Microsystems for their
* innovation and design.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* Neither the name of the 'Xith3D Project Group' nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) A
* RISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE
*/
package org.xith3d.utility.general;
import java.lang.reflect.Array;
import java.util.Arrays;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import java.util.ListIterator;
/**
* This is a java.util.List implementation, that provides <b>insitu</b> sorting
* of the elements.<br>
* This is very useful to work GC-friendly with Lists.<br>
* It also has singleton Iterators.
*
* @author Marvin Froehlich (aka Qudus)
*/
public class SortableList< E extends Comparable< E >> implements List< E >
{
private class SLIterator implements Iterator< E >
{
private int cursor = -1;
public boolean hasNext()
{
return ( cursor < size - 1 );
}
public E next()
{
return ( get( ++cursor ) );
}
public void remove()
{
SortableList.this.remove( cursor );
}
public void reset()
{
this.cursor = -1;
}
}
private class SLListIterator implements ListIterator< E >
{
private int cursor = 0;
private int lastCursor = -1;
public boolean hasNext()
{
return ( cursor < size );
}
public boolean hasPrevious()
{
return ( cursor > 0 );
}
public E next()
{
lastCursor = cursor;
return ( get( cursor++ ) );
}
public int nextIndex()
{
return ( cursor );
}
public E previous()
{
lastCursor = cursor - 1;
try
{
return ( get( --cursor ) );
}
catch ( ArrayIndexOutOfBoundsException e )
{
cursor++;
lastCursor = cursor;
throw e;
}
}
public int previousIndex()
{
return ( cursor - 1 );
}
public void add( E e )
{
SortableList.this.add( cursor, e );
cursor++;
}
public void remove()
{
SortableList.this.remove( cursor );
}
public void set( E e )
{
SortableList.this.set( lastCursor, e );
}
public void reset()
{
this.cursor = 0;
this.lastCursor = -1;
}
}
private Object[] array;
private int size;
private SLIterator iterator = new SLIterator();
private SLListIterator listIterator = new SLListIterator();
/**
* Increases the capacity of this <tt>SortableList</tt> instance, if
* necessary, to ensure that it can hold at least the number of elements
* specified by the minimum capacity argument.
*
* @param minCapacity the desired minimum capacity
*/
public void ensureCapacity( int minCapacity )
{
final int oldCapacity = array.length;
if ( minCapacity > oldCapacity )
{
final Object[] oldArray = array;
final int newCapacity = ( oldCapacity * 3 ) / 2 + 1;
array = new Object[ newCapacity ];
System.arraycopy( oldArray, 0, array, 0, oldCapacity );
}
}
/**
* {@inheritDoc}
*/
public int size()
{
return ( size );
}
/**
* {@inheritDoc}
*/
public void add( int index, E element )
{
ensureCapacity( index + 1 );
if ( index == size )
{
array[ index ] = element;
}
else if ( index > size )
{
Arrays.fill( array, size, index - 1, null );
array[ index ] = element;
}
else
{
System.arraycopy( array, index, array, index + 1, size - index - 1 );
array[ index ] = element;
}
size = index + 1;
}
/**
* {@inheritDoc}
*/
public boolean add( E element )
{
add( size, element );
return ( true );
}
/**
* {@inheritDoc}
*/
@SuppressWarnings( "unchecked" )
public boolean addAll( Collection< ? extends E > coll )
{
ensureCapacity( size + coll.size() );
for ( Object o: coll )
{
add( (E)o );
}
return ( true );
}
/**
* {@inheritDoc}
*/
@SuppressWarnings( "unchecked" )
public boolean addAll( int index, Collection< ? extends E > coll )
{
ensureCapacity( size + coll.size() );
if ( index >= size )
{
if ( index > size )
{
Arrays.fill( array, size, index - 1, null );
size = index;
}
for ( Object o: coll )
{
array[ size++ ] = (E)o;
}
}
else
{
System.arraycopy( array, index, array, index + coll.size(), size - index - 1 );
for ( Object o: coll )
{
array[ index++ ] = (E)o;
}
size += coll.size();
}
return ( coll.size() > 0 );
}
/**
* {@inheritDoc}
*/
public void clear()
{
size = 0;
}
/**
* {@inheritDoc}
*/
public boolean contains( Object o )
{
for ( int i = 0; i < size; i++ )
{
if ( array[ i ] == o )
return ( true );
}
return ( false );
}
/**
* {@inheritDoc}
*/
public boolean containsAll( Collection< ? > coll )
{
int result = 0;
for ( Object o: coll )
{
if ( contains( o ) )
result++;
}
return ( result == coll.size() );
}
/**
* {@inheritDoc}
*/
@SuppressWarnings( "unchecked" )
public E get( int index )
{
if ( index >= size )
throw new ArrayIndexOutOfBoundsException( index );
return ( (E)array[ index ] );
}
/**
* {@inheritDoc}
*/
public int indexOf( Object o )
{
if ( o == null )
{
for ( int i = 0; i < size; i++ )
{
if ( array[ i ] == null )
return ( i );
}
}
else
{
for ( int i = 0; i < size; i++ )
{
if ( o.equals( array[ i ] ) )
return ( i );
}
}
return ( -1 );
}
/**
* {@inheritDoc}
*/
public int lastIndexOf( Object o )
{
if ( o == null )
{
for ( int i = size - 1; i >= 0; i-- )
{
if ( array[ i ] == null )
return ( i );
}
}
else
{
for ( int i = size - 1; i >= 0; i-- )
{
if ( o.equals( array[ i ] ) )
return ( i );
}
}
return ( -1 );
}
/**
* {@inheritDoc}
*/
public boolean isEmpty()
{
return ( size == 0 );
}
/**
* {@inheritDoc}
*/
public Iterator< E > iterator()
{
this.iterator.reset();
return ( iterator );
}
/**
* {@inheritDoc}
*/
public ListIterator< E > listIterator( int index )
{
this.listIterator.reset();
return ( listIterator );
}
/**
* {@inheritDoc}
*/
public ListIterator< E > listIterator()
{
return ( listIterator( 0 ) );
}
/**
* {@inheritDoc}
*/
public E remove( int index )
{
if ( index >= size )
throw new ArrayIndexOutOfBoundsException( index );
final E old = get( index );
if ( index < size - 1 )
System.arraycopy( array, index + 1, array, index, size - index - 1 );
size--;
return ( old );
}
/**
* {@inheritDoc}
*/
public boolean remove( Object o )
{
final int index = indexOf( o );
if ( index >= 0 )
{
remove( index );
return ( true );
}
return ( false );
}
/**
* {@inheritDoc}
*/
public boolean removeAll( Collection< ? > coll )
{
boolean result = false;
for ( Object o: coll )
{
if ( remove( o ) )
result = true;
}
return ( result );
}
/**
* {@inheritDoc}
*/
public boolean retainAll( Collection< ? > coll )
{
boolean result = false;
for ( int i = size - 1; i >= 0; i-- )
{
if ( !coll.contains( array[ i ] ) )
{
remove( array[ i ] );
result = true;
}
}
return ( result );
}
/**
* {@inheritDoc}
*/
public E set( int index, E element )
{
if ( index >= size )
throw new ArrayIndexOutOfBoundsException( index );
final E old = get( index );
array[ index ] = element;
return ( old );
}
/**
* {@inheritDoc}
*/
public List< E > subList( int fromIndex, int toIndex )
{
throw new UnsupportedOperationException( "not yet implemented." );
}
/**
* {@inheritDoc}
*/
public Object[] toArray()
{
//E[] result = ( E[] ) Array.newInstance( array.getClass().getComponentType(), size );
Object[] result = new Object[ size ];
System.arraycopy( array, 0, result, 0, size() );
return ( result );
}
/**
* {@inheritDoc}
*/
@SuppressWarnings( "unchecked" )
public < T > T[] toArray( T[] a )
{
if ( a.length < size )
a = (T[])Array.newInstance( a.getClass().getComponentType(), size );
System.arraycopy( array, 0, a, 0, size );
if ( a.length > size )
Arrays.fill( a, size, a.length, null );
return ( a );
}
/**
* Returns a shallow copy of this <tt>SortableList</tt> instance.
* (The elements themselves are not copied.)
*
* @return a clone of this <tt>SortableList</tt> instance
*/
@SuppressWarnings( "unchecked" )
@Override
public Object clone()
{
try
{
SortableList< E > clone = (SortableList< E >)super.clone();
clone.array = (E[])Array.newInstance( array.getClass().getComponentType(), array.length );
System.arraycopy( array, 0, clone.array, 0, array.length );
return ( clone );
}
catch ( CloneNotSupportedException e )
{
// this shouldn't happen, since we are Cloneable
throw new InternalError();
}
}
/**
* Sets the list <b>insutu</b> using a mergesort.
*
* @see Arrays#sort(Object[])
*/
public void sort()
{
if ( size > 1 )
{
// Waaahh! Why inclusive/exclusive? Blame on sun here! (size is needed instead of (size-1))
Arrays.sort( array, 0, size );
}
}
/**
* Creates a new SortableList with an initial size of <tt>initialSize</tt>.
*
* @param initialCapacity
*/
public SortableList( int initialCapacity )
{
this.array = new Object[ initialCapacity ];
this.size = 0;
}
/**
* Creates a new SortableList with an initial size of 16.
*/
public SortableList()
{
this( 16 );
}
}