blob: c446f246230910c9fdde6edc43366e5354800d7f [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.Comparator;
import java.util.NoSuchElementException;
import java.util.concurrent.atomic.AtomicInteger;
import org.apache.uima.UIMAFramework;
import org.apache.uima.cas.FSIndex;
import org.apache.uima.cas.FSIterator;
import org.apache.uima.cas.FeatureStructure;
import org.apache.uima.cas.Type;
import org.apache.uima.internal.util.Misc;
import org.apache.uima.jcas.cas.TOP;
/**
* Aggregate several FS iterators. Simply iterates over one after the other
* without any sorting or merging.
* Used by getAllIndexedFS and FsIterator_subtypes when unordered
* underlying iterators could be any (bag, set, or ordered
* underlying iterators could be complex (unambiguous annotation, filtered,...)
*
* The iterators can be for single types or for types with subtypes.
* Exception: if the ll_index is accessed, it is presumed to be of type FsIndex_subtypes.
*/
class FsIterator_aggregation_common<T extends FeatureStructure> extends FsIterator_multiple_indexes<T> {
private final static AtomicInteger moveToCount = new AtomicInteger(0);
// /** only used for moveTo */
// final private boolean ignoreTypePriority;
/** the index of the current iterator */
private int current_it_idx = -1;
FsIterator_aggregation_common(LowLevelIterator<T>[] iterators,
FSIndex<T> index,
Comparator<TOP> comparatorMaybeNoTypeWithoutId) {
super((LowLevelIndex<T>)index, iterators, comparatorMaybeNoTypeWithoutId);
moveToFirstNoReinit();
}
/** copy constructor */
FsIterator_aggregation_common(FsIterator_aggregation_common<T> v) {
super(v);
current_it_idx = v.current_it_idx;
}
/* (non-Javadoc)
* @see org.apache.uima.cas.impl.LowLevelIterator#moveToSupported()
*/
@Override
public boolean isMoveToSupported() {
return false;
}
/* (non-Javadoc)
* @see org.apache.uima.cas.FSIterator#isValid()
*/
@Override
public boolean isValid() {
return current_it_idx >= 0;
}
/* (non-Javadoc)
* @see org.apache.uima.cas.FSIterator#getNvc()
*/
@Override
public T getNvc() throws NoSuchElementException {
return nonEmptyIterators[current_it_idx].getNvc();
}
/**
* MoveTo for this kind of iterator
* Happens for set or sorted indexes being operated without rattling, or for other kinds of aggregation.
*
* The meaning for set is to go to the position if it exists of the 1 element equal (using the index's comparator) the arg.
* But since the set is unordered, there's no point in doing this.
*
* The meaning for unordered other kinds: They're not really unordered, just the aggregate is unordered.
* A use would be to partially restart iteration from some point.
* But since this is unordered, there's not much point in doing this
*
*/
public void moveToNoReinit(FeatureStructure fs) {
Misc.decreasingWithTrace(moveToCount, "MoveTo operations on unsorted iterators are likely mistakes." , UIMAFramework.getLogger());
// Type typeCompare = fs.getType();
int i = -1;
int validNonMatch = -1;
for (LowLevelIterator<T> it : nonEmptyIterators) {
i++;
// Type itType = (TypeImpl) it.getType();
// if ( ! typeCompare.subsumes(itType) ) {
// continue;
// }
it.moveToNoReinit(fs);
if (it.isValid() && 0 == it.ll_getIndex().compare(fs, it.getNvc())) {
current_it_idx = i;
return; // perfect match
}
if (validNonMatch == -1 && it.isValid()) {
validNonMatch = i; // capture first valid non-Match
}
}
// nothing matched using iterator compare
if (validNonMatch >= 0) {
current_it_idx = validNonMatch;
return;
}
// mark iterator invalid otherwise
current_it_idx = -1;
}
// /**
// * MoveToExact for this kind of iterator
// */
// public void moveToExactNoReinit(FeatureStructure fs) {
// Type typeCompare = fs.getType();
// int i = 0;
// for (LowLevelIterator<T> it : nonEmptyIterators) {
// if (it.getType() == typeCompare) {
// it.moveToExactNoReinit(fs);
// current_it_idx = it.isValid() ? i : -1;
// return;
// }
// i++;
// }
// current_it_idx = -1;
// }
/** moves to the first non-empty iterator at its start position */
public void moveToFirstNoReinit() {
current_it_idx = -1; // no valid index
for (LowLevelIterator<T> it : nonEmptyIterators) {
current_it_idx++;
it.moveToFirstNoReinit();
if (it.isValid()) {
return;
}
}
}
public void moveToLastNoReinit() {
for (int i = nonEmptyIterators.length -1; i >= 0; i--) {
LowLevelIterator<T> it = nonEmptyIterators[i];
it.moveToLastNoReinit();
if (it.isValid()) {
current_it_idx = i;
return;
}
}
current_it_idx = -1; // no valid index
}
public void moveToNextNvc() {
FSIterator<T> it = nonEmptyIterators[current_it_idx];
it.moveToNextNvc();
if (it.isValid()) {
return;
}
final int nbrIt = nonEmptyIterators.length;
for (int i = current_it_idx + 1; i < nbrIt; i++) {
it = nonEmptyIterators[i];
it.moveToFirst();
if (it.isValid()) {
current_it_idx = i;
return;
}
}
current_it_idx = -1; // invalid position
}
@Override
public void moveToPreviousNvc() {
LowLevelIterator<T> it = nonEmptyIterators[current_it_idx];
it.moveToPreviousNvc();
if (it.isValid()) {
return;
}
for (int i = current_it_idx - 1; i >= 0; i--) {
it = nonEmptyIterators[i];
it.moveToLastNoReinit();
if (it.isValid()) {
current_it_idx = i;
return;
}
}
current_it_idx = -1; // invalid position
}
public int ll_indexSizeMaybeNotCurrent() {
int sum = 0;
for (int i = nonEmptyIterators.length - 1; i >= 0; i--) {
FSIterator<T> it = nonEmptyIterators[i];
sum += ((LowLevelIterator<T>)it).ll_indexSizeMaybeNotCurrent();
}
return sum;
}
public int ll_maxAnnotSpan() {
throw Misc.internalError(); // should never be called, because this operation isn't useful
// in unordered indexes
// int span = -1;
// for (int i = nonEmptyIterators.length - 1; i >= 0; i--) {
// FSIterator<T> it = nonEmptyIterators[i];
// int x = ((LowLevelIterator<T>)it).ll_maxAnnotSpan();
// if (x > span) {
// span = x;
// }
// }
// return (span == -1) ? Integer.MAX_VALUE : span;
};
/* (non-Javadoc)
* @see org.apache.uima.cas.FSIterator#copy()
*/
@Override
public FsIterator_aggregation_common<T> copy() {
return new FsIterator_aggregation_common<T>(this);
}
@Override
public String toString() {
// Type type = this.ll_getIndex().getType();
StringBuilder sb = new StringBuilder(this.getClass().getSimpleName()).append(":").append(System.identityHashCode(this));
if (nonEmptyIterators.length == 0) {
sb.append(" empty iterator");
return sb.toString();
}
sb.append( (main_idx == null && nonEmptyIterators.length > 1)
? " over multiple Types: "
: " over type: ");
if (main_idx == null) {
if (nonEmptyIterators.length > 1) {
sb.append('[');
for (FSIterator<T> it : nonEmptyIterators) {
Type type = ((LowLevelIterator<T>)it).ll_getIndex().getType();
sb.append(type.getName()).append(':').append(((TypeImpl)type).getCode()).append(' ');
}
sb.append(']');
} else {
Type type = ((LowLevelIterator<T>)nonEmptyIterators[0]).ll_getIndex().getType();
sb.append(type.getName()).append(':').append(((TypeImpl)type).getCode()).append(' ');
}
} else {
Type type = main_idx.getType();
sb.append(type.getName()).append(':').append(((TypeImpl)type).getCode()).append(' ');
}
sb.append(", iterator size (may not match current index size): ").append(this.ll_indexSizeMaybeNotCurrent());
return sb.toString();
}
@Override
public Comparator<TOP> getComparator() {
return null; // This style is unordered
}
}