blob: dbb430888a42d65e35d955e24b328fee6e99d8ed [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;
import java.util.ConcurrentModificationException;
import java.util.ListIterator;
import java.util.NoSuchElementException;
import java.util.Spliterator;
import java.util.Spliterators;
import java.util.stream.Stream;
import java.util.stream.StreamSupport;
import org.apache.uima.cas.impl.LowLevelIterator;
/**
* Iterator over feature structures.
*
* <p>
* This iterator interface extends {@link java.util.Iterator}, and supports the
* standard <code>hasNext</code> and <code>next</code> methods. If finer control, including
* reverse iteration, is needed, see below.
*
* <p>Note: do not use the APIs described below *together* with the standard Java iterator methods
* <code>next()</code> and <code>hasNext()</code>. On any given iterator, use either the one or the
* other, but not both together. Otherwise, <code>next/hasNext</code> may exhibit incorrect
* behavior.
*
* <p>
* The <code>FSIterator</code> interface introduces the methods {@link #get()},
* {@link #moveToNext()}, {@link #moveToPrevious()} methods. With these methods, retrieving the
* current element (<code>get</code>) is a separate operation from moving the iterator (<code>moveToNext</code>
* and <code>moveToPrevious</code>. This makes the user's code less compact, but allows for finer
* control.
*
* <p>
* Specifically the <code>get</code> method is defined to return the same element that a call to
* <code>next()</code> would return, but does not advance the iterator.
*
* <p>
* Implementations of this interface are not required to be fail-fast. That is, if the iterator's
* collection is modified, the effects on the iterator are in general undefined. Some collections
* may handle this more gracefully than others, but in general, concurrent modification of the
* collection you're iterating over is a bad idea.
*
* <p>
* If the iterator is moved past the boundaries of the collection, the behavior of subsequent calls
* to {@link FSIterator#moveToNext() moveToNext()} or
* {@link FSIterator#moveToPrevious() moveToPrevious()} is undefined. For example, if a previously
* valid iterator is invalidated by a call to {@link FSIterator#moveToNext() moveToNext()}, a
* subsequent call to {@link FSIterator#moveToPrevious() moveToPrevious()} is not guaranteed to set
* the iterator back to the last element in the collection. Always use
* {@link FSIterator#moveToLast() moveToLast()} in such cases.
*
*
*
*/
public interface FSIterator<T extends FeatureStructure> extends ListIterator<T> {
/**
* Check if this iterator is valid.
*
* @return <code>true</code> if the iterator is valid.
*/
boolean isValid();
/**
* Get the structure the iterator is pointing at.
*
* @return The structure the iterator is pointing at.
* @exception NoSuchElementException
* If the iterator is not valid.
*/
T get() throws NoSuchElementException;
/**
* Get the structure the iterator is pointing at.
* Throws various unchecked exceptions, if the iterator is not valid
* @return The structure the iterator is pointing at.
*/
default T getNvc() {
return get();
}
/**
* Advance the iterator. This may invalidate the iterator.
* @exception ConcurrentModificationException if the underlying indexes being iterated over were modified
*/
void moveToNext();
/**
* version of moveToNext which bypasses the isValid check - call only if you've just done this check yourself
*/
default void moveToNextNvc() {
moveToNext();
}
/**
* Move the iterator one element back. This may invalidate the iterator.
* @exception ConcurrentModificationException if the underlying indexes being iterated over were modified
*/
void moveToPrevious();
/**
* version of moveToPrevious which bypasses the isValid check - call only if you've just done this check yourself
*/
default void moveToPreviousNvc() {
moveToPrevious();
}
/**
* Move the iterator to the first element. The iterator will be valid iff the underlying
* collection is non-empty. Allowed even if the underlying indexes being iterated over were modified.
*/
void moveToFirst();
/**
* Move the iterator to the last element. The iterator will be valid iff the underlying collection
* is non-empty. Allowed even if the underlying indexes being iterated over were modified.
*/
void moveToLast();
/**
* Move the iterator to the first Feature Structure that is equal to <code>fs</code>.
* First means the earliest one occurring in the index, in case multiple FSs that are "equal" to fs
* are in the index. If no
* such feature structure exists in the underlying collection, set the iterator to the "insertion
* point" for <code>fs</code>, i.e., to a point where the current feature structure is greater
* than <code>fs</code>, and the previous one is less than <code>fs</code>.
* <p>
* If the fs is greater than all of the entries in the index, the moveTo cannot set the iterator to an insertion point
* where the current feature structure is greater than fs, so it marks the iterator "invalid".
* <p>
* If the underlying index is a bag index, no ordering is present, and the moveTo operation moves to the
* fs which is the same identical fs as the key. If no such fs is in the index, the iterator is marked
* invalid.
*
* @param fs
* The feature structure the iterator that supplies the
* comparison information. It can be a supertype of T as long as it can supply the keys needed.
* A typical example is a subtype of Annotation, and using an annotation instance to specify
* the begin / end.
* @exception ConcurrentModificationException if the underlying indexes being iterated over were modified
*/
void moveTo(FeatureStructure fs);
/**
* Copy this iterator.
*
* @return A copy of this iterator, pointing at the same element.
*/
FSIterator<T> copy();
/**
* @return the type this iterator is over
*/
default Type getType() {
return ((LowLevelIterator<T>)this).ll_getIndex().getType();
}
/*****************************************************
* DEFAULT implementations of Iterator interface
* in terms of FSIterator methods
*****************************************************/
/*
* (non-Javadoc)
*
* @see java.util.Iterator#hasNext()
*/
@Override
default boolean hasNext() {
return isValid();
}
/*
* (non-Javadoc)
*
* @see java.util.Iterator#next()
*/
@Override
default T next() {
T result = get();
moveToNext();
return result;
}
default T nextNvc() {
T result = getNvc();
moveToNextNvc();
return result;
}
/*
* (non-Javadoc)
*
* @see java.util.Iterator#remove()
*/
@Override
default void remove() {
throw new UnsupportedOperationException();
}
@Override
default boolean hasPrevious() {
return isValid();
}
@Override
default T previous() {
T result = get();
moveToPrevious();
return result;
}
@Override
default int nextIndex() {
throw new UnsupportedOperationException();
}
@Override
default int previousIndex() {
throw new UnsupportedOperationException();
}
@Override
default void set(T e) {
throw new UnsupportedOperationException();
}
@Override
default void add(T e) {
throw new UnsupportedOperationException();
}
/**
* Don't use this directly, use select()... spliterator instead where possible.
* Otherwise, insure the FSIterator instance can support sized/subsized.
* @return a split iterator for this iterator, which has the following characteristics
* DISTINCT, SIZED, SUBSIZED
*
*/
default Spliterator<T> spliterator() {
return Spliterators.spliterator(
this,
((LowLevelIterator<T>)this).ll_indexSize(),
Spliterator.DISTINCT |
Spliterator.SIZED |
Spliterator.SUBSIZED);
}
default Stream<T> stream() {
return StreamSupport.stream(spliterator(), false);
}
}