/***********************************************************************************************************************
*
* Copyright (C) 2010-2013 by the Stratosphere project (http://stratosphere.eu)
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
* an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
* specific language governing permissions and limitations under the License.
*
**********************************************************************************************************************/
package eu.stratosphere.util;
import it.unimi.dsi.fastutil.objects.ObjectArrayList;
import it.unimi.dsi.fastutil.objects.ObjectArrays;
/**
* A list implementation that does not release removed elements but allows them to be reused.
*/
public class CachingList<T> extends ObjectArrayList<T> {
/**
*
*/
private static final long serialVersionUID = 7946169971753399385L;
private int usedElements;
/**
* Initializes CachingList.
*/
public CachingList() {
}
/**
* Creates a new array list using a given array.
* <P>
* This constructor is only meant to be used by the wrapping methods.
*
* @param a
* the array that will be used to back this array list.
*/
protected CachingList(final T a[], final boolean dummy) {
super(a, dummy);
}
@Override
public void add(final int index, final T element) {
this.checkRange(index, this.usedElements + 1);
if (index < this.usedElements) // insert
super.add(index, element);
else if (this.usedElements == super.size()) // append
super.add(element);
else
super.set(index, element);
this.usedElements++;
}
@Override
public boolean add(final T element) {
if (this.usedElements == super.size()) // append
super.add(element);
else
super.set(this.usedElements, element);
this.usedElements++;
return true;
}
/*
* (non-Javadoc)
* @see java.util.AbstractList#clear()
*/
@Override
public void clear() {
this.usedElements = 0;
}
/*
* (non-Javadoc)
* @see java.util.AbstractList#get(int)
*/
@Override
public T get(final int index) {
this.checkRange(index, this.usedElements);
return super.get(index);
}
public T getUnusedElement() {
if (super.size() == this.usedElements)
return null;
return super.get(this.usedElements);
}
@Override
public T remove(final int index) {
this.checkRange(index, this.usedElements);
final T oldObject = super.remove(index);
super.add(oldObject);
this.usedElements--;
return oldObject;
}
/**
* Reactivates the last element if such an element exists.<br />
* Do not call {@link #add(Object)} in the successful case.
*
* @return a reactivated element or null
*/
public T reuseUnusedElement() {
if (super.size() == this.usedElements)
return null;
return super.get(this.usedElements++);
}
/*
* (non-Javadoc)
* @see java.util.AbstractCollection#size()
*/
@Override
public int size() {
return this.usedElements;
}
/*
* (non-Javadoc)
* @see it.unimi.dsi.fastutil.objects.ObjectArrayList#size(int)
*/
@Override
public void size(final int size) {
if (size > this.a.length)
this.ensureCapacity(size);
if (size > this.size) {
ObjectArrays.fill(this.a, this.size, size, null);
this.size = size;
}
this.usedElements = size;
}
/*
* (non-Javadoc)
* @see it.unimi.dsi.fastutil.objects.ObjectArrayList#size(int)
*/
public void size(final int size, final T defaultElement) {
if (size > this.a.length)
this.ensureCapacity(size);
if (size > this.size) {
ObjectArrays.fill(this.a, this.size, size, defaultElement);
this.size = size;
}
this.usedElements = size;
}
private void checkRange(final int index, final int size) {
if (index >= size)
throw new IndexOutOfBoundsException("Index: " + index + ", Size: " + size);
}
/**
* Wraps a given array into an array list.
*
* @param a
* an array to wrap.
* @return a new array list wrapping the given array.
*/
public static <K> CachingList<K> wrap(final K a[]) {
return wrap(a, a.length);
}
/**
* Wraps a given array into an array list of given size.
*
* @param a
* an array to wrap.
* @param length
* the length of the resulting array list.
* @return a new array list of the given size, wrapping the given array.
*/
public static <K> CachingList<K> wrap(final K a[], final int length) {
if (length > a.length)
throw new IllegalArgumentException("The specified length (" + length +
") is greater than the array size (" + a.length + ")");
final CachingList<K> l = new CachingList<K>(a, false);
l.size = length;
return l;
}
}