blob: 9dc3905829af5803b2f5e2d71646a84b18e762e6 [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.
*/
package org.apache.uima.cas.impl;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.NoSuchElementException;
import org.apache.uima.cas.FSIterator;
import org.apache.uima.cas.FeatureStructure;
/**
* Aggregate several FS iterators. Simply iterates over one after the other, no sorting or merging
* of any kind occurs. Intended for use in
* {@link FSIndexRepositoryImpl#getAllIndexedFS(org.apache.uima.cas.Type)}.
*
* <p>Note: this class does not support moveTo(FS), as it is not sorted.
*/
class FSIteratorAggregate<T extends FeatureStructure> extends FSIteratorImplBase<T> {
// Internal contract for this class is that isValid() iff the current iterator isValid().
// A list of iterators, unordered.
private final List<FSIterator<T>> iterators;
// The offset of the current index.
private int iteratorIndex = 0;
/**
* The one and only constructor.
* @param c Collection of input iterators.
*/
public FSIteratorAggregate(Collection<FSIterator<T>> c) {
super();
this.iterators = new ArrayList<FSIterator<T>>();
this.iterators.addAll(c);
// The unwritten contract of FSIterators is that they point to the first element when they are
// constructed. This is also one way of checking that the new iterator is valid (non-empty).
moveToFirst();
}
public FSIterator<T> copy() {
ArrayList<FSIterator<T>> itCopies = new ArrayList<FSIterator<T>>(this.iterators.size());
for (int i = 0; i < this.iterators.size(); i++) {
itCopies.add(this.iterators.get(i).copy());
}
FSIteratorAggregate<T> copy = new FSIteratorAggregate<T>(itCopies);
copy.iteratorIndex = this.iteratorIndex;
return copy;
}
public T get() throws NoSuchElementException {
if (!isValid()) {
throw new NoSuchElementException();
}
return this.iterators.get(this.iteratorIndex).get();
}
public boolean isValid() {
return (this.iteratorIndex < this.iterators.size());
}
public void moveTo(FeatureStructure fs) {
throw new UnsupportedOperationException("This operation is not supported on an aggregate iterator.");
}
public void moveToFirst() {
// Go through the iterators, starting with the first one
this.iteratorIndex = 0;
while (this.iteratorIndex < this.iterators.size()) {
FSIterator<T> it = this.iterators.get(this.iteratorIndex);
// Reset iterator to first position
it.moveToFirst();
// If the iterator is valid (i.e., non-empty), return...
if (it.isValid()) {
return;
}
// ...else try the next one
++this.iteratorIndex;
}
// If we get here, all iterators are empty.
}
public void moveToLast() {
// See comments on moveToFirst()
this.iteratorIndex = this.iterators.size() - 1;
while (this.iteratorIndex >= 0) {
FSIterator<T> it = this.iterators.get(this.iteratorIndex);
it.moveToLast();
if (it.isValid()) {
return;
}
--this.iteratorIndex;
}
}
public void moveToNext() {
// No point in going anywhere if iterator is not valid.
if (!isValid()) {
return;
}
// Grab current iterator and inc.
FSIterator<T> current = this.iterators.get(this.iteratorIndex);
current.moveToNext();
// If we're ok with the current iterator, return.
if (current.isValid()) {
return;
}
++this.iteratorIndex;
while (this.iteratorIndex < this.iterators.size()) {
current = this.iterators.get(this.iteratorIndex);
current.moveToFirst();
if (current.isValid()) {
return;
}
++this.iteratorIndex;
}
// If we get here, the iterator is no longer valid, there are no more elements.
}
public void moveToPrevious() {
// No point in going anywhere if iterator is not valid.
if (!isValid()) {
return;
}
// Grab current iterator and dec.
FSIterator<T> current = this.iterators.get(this.iteratorIndex);
current.moveToPrevious();
// If we're ok with the current iterator, return.
if (current.isValid()) {
return;
}
--this.iteratorIndex;
while (this.iteratorIndex >= 0) {
current = this.iterators.get(this.iteratorIndex);
current.moveToLast();
if (current.isValid()) {
return;
}
--this.iteratorIndex;
}
// If we get here, the iterator is no longer valid, there are no more elements. Set internal
// counter to the invalid position.
this.iteratorIndex = this.iterators.size();
}
}