/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You 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 com.uwyn.rife.datastructures.collections.primitives;
import java.util.ConcurrentModificationException;
import java.util.NoSuchElementException;
/**
* Abstract base class for {@link IntList}s backed
* by random access structures like arrays.
* <p />
* Read-only subclasses must override {@link #get}
* and {@link #size}. Mutable subclasses
* should also override {@link #set}. Variably-sized
* subclasses should also override {@link #add(int)}
* and {@link #removeElementAt}. All other methods
* have at least some base implementation derived from
* these. Subclasses may choose to override these methods
* to provide a more efficient implementation.
*
* @since Commons Primitives 1.0
* @version $Revision: 3913 $ $Date: 2008-04-13 09:38:28 +0200 (Sun, 13 Apr 2008) $
*
* @author Rodney Waldhoff
*/
public abstract class RandomAccessIntList extends AbstractIntCollection implements IntList {
// constructors
//-------------------------------------------------------------------------
/** Constructs an empty list. */
protected RandomAccessIntList() {
}
// fully abstract methods
//-------------------------------------------------------------------------
public abstract int get(int index);
public abstract int size();
// unsupported in base
//-------------------------------------------------------------------------
/**
* Unsupported in this implementation.
* @throws UnsupportedOperationException since this method is not supported
*/
public int removeElementAt(int index) {
throw new UnsupportedOperationException();
}
/**
* Unsupported in this implementation.
* @throws UnsupportedOperationException since this method is not supported
*/
public int set(int index, int element) {
throw new UnsupportedOperationException();
}
/**
* Unsupported in this implementation.
* @throws UnsupportedOperationException since this method is not supported
*/
public void add(int index, int element) {
throw new UnsupportedOperationException();
}
//-------------------------------------------------------------------------
// javadocs here are inherited
public boolean add(int element) {
add(size(),element);
return true;
}
public boolean addAll(int index, IntCollection collection) {
boolean modified = false;
for(IntIterator iter = collection.iterator(); iter.hasNext(); ) {
add(index++,iter.next());
modified = true;
}
return modified;
}
public int indexOf(int element) {
int i = 0;
for(IntIterator iter = iterator(); iter.hasNext(); ) {
if(iter.next() == element) {
return i;
} else {
i++;
}
}
return -1;
}
public int lastIndexOf(int element) {
for(IntListIterator iter = listIterator(size()); iter.hasPrevious(); ) {
if(iter.previous() == element) {
return iter.nextIndex();
}
}
return -1;
}
public IntIterator iterator() {
return listIterator();
}
public IntListIterator listIterator() {
return listIterator(0);
}
public IntListIterator listIterator(int index) {
return new RandomAccessIntListIterator(this,index);
}
public IntList subList(int fromIndex, int toIndex) {
return new RandomAccessIntSubList(this,fromIndex,toIndex);
}
public boolean equals(Object that) {
if(this == that) {
return true;
} else if(that instanceof IntList) {
IntList thatList = (IntList)that;
if(size() != thatList.size()) {
return false;
}
for(IntIterator thatIter = thatList.iterator(), thisIter = iterator(); thisIter.hasNext();) {
if(thisIter.next() != thatIter.next()) {
return false;
}
}
return true;
} else {
return false;
}
}
public int hashCode() {
int hash = 1;
for(IntIterator iter = iterator(); iter.hasNext(); ) {
hash = 31*hash + iter.next();
}
return hash;
}
public String toString() {
StringBuffer buf = new StringBuffer();
buf.append("[");
for(IntIterator iter = iterator(); iter.hasNext();) {
buf.append(iter.next());
if(iter.hasNext()) {
buf.append(", ");
}
}
buf.append("]");
return buf.toString();
}
// protected utilities
//-------------------------------------------------------------------------
/** Get my count of structural modifications. */
protected int getModCount() {
return _modCount;
}
/** Increment my count of structural modifications. */
protected void incrModCount() {
_modCount++;
}
// attributes
//-------------------------------------------------------------------------
private int _modCount = 0;
// inner classes
//-------------------------------------------------------------------------
private static class ComodChecker {
ComodChecker(RandomAccessIntList source) {
_source = source;
resyncModCount();
}
protected RandomAccessIntList getList() {
return _source;
}
protected void assertNotComodified() throws ConcurrentModificationException {
if(_expectedModCount != getList().getModCount()) {
throw new ConcurrentModificationException();
}
}
protected void resyncModCount() {
_expectedModCount = getList().getModCount();
}
private RandomAccessIntList _source = null;
private int _expectedModCount = -1;
}
protected static class RandomAccessIntListIterator extends ComodChecker implements IntListIterator {
RandomAccessIntListIterator(RandomAccessIntList list, int index) {
super(list);
if(index < 0 || index > getList().size()) {
throw new IndexOutOfBoundsException("Index " + index + " not in [0," + getList().size() + ")");
} else {
_nextIndex = index;
resyncModCount();
}
}
public boolean hasNext() {
assertNotComodified();
return _nextIndex < getList().size();
}
public boolean hasPrevious() {
assertNotComodified();
return _nextIndex > 0;
}
public int nextIndex() {
assertNotComodified();
return _nextIndex;
}
public int previousIndex() {
assertNotComodified();
return _nextIndex - 1;
}
public int next() {
assertNotComodified();
if(!hasNext()) {
throw new NoSuchElementException();
} else {
int val = getList().get(_nextIndex);
_lastReturnedIndex = _nextIndex;
_nextIndex++;
return val;
}
}
public int previous() {
assertNotComodified();
if(!hasPrevious()) {
throw new NoSuchElementException();
} else {
int val = getList().get(_nextIndex-1);
_lastReturnedIndex = _nextIndex-1;
_nextIndex--;
return val;
}
}
public void add(int value) {
assertNotComodified();
getList().add(_nextIndex,value);
_nextIndex++;
_lastReturnedIndex = -1;
resyncModCount();
}
public void remove() {
assertNotComodified();
if (_lastReturnedIndex == -1) {
throw new IllegalStateException();
}
if (_lastReturnedIndex == _nextIndex) {
// remove() following previous()
getList().removeElementAt(_lastReturnedIndex);
} else {
// remove() following next()
getList().removeElementAt(_lastReturnedIndex);
_nextIndex--;
}
_lastReturnedIndex = -1;
resyncModCount();
}
public void set(int value) {
assertNotComodified();
if(-1 == _lastReturnedIndex) {
throw new IllegalStateException();
} else {
getList().set(_lastReturnedIndex,value);
resyncModCount();
}
}
private int _nextIndex = 0;
private int _lastReturnedIndex = -1;
}
protected static class RandomAccessIntSubList extends RandomAccessIntList implements IntList {
RandomAccessIntSubList(RandomAccessIntList list, int fromIndex, int toIndex) {
if(fromIndex < 0 || toIndex > list.size()) {
throw new IndexOutOfBoundsException();
} else if(fromIndex > toIndex) {
throw new IllegalArgumentException();
} else {
_list = list;
_offset = fromIndex;
_limit = toIndex - fromIndex;
_comod = new ComodChecker(list);
_comod.resyncModCount();
}
}
public int get(int index) {
checkRange(index);
_comod.assertNotComodified();
return _list.get(toUnderlyingIndex(index));
}
public int removeElementAt(int index) {
checkRange(index);
_comod.assertNotComodified();
int val = _list.removeElementAt(toUnderlyingIndex(index));
_limit--;
_comod.resyncModCount();
incrModCount();
return val;
}
public int set(int index, int element) {
checkRange(index);
_comod.assertNotComodified();
int val = _list.set(toUnderlyingIndex(index),element);
incrModCount();
_comod.resyncModCount();
return val;
}
public void add(int index, int element) {
checkRangeIncludingEndpoint(index);
_comod.assertNotComodified();
_list.add(toUnderlyingIndex(index),element);
_limit++;
_comod.resyncModCount();
incrModCount();
}
public int size() {
_comod.assertNotComodified();
return _limit;
}
private void checkRange(int index) {
if(index < 0 || index >= size()) {
throw new IndexOutOfBoundsException("index " + index + " not in [0," + size() + ")");
}
}
private void checkRangeIncludingEndpoint(int index) {
if(index < 0 || index > size()) {
throw new IndexOutOfBoundsException("index " + index + " not in [0," + size() + "]");
}
}
private int toUnderlyingIndex(int index) {
return (index + _offset);
}
private int _offset = 0;
private int _limit = 0;
private RandomAccessIntList _list = null;
private ComodChecker _comod = null;
}
}