You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@uima.apache.org by sc...@apache.org on 2015/05/13 21:25:21 UTC
svn commit: r1679263 - in /uima/uimaj/trunk/uimaj-core/src:
main/java/org/apache/uima/cas/impl/ test/java/org/apache/uima/cas/test/
Author: schor
Date: Wed May 13 19:25:21 2015
New Revision: 1679263
URL: http://svn.apache.org/r1679263
Log:
[UIMA-4392][UIMA-4391][UIMA-4393] subiterator fixes and improvements
Modified:
uima/uimaj/trunk/uimaj-core/src/main/java/org/apache/uima/cas/impl/AnnotationIndexImpl.java
uima/uimaj/trunk/uimaj-core/src/main/java/org/apache/uima/cas/impl/FSIndexFlat.java
uima/uimaj/trunk/uimaj-core/src/main/java/org/apache/uima/cas/impl/FSIteratorAggregate.java
uima/uimaj/trunk/uimaj-core/src/main/java/org/apache/uima/cas/impl/FSIteratorImplBase.java
uima/uimaj/trunk/uimaj-core/src/main/java/org/apache/uima/cas/impl/FSIteratorWrapper.java
uima/uimaj/trunk/uimaj-core/src/main/java/org/apache/uima/cas/impl/FSIteratorWrapperDoubleCheck.java
uima/uimaj/trunk/uimaj-core/src/main/java/org/apache/uima/cas/impl/FilteredIterator.java
uima/uimaj/trunk/uimaj-core/src/main/java/org/apache/uima/cas/impl/Subiterator.java
uima/uimaj/trunk/uimaj-core/src/test/java/org/apache/uima/cas/test/AnnotationIteratorTest.java
Modified: uima/uimaj/trunk/uimaj-core/src/main/java/org/apache/uima/cas/impl/AnnotationIndexImpl.java
URL: http://svn.apache.org/viewvc/uima/uimaj/trunk/uimaj-core/src/main/java/org/apache/uima/cas/impl/AnnotationIndexImpl.java?rev=1679263&r1=1679262&r2=1679263&view=diff
==============================================================================
--- uima/uimaj/trunk/uimaj-core/src/main/java/org/apache/uima/cas/impl/AnnotationIndexImpl.java (original)
+++ uima/uimaj/trunk/uimaj-core/src/main/java/org/apache/uima/cas/impl/AnnotationIndexImpl.java Wed May 13 19:25:21 2015
@@ -34,7 +34,7 @@ import org.apache.uima.cas.text.Annotati
* customization for additional fns and
* a ref to it's enclosing instance of the FSIndexRepositoryImpl.
*/
-public class AnnotationIndexImpl<T extends AnnotationFS> implements AnnotationIndex<T> {
+public class AnnotationIndexImpl <T extends AnnotationFS> implements AnnotationIndex<T> {
private FSIndex<T> index;
@@ -134,7 +134,10 @@ public class AnnotationIndexImpl<T exten
if (ambiguous) {
return (FSIterator<T>) this.index.iterator();
}
- return new Subiterator<T>((FSIterator<T>) this.index.iterator());
+ // return non-constrained, non-strict, unambiguous iterator
+ boolean strict = true;
+ boolean isBounded = false;
+ return new Subiterator<T>(this.index.iterator(), null, 0, 0, ambiguous, strict, isBounded, ((FSIndexRepositoryImpl.IndexImpl<T>)(this.index)).getFsRepositoryImpl());
}
/*
@@ -155,7 +158,8 @@ public class AnnotationIndexImpl<T exten
*/
@Override
public FSIterator<T> subiterator(AnnotationFS annot, boolean ambiguous, boolean strict) {
- return new Subiterator<T>((FSIterator<T>)this.index.iterator(), annot, ambiguous, strict);
+ boolean isBounded = true;
+ return new Subiterator<T>(this.index.iterator(), annot, 0, 0, ambiguous, strict, isBounded, ((FSIndexRepositoryImpl.IndexImpl<T>)(this.index)).getFsRepositoryImpl());
}
/*
Modified: uima/uimaj/trunk/uimaj-core/src/main/java/org/apache/uima/cas/impl/FSIndexFlat.java
URL: http://svn.apache.org/viewvc/uima/uimaj/trunk/uimaj-core/src/main/java/org/apache/uima/cas/impl/FSIndexFlat.java?rev=1679263&r1=1679262&r2=1679263&view=diff
==============================================================================
--- uima/uimaj/trunk/uimaj-core/src/main/java/org/apache/uima/cas/impl/FSIndexFlat.java (original)
+++ uima/uimaj/trunk/uimaj-core/src/main/java/org/apache/uima/cas/impl/FSIndexFlat.java Wed May 13 19:25:21 2015
@@ -20,6 +20,7 @@ package org.apache.uima.cas.impl;
import java.lang.ref.SoftReference;
import java.util.Arrays;
+import java.util.Comparator;
import java.util.ConcurrentModificationException;
import java.util.NoSuchElementException;
import java.util.concurrent.atomic.AtomicBoolean;
@@ -29,6 +30,7 @@ import java.util.concurrent.atomic.Atomi
import org.apache.uima.cas.FSIterator;
import org.apache.uima.cas.FeatureStructure;
import org.apache.uima.cas.impl.FSIndexRepositoryImpl.IndexIteratorCachePair;
+import org.apache.uima.cas.text.AnnotationFS;
import org.apache.uima.internal.util.Int2IntArrayMapFixedSize;
import org.apache.uima.jcas.cas.TOP;
@@ -107,6 +109,7 @@ public class FSIndexFlat<T extends Featu
* The class can't be static - makes ref to "T" invalid
******************************************** */
public static class FSIteratorFlat<TI extends FeatureStructure> extends FSIteratorImplBase<TI> implements LowLevelIterator {
+
/**
* iterator's Feature Structure array, points to the instance
* in existence when the iterator was created, from the FSIndex
@@ -155,10 +158,10 @@ public class FSIndexFlat<T extends Featu
@Override
public TI get() throws NoSuchElementException {
- if (!hasNext()) {
+ if (!isValid()) {
throw new NoSuchElementException();
}
- final TI fs = ifsa[pos];
+ final TI fs = (TI) ifsa[pos];
final int typeCode = ((FeatureStructureImpl)fs).getTypeCode();
if (debugTypeCodeUnstable) {
if ((fs instanceof TOP) && // insures jcas in use
@@ -205,15 +208,27 @@ public class FSIndexFlat<T extends Featu
@Override
public void moveTo(FeatureStructure fs) {
- final FSLeafIndexImpl<TI> li = iicp.getFsLeafIndex();
- @SuppressWarnings("unchecked")
- final TI fsTI = (TI)fs;
- pos = Arrays.binarySearch(ifsa, fsTI, li);
+ moveToCommon((Comparator<TI>) iicp.getFsLeafIndex(), (TI)fs);
+ }
+
+ /*
+ * Version for subiterator where begin and end are specified without an FS
+ * (non-Javadoc)
+ * @see org.apache.uima.cas.impl.FSIteratorImplBase#moveTo(java.util.Comparator)
+ */
+ @Override
+ void moveTo(int begin, int end) {
+ moveToCommon((Comparator<TI>) (Subiterator.getAnnotationBeginEndComparator(begin, end)), null);
+ }
+
+ //The comparator may embed the compare values, and in that case, fs may be null
+ private void moveToCommon(Comparator<TI> comparator, TI fs) {
+ pos = Arrays.binarySearch(ifsa, fs, comparator);
if (pos < 0) {
pos = (-pos) - 1;
return;
}
- if (!hasNext()) {
+ if (!isValid()) {
return;
}
TI foundFs = get();
@@ -221,15 +236,15 @@ public class FSIndexFlat<T extends Featu
while (true) {
moveToPrevious();
if (isValid()) {
- if (li.compare(get(), foundFs) != 0) {
- moveToNext(); // go back
+ if (comparator.compare(get(), foundFs) != 0) {
+ moveToNext(); // go forwards back to the last valid one
break;
}
} else {
moveToFirst(); // went to before first, so go back to 1st
break;
}
- }
+ }
}
@Override
@@ -275,6 +290,28 @@ public class FSIndexFlat<T extends Featu
public LowLevelIndex ll_getIndex() {
throw new UnsupportedOperationException();
}
+
+ /* (non-Javadoc)
+ * @see org.apache.uima.cas.impl.FSIteratorImplBase#getBegin()
+ */
+ @Override
+ int getBegin() {
+ // all callers validate position before call
+ final AnnotationFS fs = (AnnotationFS) ifsa[pos];
+ return fs.getBegin();
+ }
+
+ /* (non-Javadoc)
+ * @see org.apache.uima.cas.impl.FSIteratorImplBase#getEnd()
+ */
+ @Override
+ int getEnd() {
+ // all callers validate position before call
+ final AnnotationFS fs = (AnnotationFS) ifsa[pos];
+ return fs.getEnd();
+ }
+
+
}
/**
Modified: uima/uimaj/trunk/uimaj-core/src/main/java/org/apache/uima/cas/impl/FSIteratorAggregate.java
URL: http://svn.apache.org/viewvc/uima/uimaj/trunk/uimaj-core/src/main/java/org/apache/uima/cas/impl/FSIteratorAggregate.java?rev=1679263&r1=1679262&r2=1679263&view=diff
==============================================================================
--- uima/uimaj/trunk/uimaj-core/src/main/java/org/apache/uima/cas/impl/FSIteratorAggregate.java (original)
+++ uima/uimaj/trunk/uimaj-core/src/main/java/org/apache/uima/cas/impl/FSIteratorAggregate.java Wed May 13 19:25:21 2015
@@ -21,11 +21,13 @@ package org.apache.uima.cas.impl;
import java.util.ArrayList;
import java.util.Collection;
+import java.util.Comparator;
import java.util.List;
import java.util.NoSuchElementException;
import org.apache.uima.cas.FSIterator;
import org.apache.uima.cas.FeatureStructure;
+import org.apache.uima.cas.text.AnnotationFS;
/**
* Aggregate several FS iterators. Simply iterates over one after the other, no sorting or merging
@@ -39,7 +41,7 @@ class FSIteratorAggregate<T extends Feat
// Internal contract for this class is that isValid() iff the current iterator isValid().
// A list of iterators, unordered.
- private final List<FSIterator<T>> iterators;
+ private final List<FSIteratorImplBase<T>> iterators;
// The offset of the current index.
private int iteratorIndex = 0;
@@ -48,9 +50,9 @@ class FSIteratorAggregate<T extends Feat
* The one and only constructor.
* @param c Collection of input iterators.
*/
- public FSIteratorAggregate(Collection<FSIterator<T>> c) {
+ public FSIteratorAggregate(Collection<FSIteratorImplBase<T>> c) {
super();
- this.iterators = new ArrayList<FSIterator<T>>();
+ this.iterators = new ArrayList<FSIteratorImplBase<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).
@@ -58,9 +60,9 @@ class FSIteratorAggregate<T extends Feat
}
public FSIterator<T> copy() {
- ArrayList<FSIterator<T>> itCopies = new ArrayList<FSIterator<T>>(this.iterators.size());
+ ArrayList<FSIteratorImplBase<T>> itCopies = new ArrayList<FSIteratorImplBase<T>>(this.iterators.size());
for (int i = 0; i < this.iterators.size(); i++) {
- itCopies.add(this.iterators.get(i).copy());
+ itCopies.add((FSIteratorImplBase<T>) this.iterators.get(i).copy());
}
FSIteratorAggregate<T> copy = new FSIteratorAggregate<T>(itCopies);
copy.iteratorIndex = this.iteratorIndex;
@@ -162,4 +164,24 @@ class FSIteratorAggregate<T extends Feat
this.iteratorIndex = this.iterators.size();
}
+ @Override
+ int getBegin() {
+ return this.iterators.get(this.iteratorIndex).getBegin();
+ }
+
+ @Override
+ int getEnd() {
+ // TODO Auto-generated method stub
+ return super.getEnd();
+ }
+
+ /* (non-Javadoc)
+ * @see org.apache.uima.cas.impl.FSIteratorImplBase#moveTo(java.util.Comparator)
+ */
+ @Override
+ <TT extends AnnotationFS> void moveTo(int begin, int end) {
+ throw new UnsupportedOperationException();
+ }
+
+
}
Modified: uima/uimaj/trunk/uimaj-core/src/main/java/org/apache/uima/cas/impl/FSIteratorImplBase.java
URL: http://svn.apache.org/viewvc/uima/uimaj/trunk/uimaj-core/src/main/java/org/apache/uima/cas/impl/FSIteratorImplBase.java?rev=1679263&r1=1679262&r2=1679263&view=diff
==============================================================================
--- uima/uimaj/trunk/uimaj-core/src/main/java/org/apache/uima/cas/impl/FSIteratorImplBase.java (original)
+++ uima/uimaj/trunk/uimaj-core/src/main/java/org/apache/uima/cas/impl/FSIteratorImplBase.java Wed May 13 19:25:21 2015
@@ -19,8 +19,11 @@
package org.apache.uima.cas.impl;
+import java.util.Comparator;
+
import org.apache.uima.cas.FSIterator;
import org.apache.uima.cas.FeatureStructure;
+import org.apache.uima.cas.text.AnnotationFS;
/**
* Base class for FSIterator implementations. Defines the hasNext, next, and remove methods required
@@ -73,4 +76,23 @@ public abstract class FSIteratorImplBase
public void remove() {
throw new UnsupportedOperationException();
}
+
+ // methods to be overridden that can speed up this operation
+ int getBegin() {
+ return ((AnnotationFS)get()).getBegin();
+ }
+
+ int getEnd() {
+ return ((AnnotationFS)get()).getEnd();
+ }
+
+ /**
+ * A special version of moveTo for subtypes of AnnotationFS, which moves to a particular begin/end
+ * (no type priority).
+ * @param begin the starting point (inclusive)
+ * @param end the ending point (inclusive)
+ */
+ <TT extends AnnotationFS> void moveTo(int begin, int end) {
+ throw new UnsupportedOperationException();
+ }
}
Modified: uima/uimaj/trunk/uimaj-core/src/main/java/org/apache/uima/cas/impl/FSIteratorWrapper.java
URL: http://svn.apache.org/viewvc/uima/uimaj/trunk/uimaj-core/src/main/java/org/apache/uima/cas/impl/FSIteratorWrapper.java?rev=1679263&r1=1679262&r2=1679263&view=diff
==============================================================================
--- uima/uimaj/trunk/uimaj-core/src/main/java/org/apache/uima/cas/impl/FSIteratorWrapper.java (original)
+++ uima/uimaj/trunk/uimaj-core/src/main/java/org/apache/uima/cas/impl/FSIteratorWrapper.java Wed May 13 19:25:21 2015
@@ -19,8 +19,11 @@
package org.apache.uima.cas.impl;
+import java.util.Comparator;
+
import org.apache.uima.cas.FSIterator;
import org.apache.uima.cas.FeatureStructure;
+import org.apache.uima.cas.text.AnnotationFS;
import org.apache.uima.internal.util.IntPointerIterator;
public class FSIteratorWrapper<T extends FeatureStructure> extends FSIteratorImplBase<T> {
@@ -33,10 +36,17 @@ public class FSIteratorWrapper<T extends
IntPointerIterator it;
CASImpl casImpl;
+
+ final int beginOffset;
+ final int endOffset;
+
FSIteratorWrapper(IntPointerIterator it, CASImpl casImpl) {
this.it = it;
this.casImpl = casImpl;
+ TypeSystemImpl tsi = casImpl.getTypeSystemImpl();
+ beginOffset = casImpl.getFeatureOffset(tsi.startFeatCode);
+ endOffset = casImpl.getFeatureOffset(tsi.endFeatCode);
}
/**
@@ -95,4 +105,21 @@ public class FSIteratorWrapper<T extends
this.it.moveTo(((FeatureStructureImpl) fs).getAddress());
}
+ @Override
+ int getBegin() {
+ return casImpl.getHeapValue(it.get() + beginOffset);
+ }
+
+ @Override
+ int getEnd() {
+ return casImpl.getHeapValue(it.get() + endOffset);
+ }
+
+ @Override
+ <TT extends AnnotationFS> void moveTo(int begin, int end) {
+ ((FSIteratorImplBase<TT>)it).moveTo(begin, end);
+ }
+
+
+
}
Modified: uima/uimaj/trunk/uimaj-core/src/main/java/org/apache/uima/cas/impl/FSIteratorWrapperDoubleCheck.java
URL: http://svn.apache.org/viewvc/uima/uimaj/trunk/uimaj-core/src/main/java/org/apache/uima/cas/impl/FSIteratorWrapperDoubleCheck.java?rev=1679263&r1=1679262&r2=1679263&view=diff
==============================================================================
--- uima/uimaj/trunk/uimaj-core/src/main/java/org/apache/uima/cas/impl/FSIteratorWrapperDoubleCheck.java (original)
+++ uima/uimaj/trunk/uimaj-core/src/main/java/org/apache/uima/cas/impl/FSIteratorWrapperDoubleCheck.java Wed May 13 19:25:21 2015
@@ -19,9 +19,12 @@
package org.apache.uima.cas.impl;
+import java.util.Comparator;
+
import org.apache.uima.cas.FSIterator;
import org.apache.uima.cas.FeatureStructure;
import org.apache.uima.cas.impl.FSIndexFlat.FSIteratorFlat;
+import org.apache.uima.cas.text.AnnotationFS;
/**
* Only used for debugging
@@ -31,6 +34,7 @@ import org.apache.uima.cas.impl.FSIndexF
*/
public class FSIteratorWrapperDoubleCheck<T extends FeatureStructure> extends FSIteratorImplBase<T> {
+
@Override
public String toString() {
return "FSIteratorWrapper [it=" + nonFlatIterator + "]";
@@ -134,6 +138,16 @@ public class FSIteratorWrapperDoubleChec
this.nonFlatIterator.moveTo(fs);
this.flatIterator.moveTo(fs);
}
+
+ /* (non-Javadoc)
+ * @see org.apache.uima.cas.impl.FSIteratorImplBase#moveTo(java.util.Comparator)
+ */
+ @Override
+ <TT extends AnnotationFS> void moveTo(int begin, int end) {
+ ((FSIteratorImplBase<TT>)(this.nonFlatIterator)).moveTo(begin, end);
+ this.flatIterator.moveTo(begin, end);
+ }
+
private void error(String msg) {
msg = flatIterator.verifyFsaSubsumes() + msg;
Modified: uima/uimaj/trunk/uimaj-core/src/main/java/org/apache/uima/cas/impl/FilteredIterator.java
URL: http://svn.apache.org/viewvc/uima/uimaj/trunk/uimaj-core/src/main/java/org/apache/uima/cas/impl/FilteredIterator.java?rev=1679263&r1=1679262&r2=1679263&view=diff
==============================================================================
--- uima/uimaj/trunk/uimaj-core/src/main/java/org/apache/uima/cas/impl/FilteredIterator.java (original)
+++ uima/uimaj/trunk/uimaj-core/src/main/java/org/apache/uima/cas/impl/FilteredIterator.java Wed May 13 19:25:21 2015
@@ -19,11 +19,13 @@
package org.apache.uima.cas.impl;
+import java.util.Comparator;
import java.util.NoSuchElementException;
import org.apache.uima.cas.FSIterator;
import org.apache.uima.cas.FSMatchConstraint;
import org.apache.uima.cas.FeatureStructure;
+import org.apache.uima.cas.text.AnnotationFS;
/**
* Implements a filtered iterator.
@@ -58,34 +60,40 @@ class FilteredIterator<T extends Feature
// can simply refer to the underlying iterator.
return this.it.isValid();
}
-
- public void moveToFirst() {
- this.it.moveToFirst();
+
+ private void adjustForConstraintForward() {
// If the iterator is valid, but doesn't match the constraint, advance.
while (this.it.isValid() && !this.cons.match(this.it.get())) {
this.it.moveToNext();
- }
+ }
+ }
+
+ private void adjustForConstraintBackward() {
+ // If the iterator is valid, but doesn't match the constraint, advance.
+ while (this.it.isValid() && !this.cons.match(this.it.get())) {
+ this.it.moveToPrevious();
+ }
+ }
+
+
+ public void moveToFirst() {
+ this.it.moveToFirst();
+ adjustForConstraintForward();
}
public void moveToLast() {
this.it.moveToLast();
- while (this.it.isValid() && !this.cons.match(this.it.get())) {
- this.it.moveToPrevious();
- }
+ adjustForConstraintBackward();
}
public void moveToNext() {
this.it.moveToNext();
- while (this.it.isValid() && !this.cons.match(this.it.get())) {
- this.it.moveToNext();
- }
+ adjustForConstraintForward();
}
public void moveToPrevious() {
this.it.moveToPrevious();
- while (this.it.isValid() && !this.cons.match(this.it.get())) {
- this.it.moveToPrevious();
- }
+ adjustForConstraintBackward();
}
public T get() throws NoSuchElementException {
@@ -105,9 +113,15 @@ class FilteredIterator<T extends Feature
*/
public void moveTo(FeatureStructure fs) {
this.it.moveTo(fs);
- if (!this.cons.match(this.it.get())) {
- moveToNext();
- }
+ adjustForConstraintForward();
}
+ /* (non-Javadoc)
+ * @see org.apache.uima.cas.impl.FSIteratorImplBase#moveTo(java.util.Comparator)
+ */
+ @Override
+ <TT extends AnnotationFS> void moveTo(int begin, int end) {
+ ((FSIteratorImplBase<T>)(this.it)).moveTo(begin, end);
+ adjustForConstraintForward();
+ }
}
Modified: uima/uimaj/trunk/uimaj-core/src/main/java/org/apache/uima/cas/impl/Subiterator.java
URL: http://svn.apache.org/viewvc/uima/uimaj/trunk/uimaj-core/src/main/java/org/apache/uima/cas/impl/Subiterator.java?rev=1679263&r1=1679262&r2=1679263&view=diff
==============================================================================
--- uima/uimaj/trunk/uimaj-core/src/main/java/org/apache/uima/cas/impl/Subiterator.java (original)
+++ uima/uimaj/trunk/uimaj-core/src/main/java/org/apache/uima/cas/impl/Subiterator.java Wed May 13 19:25:21 2015
@@ -30,148 +30,242 @@ import org.apache.uima.cas.text.Annotati
/**
* Subiterator implementation.
+ *
+ * There are two bounding styles and 2 underlying forms.
+ *
+ * The 2nd form is produced lazily when needed, and
+ * is made by a one-time forward traversal to compute unambigious subsets and store them into a list.
+ * - The 2nd form is needed only for unambiguous style if backwards or moveto(fs) operation.
+ *
+ * The 1st form uses the underlying iterator directly, and does skipping as needed, while iterating
+ * - going forward:
+ * skip if unambigious and start is within prev span
+ * skip if strict and end lies outside of scope span
+ *
+ * - going backward:
+ * if unambiguous - convert to form 2
+ * skip if strict and end lies outside of scope span
+ *
+ * - going to particular fs (left most match)
+ * if unambiguous - convert to form 2
+ * skip (forward) if strict and end lies outside of scope span
+ *
+ * - going to first:
+ * unambiguous - no testing needed, no prior span
+ * skip if strict and end lies outside of scope span
+ *
+ * - going to last:
+ * unambigious - convert to 2nd form
+ * skip backwards if strict and end lies outside of scope span
+ *
+ * There are two styles of the bounding information.
+ *
+ * - the traditional one uses the standard comparator for annotations: begin (ascending), end (descending) and
+ * type priority ordering
+ * - the 2nd style uses just a begin value and an end value, no type priority ordering.
*/
public class Subiterator<T extends AnnotationFS> extends FSIteratorImplBase<T> {
- final private ArrayList<T> list;
+ private ArrayList<T> list = null; // used for form 2, lazily initialized
- private int pos;
+ private int pos = 0; // used for form 2
+
+ private final FSIteratorImplBase<T> it;
- private Comparator<AnnotationFS> annotationComparator = null;
+ private final FSIndexRepositoryImpl fsIndexRepo;
+
+ private final AnnotationFS boundingAnnotation; // the bounding annotation need not be a subtype of T
+
+ private final int boundingBegin;
+ private final int boundingEnd;
+ private int prevEnd = 0; // for unambiguous iterators
+ private final boolean ambiguous;
+ private final boolean strict;
+ private final boolean isBounded;
+ private boolean isListForm = false;
+ private final boolean isBeginEndCompare;
- private Subiterator() {
- super();
- this.list = new ArrayList<T>();
- this.pos = 0;
- }
- private Subiterator(ArrayList<T> list) {
+ /**
+ * Constructor called with annot == null and boundingBegin and boundingEnd specified, or
+ * called with annot != null (boundingBegin/End ignored)
+ *
+ * if annot == null, then this implies the comparisons should use just begin and end (not type priorities) and
+ * the range is inclusive with the begin/ end boundaries
+ * != null, then this implies the comparisons use the normal Annotation compare and
+ * the range is exclusive on the left with the boundaries.
+ * @param it the iterator to use
+ * @param boundingAnnotation null or the bounding annotation
+ * @param boundingBegin if boundingAnnotation is null, this is used as the bounding begin (inclusive);
+ * ignored if boundingAnnotation is not null
+ * @param boundingEnd if annot is null, this is used as the bounding end (inclusive);
+ * ignored if boundingAnnotation is not null
+ * @param ambiguous true means normal iteration,
+ * false means to skip annotations whose begin lies between previous begin (inclusive) and end (exclusive)
+ * @param strict true means to skip annotations whose end is greater than the bounding end position (ignoring type priorities)
+ * @param isBounded false means its an unambiguous iterator with no bounds narrowing; ambiguous taken to be false
+ * @param fsIndexRepo the index repository for this iterator
+ */
+ Subiterator(
+ FSIterator<T> it,
+ AnnotationFS boundingAnnotation,
+ int boundingBegin,
+ int boundingEnd,
+ boolean ambiguous,
+ boolean strict,
+ boolean isBounded,
+ FSIndexRepositoryImpl fsIndexRepo
+ ) {
super();
- this.list = list;
- this.pos = 0;
+ this.isBounded = isBounded;
+ // non bounded iterators don't use any begin/end compares
+ this.isBeginEndCompare = this.isBounded ? (boundingAnnotation == null) : false;
+ this.it = (FSIteratorImplBase<T>) it;
+ this.boundingAnnotation = this.isBounded ? boundingAnnotation : null;
+ this.boundingBegin = (boundingAnnotation == null) ? boundingBegin : boundingAnnotation.getBegin();
+ this.boundingEnd = (boundingAnnotation == null) ? boundingEnd : boundingAnnotation.getEnd();
+ this.ambiguous = ambiguous;
+ this.strict = strict;
+ this.fsIndexRepo = fsIndexRepo;
+
+ moveToStart();
}
-
+
+
/**
- * Create a disambiguated iterator. No concurrent modification exception checking is done.
+ * Converting to list form - called for
+ * unambiguous iterator going backwards,
+ * unambiguous iterator doing a moveTo(fs) operation
+ * iterator doing a moveToLast() operation
*
- * @param it
- * The iterator to be disambiguated.
*/
- Subiterator(FSIterator<T> it) {
- this();
- it.moveToFirst();
- if (!it.isValid()) {
- return;
- }
- T current, next;
- current = it.get();
- this.list.add(current);
- it.moveToNext();
- while (it.isValid()) {
- next = it.get();
- if (current.getEnd() <= next.getBegin()) {
- current = next;
- this.list.add(current);
- }
+ private void convertToListForm() {
+ moveToStart(); // moves to the start annotation, including moving past equals for annot style, and accomodating strict
+ this.list = new ArrayList<T>();
+ while (isValid()) {
+ prevEnd = it.getEnd();
+ list.add(it.get());
it.moveToNext();
- }
+ movePastPrevAnnotation();
+ adjustForStrictForward();
+ }
+ isListForm = true; // do at end, so up to this point, iterator is not the list form style
}
-
- Subiterator(FSIterator<T> it, AnnotationFS annot, final boolean ambiguous, final boolean strict) {
- this();
- if (ambiguous) {
-
- initAmbiguousSubiterator(it, annot, strict);
- } else {
- initUnambiguousSubiterator(it, annot, strict);
- }
- }
-
- // makes an extra copy of the items
- private void initAmbiguousSubiterator(FSIterator<T> it, AnnotationFS annot, final boolean strict) {
- final int start = annot.getBegin();
- final int end = annot.getEnd();
- it.moveTo(annot); // to "earliest" equal, or if none are equal, to the one just later than annot
-
- // This is a little silly, it skips 1 of possibly many indexed annotations if the earliest one is "equal"
- // (just means matching the keys) to the control annot 4/2015
- if (it.isValid() && it.get().equals(annot)) {
- it.moveToNext();
- }
- // Skip annotations whose start is before the start parameter.
- // should never have any???
- while (it.isValid() && it.get().getBegin() < start) {
- it.moveToNext();
- }
- T current;
- while (it.isValid()) {
- current = it.get();
- // If the start of the current annotation is past the end parameter,
- // we're done.
- if (current.getBegin() > end) {
+ private void moveToExact(FeatureStructureImpl targetAnnotation) {
+ it.moveTo(targetAnnotation); // move to left-most equal one
+ while (it.isValid()) { // advance to the exact equal one
+ if (targetAnnotation.getAddress() == ((FeatureStructureImpl)(it.get())).getAddress()) {
break;
}
it.moveToNext();
- if (strict && current.getEnd() > end) {
- continue;
- }
- this.list.add(current);
}
}
-
- private void initUnambiguousSubiterator(FSIterator<T> it, AnnotationFS annot, final boolean strict) {
- final int start = annot.getBegin();
- final int end = annot.getEnd();
- it.moveTo(annot);
+ /**
+ * Move to the starting position of the sub iterator
+ * Annotation bounding: move to the annotation, then move forwards until you're at an element not equal to the annot.
+ * (by definition of the iterator)
+ * and adjust for strict
+ */
+ private void moveToStart() {
+ if (!isBounded) {
+ it.moveToFirst();
+ } else if (isBeginEndCompare) {
+ it.moveTo(this.boundingBegin, this.boundingEnd);
+ } else { // is annotation bounding
+ it.moveTo(boundingAnnotation);
+ movePastAnnot(); // only for the annot style, the range is exclusive by definition
+ }
- if (it.isValid() && it.get().equals(annot)) {
+ adjustForStrictForward();
+ setPrevEnd();
+ }
+
+ private void setPrevEnd() {
+ if (!ambiguous && it.isValid()) {
+ this.prevEnd = it.getEnd();
+ }
+ }
+
+ /**
+ * For subiterators bounded by Annotations, the starting place is the
+ * item past the elements that are equal to the the bounding annot,
+ * adjusted for strict exclusions
+ */
+ private void movePastAnnot() {
+ Comparator<AnnotationFS> annotationComparator = getAnnotationComparator();
+ while (isValid() && (0 == annotationComparator.compare(boundingAnnotation, it.get()))) {
it.moveToNext();
}
- if (!it.isValid()) {
- return;
- }
- annot = it.get();
- // Skip annotations with begin positions before the given start
- // position.
- while (it.isValid() && ((start > annot.getBegin()) || (strict && annot.getEnd() > end))) {
- it.moveToNext();
+ }
+
+ private Comparator<AnnotationFS> getAnnotationComparator() {
+ return fsIndexRepo.getAnnotationFsComparator();
+ }
+
+ /**
+ * Called for begin/end compare, after moveTo(fs)
+ * to eliminate the effect of the type order comparison before any adjustment for strict.
+ * Move backwards while equal with begin/end iterator.
+ */
+ private void adjustAfterMoveToForBeginEndComparator(AnnotationFS fs) {
+ final int begin = fs.getBegin();
+ final int end = fs.getEnd();
+
+ while (it.isValid() && (it.getBegin() == begin) && (it.getEnd() == end)) {
+ it.moveToPrevious();
}
- // Add annotations.
- if (!it.isValid()) {
- return;
+ // are one position too far, move back one
+ if (it.isValid()) {
+ it.moveToNext();
+ } else {
+ moveToStart();
}
- T current = null;
- while (it.isValid()) {
- final T next = it.get();
- // If the next annotation overlaps, skip it. Don't check while there is no "current" yet.
- if ((current != null) && (next.getBegin() < current.getEnd())) {
+ }
+
+ /**
+ * For strict mode, advance iterator until the end is within the bounding end
+ */
+ private void adjustForStrictForward() {
+ if (strict && isBounded) {
+ while (it.isValid() && (it.getEnd() > this.boundingEnd)) {
it.moveToNext();
- continue;
}
- // If we're past the end, stop.
- if (next.getBegin() > end) {
- break;
+ }
+ }
+
+ /**
+ * For unambiguous, going forwards
+ */
+ private void movePastPrevAnnotation() {
+ if (!ambiguous) {
+ while (it.isValid() && (it.getBegin() < this.prevEnd)) {
+ it.moveToNext();
}
- // We have an annotation that's within the boundaries and doesn't
- // overlap
- // with the previous annotation. We add this annotation if we're not
- // strict, or the end position is within the limits.
- if (!strict || next.getEnd() <= end) {
- current = next;
- this.list.add(current);
+ }
+ }
+
+ private void adjustForStrictBackward() {
+ if (strict && isBounded) {
+ while (it.isValid() && (it.getEnd() > this.boundingEnd)) {
+ it.moveToPrevious();
}
- it.moveToNext();
}
}
-
+
/*
* (non-Javadoc)
*
* @see org.apache.uima.cas.FSIterator#isValid()
*/
public boolean isValid() {
- return (this.pos >= 0) && (this.pos < this.list.size());
+ return isListForm ?
+ (this.pos >= 0) && (this.pos < this.list.size()) :
+
+ // assume that it position is adjusted for strict and unambiguous already
+ (it.isValid() &&
+ ( isBounded? (it.getBegin() <= this.boundingEnd) :
+ true));
}
/*
@@ -180,8 +274,14 @@ public class Subiterator<T extends Annot
* @see org.apache.uima.cas.FSIterator#get()
*/
public T get() throws NoSuchElementException {
- if (isValid()) {
- return this.list.get(this.pos);
+ if (isListForm) {
+ if ((this.pos >= 0) && (this.pos < this.list.size())) {
+ return this.list.get(this.pos);
+ }
+ } else {
+ if (isValid()) {
+ return it.get();
+ }
}
throw new NoSuchElementException();
}
@@ -192,7 +292,20 @@ public class Subiterator<T extends Annot
* @see org.apache.uima.cas.FSIterator#moveToNext()
*/
public void moveToNext() {
- ++this.pos;
+ if (isListForm) {
+ ++this.pos;
+ // setPrevEnd not needed because list form already accounted for unambiguous
+ return;
+ }
+
+ it.moveToNext();
+
+ if (!ambiguous) {
+ movePastPrevAnnotation();
+ }
+
+ adjustForStrictForward();
+ setPrevEnd();
}
/*
@@ -201,7 +314,22 @@ public class Subiterator<T extends Annot
* @see org.apache.uima.cas.FSIterator#moveToPrevious()
*/
public void moveToPrevious() {
- --this.pos;
+ if (isListForm) {
+ --this.pos;
+ return;
+ }
+
+ if (!ambiguous) {
+ // Convert to list form
+ FeatureStructureImpl currentAnnotation = (FeatureStructureImpl) it.get(); // save to restore position
+ convertToListForm();
+ moveToExact(currentAnnotation);
+ --this.pos;
+ return;
+ }
+
+ it.moveToPrevious();
+ adjustForStrictBackward();
}
/*
@@ -210,24 +338,53 @@ public class Subiterator<T extends Annot
* @see org.apache.uima.cas.FSIterator#moveToFirst()
*/
public void moveToFirst() {
- this.pos = 0;
+ if (isListForm) {
+ this.pos = 0;
+ } else {
+ moveToStart();
+ }
}
/*
- * (non-Javadoc)
+ * This operation is relatively expensive
*
* @see org.apache.uima.cas.FSIterator#moveToLast()
*/
public void moveToLast() {
- this.pos = this.list.size() - 1;
+ if (isListForm) {
+ this.pos = this.list.size() - 1;
+ } else {
+ convertToListForm();
+ this.pos = this.list.size() - 1;
+ }
}
- private final Comparator<AnnotationFS> getAnnotationComparator(FeatureStructure fs) {
- if (this.annotationComparator == null) {
- this.annotationComparator =
- ((FSIndexRepositoryImpl)(fs.getCAS().getIndexRepository())).getAnnotationFsComparator();
- }
- return this.annotationComparator;
+ // default visibility - referred to by flat iterator
+ static Comparator<AnnotationFS> getAnnotationBeginEndComparator(final int boundingBegin, final int boundingEnd) {
+ return new Comparator<AnnotationFS>() {
+
+ @Override
+ public int compare(AnnotationFS o1, AnnotationFS o2) {
+ AnnotationFS a = (o1 == null) ? o2 : o1;
+ boolean isReverse = o1 == null;
+ final int b;
+ if ((b = a.getBegin()) < boundingBegin) {
+ return isReverse? 1 : -1;
+ }
+ if (b > boundingBegin) {
+ return isReverse? -1 : 1;
+ }
+
+ final int e;
+ if ((e = a.getEnd()) < boundingEnd) {
+ return isReverse? -1 : 1;
+ }
+ if (e > boundingEnd) {
+ return isReverse? 1 : -1;
+ }
+ return 0;
+ }
+ };
}
/*
@@ -236,32 +393,103 @@ public class Subiterator<T extends Annot
* @see org.apache.uima.cas.FSIterator#moveTo(org.apache.uima.cas.FeatureStructure)
*/
public void moveTo(FeatureStructure fs) {
- final Comparator<AnnotationFS> comparator = getAnnotationComparator(fs);
- pos = Collections.binarySearch(this.list, (AnnotationFS) fs, comparator);
- if (pos >= 0) {
- if (!isValid()) {
- return;
- }
- T foundFs = get();
- // Go back until we find a FS that is really smaller
- while (true) {
- moveToPrevious();
- if (isValid()) {
- if (comparator.compare(get(), foundFs) != 0) {
- moveToNext(); // go back
- break;
- }
+ AnnotationFS fsa = (AnnotationFS) fs;
+ if (!ambiguous && !isListForm) { // unambiguous must be in list form
+ convertToListForm();
+ }
+ if (isListForm) {
+ Comparator<AnnotationFS> annotationComparator = getAnnotationComparator();
+ pos = Collections.binarySearch(this.list, (AnnotationFS) fs, annotationComparator);
+ if (pos >= 0) {
+ if (!isValid()) {
+ return;
+ }
+ T foundFs = get();
+ // Go back until we find a FS that is really smaller
+ if (isBeginEndCompare) {
+ adjustAfterMoveToForBeginEndComparator(fsa);
} else {
- moveToFirst(); // went to before first, so go back to 1st
- break;
+ while (true) {
+ moveToPrevious();
+ if (isValid()) {
+ if (annotationComparator.compare(get(), foundFs) != 0) {
+ moveToNext(); // backed up too far, so go back
+ break;
+ }
+ } else {
+ moveToFirst(); // went to before first, so go back to 1st
+ break;
+ }
+ }
}
- }
- return;
+ } else {
+ // element wasn't found,
+ //set the position to the next (greater) element in the list or to an invalid position
+ // if no element is greater
+ pos = (-pos) - 1;
+ if (isBeginEndCompare) {
+ pos-- ; // check to see if previous element, unequal with annotation compare, might be equal with begin-end compare
+ adjustAfterMoveToForBeginEndComparator(fsa);
+ }
+ }
} else {
- pos = (-pos) - 1;
- return;
+ // is ambiguous, may be strict, always bounded (either by annotation or begin / end
+ it.moveTo(fs);
+ if (isBeginEndCompare) {
+ it.moveTo(fs);
+ adjustAfterMoveToForBeginEndComparator(fsa);
+ } else { // is begin/end bounding
+ it.moveTo(fs);
+ }
+ adjustForStrictForward();
}
}
+
+ /*
+ * @see org.apache.uima.cas.impl.FSIteratorImplBase#moveTo(java.util.Comparator)
+ */
+ @Override
+ <TT extends AnnotationFS> void moveTo(final int begin, final int end) {
+ if (!ambiguous && !isListForm) { // unambiguous must be in list form
+ convertToListForm();
+ }
+ if (isListForm) {
+ pos = Collections.binarySearch(this.list, null, getAnnotationBeginEndComparator(begin, end));
+ if (pos >= 0) {
+ if (!isValid()) {
+ return;
+ }
+
+ // Go back to leftmost
+ while (it.isValid() && (it.getBegin() == begin) && (it.getEnd() == end)) {
+ it.moveToPrevious();
+ }
+ // are one position too far, move back one
+ if (it.isValid()) {
+ it.moveToNext();
+ } else {
+ it.moveToFirst();
+ }
+ } else {
+ // element wasn't found,
+ //set the position to the next (greater) element in the list or to an invalid position
+ // if no element is greater
+ pos = (-pos) - 1;
+ }
+ } else {
+ // is ambiguous, may be strict, always bounded (either by annotation or begin / end
+ it.moveTo(begin, end);
+ // Go back to leftmost
+ while (isValid() && (it.getBegin() == begin) && (it.getEnd() == end)) {
+ it.moveToPrevious();
+ }
+ adjustForStrictForward();
+ }
+
+
+ }
+
+
/*
* (non-Javadoc)
@@ -269,9 +497,96 @@ public class Subiterator<T extends Annot
* @see org.apache.uima.cas.FSIterator#copy()
*/
public FSIterator<T> copy() {
- Subiterator<T> copy = new Subiterator<T>(this.list);;
- copy.pos = this.pos;
+ Subiterator<T> copy = new Subiterator<T>(
+ this.it, this.boundingAnnotation, this.boundingBegin, this.boundingEnd, this.ambiguous, this.strict, this.isBounded, this.fsIndexRepo);
+ copy.list = this.list; // non-final things
+ copy.pos = this.pos;
return copy;
}
+
+
+
+
+// // makes an extra copy of the items
+// private void initAmbiguousSubiterator(AnnotationFS annot, final boolean strict) {
+// final int start = (annot == null) ? 0 : annot.getBegin();
+// final int boundingEnd = (annot == null) ? Integer.MAX_VALUE : annot.getEnd();
+// if (annot == null) {
+// it.moveToFirst();
+// } else {
+// it.moveTo(annot); // to "earliest" equal, or if none are equal, to the one just later than annot
+// }
+//
+// // This is a little silly, it skips 1 of possibly many indexed annotations if the earliest one is "equal"
+// // (just means matching the keys) to the control annot 4/2015
+// if (it.isValid() && it.get().equals(annot)) {
+// it.moveToNext();
+// }
+// // Skip annotations whose start is before the start parameter.
+// // should never have any???
+// while (it.isValid() && it.getBegin() < start) {
+// it.moveToNext();
+// }
+// T current;
+// while (it.isValid()) {
+// current = it.get();
+// // If the start of the current annotation is past the boundingEnd parameter,
+// // we're done.
+// if (current.getBegin() > boundingEnd) {
+// break;
+// }
+// it.moveToNext();
+// if (strict && current.getEnd() > boundingEnd) {
+// continue;
+// }
+// this.list.add(current);
+// }
+// }
+//
+// private void initUnambiguousSubiterator(AnnotationFS annot, final boolean strict) {
+// final int start = annot.getBegin();
+// final int boundingEnd = annot.getEnd();
+// it.moveTo(annot);
+//
+// if (it.isValid() && it.get().equals(annot)) {
+// it.moveToNext();
+// }
+// if (!it.isValid()) {
+// return;
+// }
+// annot = it.get();
+// // Skip annotations with begin positions before the given start
+// // position.
+// while (it.isValid() && ((start > annot.getBegin()) || (strict && annot.getEnd() > boundingEnd))) {
+// it.moveToNext();
+// }
+// // Add annotations.
+// if (!it.isValid()) {
+// return;
+// }
+// T current = null;
+// while (it.isValid()) {
+// final T next = it.get();
+// // If the next annotation overlaps, skip it. Don't check while there is no "current" yet.
+// if ((current != null) && (next.getBegin() < current.getEnd())) {
+// it.moveToNext();
+// continue;
+// }
+// // If we're past the boundingEnd, stop.
+// if (next.getBegin() > boundingEnd) {
+// break;
+// }
+// // We have an annotation that's within the boundaries and doesn't
+// // overlap
+// // with the previous annotation. We add this annotation if we're not
+// // strict, or the end position is within the limits.
+// if (!strict || next.getEnd() <= boundingEnd) {
+// current = next;
+// this.list.add(current);
+// }
+// it.moveToNext();
+// }
+// }
+
}
Modified: uima/uimaj/trunk/uimaj-core/src/test/java/org/apache/uima/cas/test/AnnotationIteratorTest.java
URL: http://svn.apache.org/viewvc/uima/uimaj/trunk/uimaj-core/src/test/java/org/apache/uima/cas/test/AnnotationIteratorTest.java?rev=1679263&r1=1679262&r2=1679263&view=diff
==============================================================================
--- uima/uimaj/trunk/uimaj-core/src/test/java/org/apache/uima/cas/test/AnnotationIteratorTest.java (original)
+++ uima/uimaj/trunk/uimaj-core/src/test/java/org/apache/uima/cas/test/AnnotationIteratorTest.java Wed May 13 19:25:21 2015
@@ -26,6 +26,7 @@ import junit.framework.TestCase;
import org.apache.uima.cas.CAS;
import org.apache.uima.cas.CASRuntimeException;
+import org.apache.uima.cas.FSIndexRepository;
import org.apache.uima.cas.FSIterator;
import org.apache.uima.cas.Feature;
import org.apache.uima.cas.Type;
@@ -34,12 +35,15 @@ import org.apache.uima.cas.impl.FSIndexF
import org.apache.uima.cas.impl.FSIteratorWrapper;
import org.apache.uima.cas.text.AnnotationFS;
import org.apache.uima.cas.text.AnnotationIndex;
+import org.apache.uima.jcas.tcas.Annotation;
/**
* Class comment for FilteredIteratorTest.java goes here.
*
*/
public class AnnotationIteratorTest extends TestCase {
+
+ private static final boolean showFSs = false;
private CAS cas;
@@ -73,6 +77,14 @@ public class AnnotationIteratorTest exte
private Type sentenceType;
+ private boolean isSave;
+
+ private List<AnnotationFS> fss;
+
+ private List<Integer> fssStarts = new ArrayList<Integer>();
+
+ private int callCount = -1;
+
/**
* Constructor for FilteredIteratorTest.
*
@@ -85,6 +97,7 @@ public class AnnotationIteratorTest exte
@Override
public void setUp() {
try {
+ // make a cas with various types, fairly complex -- see CASTestSetup class
this.cas = CASInitializer.initCas(new CASTestSetup());
assertTrue(this.cas != null);
this.ts = this.cas.getTypeSystem();
@@ -143,9 +156,18 @@ public class AnnotationIteratorTest exte
}
public void testIterator1() {
-
+// Tokens +---+
+// +---+
+// +---+
+// BigBound +-----------------------------+
final String text = "aaaa bbbb cccc dddd aaaa bbbb cccc dddd aaaa bbbb cccc dddd ";
-
+// +--------+
+// Sentences +--------+
+// +----------+
+//
+// bound4strict +------------------+
+// sentence4strict +-----------------------------+
+
try {
this.cas.setDocumentText(text);
} catch (CASRuntimeException e) {
@@ -153,135 +175,172 @@ public class AnnotationIteratorTest exte
}
/***************************************************
- * Create and index tokens an sentences
+ * Create and index tokens and sentences
***************************************************/
+ FSIndexRepository ir = this.cas.getIndexRepository();
int annotCount = 1; // Init with document annotation.
// create token and sentence annotations
for (int i = 0; i < text.length() - 5; i++) {
++annotCount;
- this.cas.getIndexRepository().addFS(this.cas.createAnnotation(this.tokenType, i, i + 5));
+ ir.addFS(this.cas.createAnnotation(this.tokenType, i, i + 5));
}
// for (int i = 0; i < text.length() - 5; i++) {
// cas.getIndexRepository().addFS(cas.createAnnotation(tokenType, i, i+5));
// }
for (int i = 0; i < text.length() - 10; i += 5) {
++annotCount;
- this.cas.getIndexRepository().addFS(this.cas.createAnnotation(this.sentenceType, i, i + 10));
+ ir.addFS(this.cas.createAnnotation(this.sentenceType, i, i + 10));
}
+
+ ++annotCount;
+ ir.addFS(this.cas.createAnnotation(this.sentenceType, 12, 31));
/***************************************************
* iterate over them
***************************************************/
List fss = new ArrayList();
- iterateOverAnnotations(annotCount, fss);
+ callCount = -1;
+ iterateOverAnnotations(annotCount, fss); // annotCount is the total number of sentences and tokens
+ callCount = -1;
iterateOverAnnotations(annotCount, fss); // should be using flattened version
+
+ /***************************************************
+ * test skipping over multiple equal items at front
+ ***************************************************/
+ callCount = -1;
+ fss.clear();
+ isSave = true;
+ AnnotationFS a1, a2;
+ ir.addFS(a1 = this.cas.createAnnotation(this.tokenType, 1, 6));
+ a1.setStringValue(lemmaFeat, "lemma1");
+ ir.addFS(a2 = this.cas.createAnnotation(this.tokenType, 1, 6));
+ a2.setStringValue(lemmaFeat, "lemma2");
+
+ FSIterator<AnnotationFS> it;
+ AnnotationIndex<AnnotationFS> tokenIndex = cas.getAnnotationIndex(tokenType);
+ it = tokenIndex.subiterator(a1);
+ assertCount("multi equal", 0, it);
+
}
-
- private void iterateOverAnnotations(int annotCount, List fss) {
- boolean isSave = fss.size() == 0;
+ /**
+ * The tests include:
+ * a) running with / w/o "flattened" indexes
+ * b) running forwards and backwards (testing moveToLast, isValid)
+ * c) testing strict and unambiguous variants
+ * d) running over all annotations and restricting to just a particular subtype
+ *
+ * new tests:
+ * verifying bounding FS < all returned, including multiples of it
+ * strict at 1st element, at last element
+ * (not done yet) ConcurrentModificationException testing
+ *
+ * (not done yet) Testing with different bound styles
+ *
+ * @param annotCount
+ * @param fss
+ */
+ // called twice, the 2nd time should be with flattened indexes (List fss non empty the 2nd time)
+ private void iterateOverAnnotations(int annotCount, List<AnnotationFS> fss) {
+ this.fss = fss;
+ isSave = fss.size() == 0;
int count;
AnnotationIndex<AnnotationFS> annotIndex = this.cas.getAnnotationIndex();
- FSIterator<AnnotationFS> it = annotIndex.iterator(true);
- assertTrue((isSave) ? it instanceof FSIteratorWrapper : it instanceof FSIndexFlat.FSIteratorFlat);
- count = 0;
+ AnnotationIndex<AnnotationFS> sentIndex = this.cas.getAnnotationIndex(sentenceType);
+ FSIterator<AnnotationFS> it = annotIndex.iterator(true); // a normal "ambiguous" iterator
+ assertTrue((isSave) ? it instanceof FSIteratorWrapper : it instanceof FSIndexFlat.FSIteratorFlat);
+ assertCount("Normal ambiguous annot iterator", annotCount, it);
+
+ it = annotIndex.iterator(false); // false means create an unambiguous iterator
+ assertCount("Unambiguous annot iterator", 1, it); // because of document Annotation
+
+ AnnotationFS bigBound = this.cas.createAnnotation(this.sentenceType, 10, 41);
+ it = annotIndex.subiterator(bigBound, true, true); // ambiguous, and strict
+ assertCount("Subiterator over annot with big bound, strict", 33, it);
+
+ it = annotIndex.subiterator(bigBound, false, true); // unambiguous, strict
+ assertCount("Subiterator over annot unambiguous strict", 3, it);
+
+ it = annotIndex.subiterator(bigBound, true, false);
+ assertCount("Subiterator over annot ambiguous not-strict", 40, it);
+
+ it = annotIndex.subiterator(bigBound, false, false); // unambiguous, not strict
+ assertCount("Subiterator over annot, unambiguous, not-strict", 4, it);
+
+ AnnotationFS sent = this.cas.getAnnotationIndex(this.sentenceType).iterator().get();
+ it = annotIndex.subiterator(sent, false, true);
+ assertCount("Subiterator over annot unambiguous strict", 2, it);
+
+ // strict skips first item
+ bigBound = this.cas.createAnnotation(this.sentenceType, 11, 30);
+ it = sentIndex.subiterator(bigBound, true, true);
+ assertCount("Subiteratover over sent ambiguous strict", 2, it);
+ it = sentIndex.subiterator(bigBound, true, false);
+ assertCount("Subiteratover over sent ambiguous", 5, it);
+ it = sentIndex.subiterator(bigBound, false, false);
+ assertCount("Subiteratover over sent unambiguous", 1, it);
+ }
+
+ private String flatStateMsg(String s) {
+ return s + (isSave ? "" : " with flattened index");
+ }
+
+ private void assertCount(String msg, int expected, FSIterator<AnnotationFS> it) {
+ msg = flatStateMsg(msg);
+ int count = 0;
+ callCount ++;
+ int fssStart;
+ if (isSave) {
+ fssStarts.add(fssStart = fss.size());
+ } else {
+ fssStart = fssStarts.get(callCount);
+ }
while (it.isValid()) {
++count;
AnnotationFS fs = it.next();
+ if (showFSs) {
+ System.out.format("%d " + msg + " fs begin: %d end: %d type: %s%n", count, fs.getBegin(), fs.getEnd(), fs.getType().getName() );
+ }
if (isSave) {
fss.add(fs);
} else {
- assertEquals(fss.get(count -1).hashCode(), fs.hashCode());
+ assertEquals(msg, fss.get(fssStart + count -1).hashCode(), fs.hashCode());
}
}
- assertEquals(annotCount, count);
- // System.out.println("Size of ambiguous iterator: " + count);
- it = annotIndex.iterator(false); // false means create an unambiguous iterator
- count = 0;
- while (it.isValid()) {
- ++count;
- it.moveToNext();
+ assertEquals(msg, expected, count);
+ if (count > 0) {
+ // test moveTo(fs) in middle, first, and last
+ AnnotationFS posFs = fss.get(fssStart + (count >> 1));
+ it.moveTo(posFs);
+ assertEquals(msg, it.get().hashCode(), posFs.hashCode());
+
+ posFs = fss.get(fssStart);
+ it.moveTo(posFs);
+ assertEquals(msg, it.get().hashCode(), posFs.hashCode());
+ it.moveToFirst();
+ assertEquals(msg, it.get().hashCode(), posFs.hashCode());
+
+ posFs = fss.get(fssStart + count - 1);
+ it.moveTo(posFs);
+ assertEquals(msg, it.get().hashCode(), posFs.hashCode());
+ it.moveToLast();
+ assertEquals(msg, it.get().hashCode(), posFs.hashCode());
+ } else {
+ // count is 0
+ it.moveToFirst();
+ assertFalse(it.isValid());
+ it.moveToLast();
+ assertFalse(it.isValid());
+ it.moveTo(cas.getDocumentAnnotation());
+ assertFalse(it.isValid());
}
- assertEquals(1, count); // because of document Annotation
- // System.out.println("Size of unambiguous iterator: " + count);
- AnnotationFS bigAnnot = this.cas.createAnnotation(this.sentenceType, 10, 41);
- it = annotIndex.subiterator(bigAnnot, true, true);
- count = 0;
- while (it.isValid()) {
- ++count;
- // AnnotationFS a = (AnnotationFS) it.get();
- // System.out.println("Annotation from " + a.getBegin() + " to " + a.getEnd());
- it.moveToNext();
- }
- assertEquals(32, count);
- count = 0;
- for (it.moveToLast(); it.isValid(); it.moveToPrevious()) {
- ++count;
- }
- assertEquals(32, count);
- // System.out.println("Size of subiterator(true, true): " + count);
- it = annotIndex.subiterator(bigAnnot, false, true);
- count = 0;
- while (it.isValid()) {
- ++count;
- // AnnotationFS a = (AnnotationFS) it.get();
- // System.out.println("Annotation from " + a.getBegin() + " to " + a.getEnd());
- it.moveToNext();
- }
- assertEquals(3, count);
- // System.out.println("Size of subiterator(false, true): " + count);
- count = 0;
- for (it.moveToLast(); it.isValid(); it.moveToPrevious()) {
- ++count;
- }
- assertEquals(3, count);
- it = annotIndex.subiterator(bigAnnot, true, false);
- count = 0;
- while (it.isValid()) {
- ++count;
- // AnnotationFS a = (AnnotationFS) it.get();
- // System.out.println("Annotation from " + a.getBegin() + " to " + a.getEnd());
- it.moveToNext();
- }
- assertEquals(39, count);
- // System.out.println("Size of subiterator(true, false): " + count);
- count = 0;
- for (it.moveToLast(); it.isValid(); it.moveToPrevious()) {
- ++count;
- }
- assertEquals(39, count);
- it = annotIndex.subiterator(bigAnnot, false, false);
- count = 0;
- while (it.isValid()) {
- ++count;
- // AnnotationFS a = (AnnotationFS) it.get();
- // System.out.println("Annotation from " + a.getBegin() + " to " + a.getEnd());
- it.moveToNext();
- }
- assertEquals(4, count);
- // System.out.println("Size of subiterator(false, false): " + count);
- count = 0;
- for (it.moveToLast(); it.isValid(); it.moveToPrevious()) {
- ++count;
- }
- assertEquals(4, count);
- AnnotationFS sent = this.cas.getAnnotationIndex(this.sentenceType).iterator().get();
- it = annotIndex.subiterator(sent, false, true);
- count = 0;
- while (it.isValid()) {
- ++count;
- // AnnotationFS a = (AnnotationFS) it.get();
- // System.out.println("Annotation from " + a.getBegin() + " to " + a.getEnd());
- it.moveToNext();
- }
- assertEquals(2, count);
- // System.out.println("Size of subiterator(false, false): " + count);
+
+ // test movetoLast, moving backwards
count = 0;
for (it.moveToLast(); it.isValid(); it.moveToPrevious()) {
++count;
}
- assertEquals(2, count);
-
+ assertEquals(msg, expected, count);
}
public void testIncorrectIndexTypeException() {