/**
*
*/
package vroom.common.utilities;
import java.util.AbstractSequentialList;
import java.util.Comparator;
import java.util.List;
import java.util.ListIterator;
import java.util.NoSuchElementException;
/**
* Fixed size implementation of the {@link List} interface, this class holds a list of at most <code>k</code> elements
* sorted according to their natural ordering.
* <p>
* <code>LimitedSortedList</code> is backed up by a doubly linked list, and {@link #add(Comparable) add} is executed in
* {@code O(k)}
* </p>
* <p>
* Creation date: Oct 18, 2011 - 2:04:51 PM
*
* @author Victor Pillac, <a href="http://uniandes.edu.co">Universidad de Los Andes</a>-<a
* href="http://copa.uniandes.edu.co">Copa</a> <a href="http://www.emn.fr">Ecole des Mines de Nantes</a>-<a
* href="http://www.irccyn.ec-nantes.fr/irccyn/d/en/equipes/Slp">SLP</a>
* @version 1.0
*/
public class LimitedSortedList<E> extends AbstractSequentialList<E> {
/** The maximum size of this list */
private final int mMaxSize;
private int mSize;
private Element mFirst;
private Element mLast;
private final Comparator<? super E> mComparator;
/**
* Creates a new <code>LimitedSortedList</code>
*
* @param size
* the desired size for this list
*/
public LimitedSortedList(int size) {
this(size, new Comparator<E>() {
@SuppressWarnings("unchecked")
@Override
public int compare(E o1, E o2) {
return ((Comparable<? super E>) o1).compareTo(o2);
}
});
}
/**
* Creates a new <code>LimitedSortedList</code>
*
* @param size
* the desired size for this list
*/
public LimitedSortedList(int size, Comparator<E> comparator) {
if (size < 1)
throw new IllegalArgumentException("Illegal size: " + size);
mMaxSize = size;
mSize = 0;
mComparator = comparator;
}
@Override
public boolean add(E e) {
if (mFirst == null) {
// The list is currently empty
mFirst = new Element(e);
mLast = mFirst;
mSize++;
return true;
} else if (isBefore(e, mFirst.mElement)) {
// The element better than the first element
Element el = new Element(e);
el.mNext = mFirst;
mFirst.mPrev = el;
mFirst = el;
mSize++;
checkSize();
return true;
} else {
boolean roomLeft = size() < mMaxSize;
boolean betterThanLast = isBefore(e, mLast.mElement);
if (roomLeft && !betterThanLast) {
// Append the element to the end of the list
Element el = new Element(e);
el.mPrev = mLast;
mLast.mNext = el;
mLast = el;
mSize++;
// We dont check the size as this will only happen if we have space left
return true;
} else if (betterThanLast) {
// The element better than the last element or the list not full
ListIterator<E> it = listIterator();
it.next(); // Skip the first element
while (it.hasNext()) {
E next = it.next();
if (isBefore(e, next)) {
// The element is better than the next element of the list
break;
}
}
it.previous(); // Move the iterator to its previous position
it.add(e); // Insert the element
checkSize();
return true;
} else {
return false;
}
}
}
/**
* Returns {@code true} if {@code o1} should appear before {@code o2} in the list
*
* @param o1
* @param o2
* @return {@code true} if {@code o1} should appear before {@code o2} in the list
*/
private boolean isBefore(E o1, E o2) {
return mComparator.compare(o1, o2) < 0;
}
private void checkSize() {
while (size() > mMaxSize) {
mLast = mLast.mPrev;
mLast.mNext = null;
mSize--;
}
}
public int size() {
return mSize;
}
/**
* Returns the first element of this list
*
* @return the first element of this list
*/
public E first() {
if (mFirst == null)
throw new NoSuchElementException();
return mFirst.mElement;
}
/**
* Returns the last element of this list
*
* @return the last element of this list
*/
public E last() {
if (mLast == null)
throw new NoSuchElementException();
return mLast.mElement;
}
@Override
public void clear() {
mFirst = null;
mLast = null;
mSize = 0;
}
@Override
public LimitedSortedListIterator listIterator(int index) {
if (index > size())
throw new IndexOutOfBoundsException();
int idx = 0;
Element first = mFirst;
while (idx < index) {
first = first.mNext;
idx++;
}
return new LimitedSortedListIterator(first);
}
private class Element {
private final E mElement;
private Element mPrev;
private Element mNext;
/**
* Creates a new <code>Element</code>
*
* @param element
*/
private Element(E element) {
mElement = element;
}
@Override
public String toString() {
return mElement != null ? mElement.toString() : "null";
}
}
private class LimitedSortedListIterator implements ListIterator<E> {
private Element mCurrent;
private int mIdx;
private LimitedSortedListIterator(Element first) {
mCurrent = new Element(null);
mCurrent.mNext = first;
mIdx = 0;
}
@Override
public boolean hasNext() {
return mCurrent != null && mCurrent.mNext != null;
}
@Override
public E next() {
if (!hasNext())
throw new NoSuchElementException();
mCurrent = mCurrent.mNext;
mIdx++;
return mCurrent.mElement;
}
@Override
public void remove() {
if (!hasPrevious())
throw new NoSuchElementException();
if (mCurrent.mPrev == null) {
// Current was the first node
mFirst = mCurrent.mNext;
} else {
mCurrent.mPrev.mNext = mCurrent.mNext;
}
if (mCurrent.mNext == null) {
// Current was the last node
mLast = mCurrent.mPrev;
} else {
mCurrent.mNext.mPrev = mCurrent.mPrev;
}
mSize--;
}
@Override
public boolean hasPrevious() {
return mCurrent != null;
}
@Override
public E previous() {
if (!hasPrevious())
throw new NoSuchElementException();
Element prev = mCurrent;
mCurrent = mCurrent.mPrev;
mIdx--;
return prev.mElement;
}
@Override
public int nextIndex() {
return mIdx;
}
@Override
public int previousIndex() {
return mIdx - 1;
}
@Override
public void set(E e) {
throw new UnsupportedOperationException();
}
@Override
public void add(E e) {
Element el = new Element(e);
el.mPrev = mCurrent;
if (mCurrent.mNext != null)
mCurrent.mNext.mPrev = el;
el.mNext = mCurrent.mNext;
mCurrent.mNext = el;
if (mCurrent.mNext == mFirst)
// The next element is the first element of the list
mFirst = el;
mCurrent = el;
mSize++;
}
}
}