blob: cdd00b5f0fdc3a9683ac5f796c836fe610b16e90 [file] [log] [blame]
/*
* 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.
*/
#ifndef _DECAF_UTIL_ABSTRACTLIST_H_
#define _DECAF_UTIL_ABSTRACTLIST_H_
#include <decaf/util/Config.h>
#include <decaf/util/NoSuchElementException.h>
#include <decaf/lang/exceptions/UnsupportedOperationException.h>
#include <decaf/lang/exceptions/NullPointerException.h>
#include <decaf/lang/exceptions/IllegalArgumentException.h>
#include <decaf/util/ConcurrentModificationException.h>
#include <decaf/lang/Iterable.h>
#include <decaf/util/Iterator.h>
#include <decaf/util/List.h>
#include <decaf/util/AbstractCollection.h>
#include <memory>
namespace decaf {
namespace util {
/**
* This class provides a skeletal implementation of the List interface to minimize
* the effort required to implement this interface backed by a "random access" data
* store (such as an array). For sequential access data (such as a linked list),
* AbstractSequentialList should be used in preference to this class.
*
* To implement an unmodifiable list, the programmer needs only to extend this class
* and provide implementations for the get(int) and size() methods.
*
* To implement a modifiable list, the programmer must additionally override the
* set(int, E) method (which otherwise throws an UnsupportedOperationException). If
* the list is variable-size the programmer must additionally override the add(int, E)
* and remove(int) methods.
*
* The programmer should generally provide a void (no argument) and collection
* constructor, as per the recommendation in the Collection interface specification.
*
* Unlike the other abstract collection implementations, the programmer does not have
* to provide an iterator implementation; the iterator and list iterator are implemented
* by this class, on top of the "random access" methods: get(int), set(int, E),
* add(int, E) and remove(int).
*
* The documentation for each non-abstract method in this class describes its
* implementation in detail. Each of these methods may be overridden if the collection
* being implemented admits a more efficient implementation.
*
* @since 1.0
*/
template< typename E >
class AbstractList : public decaf::util::List<E>,
public decaf::util::AbstractCollection<E> {
protected:
int modCount;
private:
class SimpleListIterator : public ListIterator<E> {
protected:
AbstractList<E>* parent;
int numLeft;
int expectedModCount;
int lastPosition;
private:
SimpleListIterator(const SimpleListIterator&);
SimpleListIterator operator=(const SimpleListIterator&);
public:
SimpleListIterator(AbstractList<E>* parent, int start) :
ListIterator<E>(), parent(NULL), numLeft(0), expectedModCount(0), lastPosition(-1) {
if (parent == NULL) {
throw decaf::lang::exceptions::NullPointerException(
__FILE__, __LINE__, "List Iterator constructed with NULL parent");
}
if (start < 0 || start > parent->size()) {
throw decaf::lang::exceptions::IndexOutOfBoundsException(
__FILE__, __LINE__, "start index passed was negative or greater than size()");
}
this->numLeft = parent->size() - start;
this->parent = parent;
this->expectedModCount = parent->modCount;
}
virtual ~SimpleListIterator() {}
virtual bool hasNext() const {
return this->numLeft > 0;
}
virtual E next() {
if (this->expectedModCount != this->parent->modCount) {
throw ConcurrentModificationException(
__FILE__, __LINE__, "Concurrent Modification of Parent List detected.");
}
try {
int index = this->parent->size() - this->numLeft;
E result = this->parent->get( index );
this->lastPosition = index;
this->numLeft--;
return result;
} catch (decaf::lang::exceptions::IndexOutOfBoundsException& e) {
throw decaf::util::NoSuchElementException(
__FILE__, __LINE__, "Next called without a next element to process.");
}
}
virtual void remove() {
if (this->lastPosition == -1) {
throw decaf::lang::exceptions::IllegalStateException(
__FILE__, __LINE__, "Remove called before next() was called.");
}
if (this->expectedModCount != this->parent->modCount) {
throw ConcurrentModificationException(
__FILE__, __LINE__, "Concurrent Modification of Parent List detected.");
}
try {
if (this->lastPosition == this->parent->size() - this->numLeft) {
this->numLeft--; // we're removing after a call to previous()
}
this->parent->removeAt( lastPosition );
} catch (decaf::lang::exceptions::IndexOutOfBoundsException& e) {
throw ConcurrentModificationException(
__FILE__, __LINE__, "Concurrent Modification detected.");
}
this->expectedModCount = this->parent->modCount;
this->lastPosition = -1;
}
virtual void add(const E& value) {
if (this->expectedModCount != this->parent->modCount) {
throw ConcurrentModificationException(
__FILE__, __LINE__, "Concurrent Modification of Parent List detected.");
}
try {
this->parent->add(this->parent->size() - this->numLeft, value);
this->expectedModCount = this->parent->modCount;
this->lastPosition = -1;
} catch (decaf::lang::exceptions::IndexOutOfBoundsException& e) {
throw decaf::util::NoSuchElementException(
__FILE__, __LINE__, "Add called without a next element to process.");
}
}
virtual bool hasPrevious() const {
return this->numLeft < this->parent->size();
}
virtual int nextIndex() const {
return this->parent->size() - this->numLeft;
}
virtual E previous() {
if (this->expectedModCount != this->parent->modCount) {
throw ConcurrentModificationException(
__FILE__, __LINE__, "Concurrent Modification detected.");
}
try {
int index = this->parent->size() - this->numLeft - 1;
E result = this->parent->get(index);
this->numLeft++;
this->lastPosition = index;
return result;
} catch( decaf::lang::exceptions::IndexOutOfBoundsException& e ) {
throw decaf::util::NoSuchElementException(
__FILE__, __LINE__, "No previous element exists.");
}
}
virtual int previousIndex() const {
return this->parent->size() - this->numLeft - 1;
}
virtual void set(const E& value) {
if (this->expectedModCount != this->parent->modCount) {
throw ConcurrentModificationException(
__FILE__, __LINE__, "Concurrent Modification detected.");
}
try {
this->parent->set(this->lastPosition, value);
} catch( decaf::lang::exceptions::IndexOutOfBoundsException& e ) {
throw decaf::lang::exceptions::IllegalStateException();
}
}
};
class ConstSimpleListIterator : public ListIterator<E> {
protected:
const AbstractList<E>* parent;
int numLeft;
int expectedModCount;
int lastPosition;
private:
ConstSimpleListIterator(const ConstSimpleListIterator&);
ConstSimpleListIterator operator=(const ConstSimpleListIterator&);
public:
ConstSimpleListIterator(const AbstractList<E>* parent, int start) :
ListIterator<E>(), parent(parent), numLeft(0), expectedModCount(0), lastPosition(-1) {
if (parent == NULL) {
throw decaf::lang::exceptions::NullPointerException(
__FILE__, __LINE__, "List Iterator constructed with NULL parent");
}
if (start < 0 || start > parent->size()) {
throw decaf::lang::exceptions::IndexOutOfBoundsException(
__FILE__, __LINE__, "start index passed was negative or greater than size()");
}
this->numLeft = parent->size() - start;
this->parent = parent;
this->expectedModCount = parent->modCount;
}
virtual ~ConstSimpleListIterator() {}
virtual bool hasNext() const {
return this->numLeft > 0;
}
virtual E next() {
if (this->expectedModCount != this->parent->modCount) {
throw ConcurrentModificationException(
__FILE__, __LINE__, "Concurrent Modification of Parent List detected.");
}
try {
int index = this->parent->size() - this->numLeft;
E result = this->parent->get(index);
this->lastPosition = index;
this->numLeft--;
return result;
} catch (decaf::lang::exceptions::IndexOutOfBoundsException& e) {
throw decaf::util::NoSuchElementException(
__FILE__, __LINE__, "Next called without a next element to process.");
}
}
virtual void remove() {
throw lang::exceptions::UnsupportedOperationException(
__FILE__, __LINE__,
"AbstractList::Iterator::remove - Const Iterator.");
}
virtual void add(const E& value DECAF_UNUSED) {
throw lang::exceptions::UnsupportedOperationException(
__FILE__, __LINE__,
"AbstractList::ListIterator::radd - Const Iterator.");
}
virtual bool hasPrevious() const {
return this->numLeft < this->parent->size();
}
virtual int nextIndex() const {
return this->parent->size() - this->numLeft;
}
virtual E previous() {
if (this->expectedModCount != this->parent->modCount) {
throw ConcurrentModificationException(
__FILE__, __LINE__, "Concurrent Modification detected.");
}
try {
int index = this->parent->size() - this->numLeft - 1;
E result = this->parent->get(index);
this->numLeft++;
this->lastPosition = index;
return result;
} catch (decaf::lang::exceptions::IndexOutOfBoundsException& e) {
throw decaf::util::NoSuchElementException(
__FILE__, __LINE__, "No previous element exists.");
}
}
virtual int previousIndex() const {
return this->parent->size() - this->numLeft - 1;
}
virtual void set(const E& value DECAF_UNUSED) {
throw lang::exceptions::UnsupportedOperationException(
__FILE__, __LINE__,
"AbstractList::ListIterator::set - Const Iterator.");
}
};
public:
AbstractList() : modCount( 0 ) {}
virtual ~AbstractList() {}
virtual Iterator<E>* iterator() {
return new SimpleListIterator(this, 0);
}
virtual Iterator<E>* iterator() const {
return new ConstSimpleListIterator(this, 0);
}
virtual ListIterator<E>* listIterator() {
return new SimpleListIterator(this, 0);
}
virtual ListIterator<E>* listIterator() const {
return new ConstSimpleListIterator(this, 0);
}
virtual ListIterator<E>* listIterator(int index) {
return new SimpleListIterator(this, index);
}
virtual ListIterator<E>* listIterator(int index) const {
return new ConstSimpleListIterator(this, index);
}
virtual void clear() {
this->removeRange(0, this->size());
}
virtual bool add(const E& value) {
this->add(this->size(), value);
return true;
}
virtual void add(int index DECAF_UNUSED, const E& element DECAF_UNUSED) {
throw decaf::lang::exceptions::UnsupportedOperationException(
__FILE__, __LINE__, "Abstract list does not implement the add method.");
}
// Use this method since our own addAll will hide the base class version.
using AbstractCollection<E>::addAll;
virtual bool addAll(int index, const Collection<E>& source) {
std::auto_ptr<decaf::util::Iterator<E> > iter(source.iterator());
while (iter->hasNext()) {
this->add(index++, iter->next());
}
return !source.isEmpty();
}
virtual E removeAt(int index DECAF_UNUSED) {
throw decaf::lang::exceptions::UnsupportedOperationException(
__FILE__, __LINE__, "Abstract list does not implement the removeAt method.");
}
virtual E set(int index DECAF_UNUSED, const E& element DECAF_UNUSED) {
throw decaf::lang::exceptions::UnsupportedOperationException(
__FILE__, __LINE__, "Abstract list does not implement the set method.");
}
virtual int indexOf(const E& value) const {
std::auto_ptr<decaf::util::ListIterator<E> > iter(this->listIterator());
while (iter->hasNext()) {
if (value == iter->next()) {
return iter->previousIndex();
}
}
return -1;
}
virtual int lastIndexOf(const E& value) const {
std::auto_ptr< decaf::util::ListIterator<E> > iter( this->listIterator( this->size() ) );
while (iter->hasPrevious()) {
if (value == iter->previous()) {
return iter->nextIndex();
}
}
return -1;
}
protected:
void removeRange(int start, int end) {
std::auto_ptr<decaf::util::Iterator<E> > iter(this->listIterator(start));
for (int i = start; i < end; i++) {
iter->next();
iter->remove();
}
}
};
}}
#endif /* _DECAF_UTIL_ABSTRACTLIST_H_ */