blob: 9ec24872c5dad3bdffc0d49292f701a21038fb82 [file] [log] [blame]
/*
* Copyright 2007 Google Inc.
*
* 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 java.util;
import static javaemul.internal.InternalPreconditions.checkCriticalPositionIndexes;
import static javaemul.internal.InternalPreconditions.checkElement;
import static javaemul.internal.InternalPreconditions.checkElementIndex;
import static javaemul.internal.InternalPreconditions.checkNotNull;
import static javaemul.internal.InternalPreconditions.checkPositionIndex;
import static javaemul.internal.InternalPreconditions.checkState;
import jsinterop.annotations.JsNonNull;
/**
* Skeletal implementation of the List interface. <a
* href="http://java.sun.com/j2se/1.5.0/docs/api/java/util/AbstractList.html">[Sun
* docs]</a>
*
* @param <E> the element type.
*/
public abstract class AbstractList<E> extends AbstractCollection<E> implements
List<E> {
private class IteratorImpl implements Iterator<E> {
/*
* i is the index of the item that will be returned on the next call to
* next() last is the index of the item that was returned on the previous
* call to next() or previous (for ListIterator), -1 if no such item exists.
*/
int i = 0, last = -1;
@Override
public boolean hasNext() {
return i < AbstractList.this.size();
}
@Override
public E next() {
checkElement(hasNext());
return AbstractList.this.get(last = i++);
}
@Override
public void remove() {
checkState(last != -1);
AbstractList.this.remove(last);
i = last;
last = -1;
}
}
/**
* Implementation of <code>ListIterator</code> for abstract lists.
*/
private final class ListIteratorImpl extends IteratorImpl implements
ListIterator<E> {
/*
* i is the index of the item that will be returned on the next call to
* next() last is the index of the item that was returned on the previous
* call to next() or previous (for ListIterator), -1 if no such item exists.
*/
private ListIteratorImpl() {
// Nothing to do
}
private ListIteratorImpl(int start) {
checkPositionIndex(start, AbstractList.this.size());
i = start;
}
@Override
public void add(E o) {
AbstractList.this.add(i, o);
i++;
last = -1;
}
@Override
public boolean hasPrevious() {
return i > 0;
}
@Override
public int nextIndex() {
return i;
}
@Override
public E previous() {
checkElement(hasPrevious());
return AbstractList.this.get(last = --i);
}
@Override
public int previousIndex() {
return i - 1;
}
@Override
public void set(E o) {
checkState(last != -1);
AbstractList.this.set(last, o);
}
}
private static class SubList<E> extends AbstractList<E> {
private final List<E> wrapped;
private final int fromIndex;
private int size;
public SubList(List<E> wrapped, int fromIndex, int toIndex) {
checkCriticalPositionIndexes(fromIndex, toIndex, wrapped.size());
this.wrapped = wrapped;
this.fromIndex = fromIndex;
this.size = toIndex - fromIndex;
}
@Override
public void add(int index, E element) {
checkPositionIndex(index, size);
wrapped.add(fromIndex + index, element);
size++;
}
@Override
public E get(int index) {
checkElementIndex(index, size);
return wrapped.get(fromIndex + index);
}
@Override
public E remove(int index) {
checkElementIndex(index, size);
E result = wrapped.remove(fromIndex + index);
size--;
return result;
}
@Override
public E set(int index, E element) {
checkElementIndex(index, size);
return wrapped.set(fromIndex + index, element);
}
@Override
public int size() {
return size;
}
}
protected transient int modCount;
protected AbstractList() {
}
@Override
public boolean add(E obj) {
add(size(), obj);
return true;
}
@Override
public void add(int index, E element) {
throw new UnsupportedOperationException("Add not supported on this list");
}
@Override
public boolean addAll(int index, Collection<? extends E> c) {
checkNotNull(c);
boolean changed = false;
for (E e : c) {
add(index++, e);
changed = true;
}
return changed;
}
@Override
public void clear() {
removeRange(0, size());
}
@Override
public boolean equals(Object o) {
if (o == this) {
return true;
}
if (!(o instanceof List)) {
return false;
}
List<?> other = (List<?>) o;
if (size() != other.size()) {
return false;
}
Iterator<?> iterOther = other.iterator();
for (E elem : this) {
Object elemOther = iterOther.next();
if (!Objects.equals(elem, elemOther)) {
return false;
}
}
return true;
}
@Override
public int hashCode() {
return Collections.hashCode(this);
}
@Override
public int indexOf(Object toFind) {
for (int i = 0, n = size(); i < n; ++i) {
if (Objects.equals(toFind, get(i))) {
return i;
}
}
return -1;
}
@Override
public Iterator<E> iterator() {
return new IteratorImpl();
}
@Override
public int lastIndexOf(Object toFind) {
for (int i = size() - 1; i > -1; --i) {
if (Objects.equals(toFind, get(i))) {
return i;
}
}
return -1;
}
@Override
public ListIterator<E> listIterator() {
return listIterator(0);
}
@Override
public ListIterator<E> listIterator(int from) {
return new ListIteratorImpl(from);
}
@Override
public E remove(int index) {
throw new UnsupportedOperationException("Remove not supported on this list");
}
@Override
public E set(int index, E o) {
throw new UnsupportedOperationException("Set not supported on this list");
}
@Override
@JsNonNull
public List<E> subList(int fromIndex, int toIndex) {
return new SubList<E>(this, fromIndex, toIndex);
}
protected void removeRange(int fromIndex, int endIndex) {
ListIterator<E> iter = listIterator(fromIndex);
for (int i = fromIndex; i < endIndex; ++i) {
iter.next();
iter.remove();
}
}
}