Author: schor Date: Wed Jul 18 18:28:32 2018 New Revision: 1836215 URL: http://svn.apache.org/viewvc?rev=1836215&view=rev Log: [UIMA-5830][UIMA-5829][UIMA-5828][UIMA-5826] many fixes to select
Modified: uima/uv3/uimaj-v3/trunk/uimaj-core/src/main/java/org/apache/uima/cas/SelectFSs.java uima/uv3/uimaj-v3/trunk/uimaj-core/src/main/java/org/apache/uima/cas/impl/SelectFSs_impl.java Modified: uima/uv3/uimaj-v3/trunk/uimaj-core/src/main/java/org/apache/uima/cas/SelectFSs.java URL: http://svn.apache.org/viewvc/uima/uv3/uimaj-v3/trunk/uimaj-core/src/main/java/org/apache/uima/cas/SelectFSs.java?rev=1836215&r1=1836214&r2=1836215&view=diff ============================================================================== --- uima/uv3/uimaj-v3/trunk/uimaj-core/src/main/java/org/apache/uima/cas/SelectFSs.java (original) +++ uima/uv3/uimaj-v3/trunk/uimaj-core/src/main/java/org/apache/uima/cas/SelectFSs.java Wed Jul 18 18:28:32 2018 @@ -380,8 +380,8 @@ public interface SelectFSs<T extends Fea SelectFSs<T> following(int position, int offset); /** - * For AnnotationIndex, set up a selection that will proceed backwards, - * starting at the first Annotation to the left of the specified position, + * For AnnotationIndex, set up a selection that will go from the beginning to + * the first Annotation to the left of the specified position, * whose end <= fs.getBegin(). * Annotations whose end > fs.getBegin() are skipped. * @param annotation the Annotation to use as the position to start before. @@ -389,28 +389,31 @@ public interface SelectFSs<T extends Fea */ SelectFSs<T> preceding(Annotation annotation); /** - * For AnnotationIndex, set up a selection that will proceed backwards, - * starting at the first Annotation whose end <= position. + * For AnnotationIndex, set up a selection that will go from the beginning to + * the first Annotation to the left of the specified position, + * ending at the last Annotation whose end <= position. * Annotations whose end > position are skipped. * @param position the position to start before. * @return the updated SelectFSs object */ SelectFSs<T> preceding(int position); /** - * For AnnotationIndex, set up a selection that will proceed backwards, - * starting at the first Annotation whose end <= fs.getBegin(), + * For AnnotationIndex, set up a selection that will go from the beginning to + * the first Annotation to the left of the specified position, + * ending at the last Annotation whose end <= fs.getBegin(), * after adjusting by offset items. * Annotations whose end > fs.getBegin() are skipped (including during the offset positioning) * @param annotation the Annotation to use as the position to start before. - * @param offset the offset adjustment, positive or negative. Positive moves backwards. + * @param offset the offset adjustment, positive or negative. Positive moves backwards. * @return the updated SelectFSs object */ SelectFSs<T> preceding(Annotation annotation, int offset); /** - * For AnnotationIndex, set up a selection that will proceed backwards, - * starting at the first Annotation whose end <= position. + * For AnnotationIndex, set up a selection that will go from the beginning to + * the first Annotation to the left of the specified position, + * ending at the last Annotation whose end <= position. * after adjusting by offset items. - * Annotations whose end > fs.getBegin() are skipped (including during the offset positioning) + * Annotations whose end > position are skipped (including during the offset positioning) * @param position the position to start before. * @param offset the offset adjustment, positive or negative. Positive moves backwards. * @return the updated SelectFSs object Modified: uima/uv3/uimaj-v3/trunk/uimaj-core/src/main/java/org/apache/uima/cas/impl/SelectFSs_impl.java URL: http://svn.apache.org/viewvc/uima/uv3/uimaj-v3/trunk/uimaj-core/src/main/java/org/apache/uima/cas/impl/SelectFSs_impl.java?rev=1836215&r1=1836214&r2=1836215&view=diff ============================================================================== --- uima/uv3/uimaj-v3/trunk/uimaj-core/src/main/java/org/apache/uima/cas/impl/SelectFSs_impl.java (original) +++ uima/uv3/uimaj-v3/trunk/uimaj-core/src/main/java/org/apache/uima/cas/impl/SelectFSs_impl.java Wed Jul 18 18:28:32 2018 @@ -20,12 +20,11 @@ package org.apache.uima.cas.impl; import java.lang.reflect.Array; -import java.util.AbstractSequentialList; +import java.util.AbstractList; import java.util.ArrayList; import java.util.Comparator; import java.util.Iterator; import java.util.List; -import java.util.ListIterator; import java.util.Optional; import java.util.Spliterator; import java.util.function.BiConsumer; @@ -81,6 +80,7 @@ import org.apache.uima.jcas.tcas.Annotat * * for not-bounded, * - ignore strict and skipEq + * -- except: preceding implies skipping annotations whose end > positioning begin * - order-not-needed only applies if iicp size > 1 * - unambig ==> use Subiterator * -- subiterator wraps: according to typePriority and order-not-needed @@ -91,7 +91,7 @@ import org.apache.uima.jcas.tcas.Annotat * - use subiterator, pass in strict and skipeq * finish this javadoc comment edit - * extends FeatureStructure, not TOP, because of ref from FSIndex + * T extends FeatureStructure, not TOP, because of ref from FSIndex * which uses FeatureStructure for backwards compatibility */ public class SelectFSs_impl <T extends FeatureStructure> implements SelectFSs<T> { @@ -130,6 +130,7 @@ public class SelectFSs_impl <T extends F private TOP startingFs = null; // this is used for non-annotation positioning too private AnnotationFS boundingFs = null; + private boolean isEmptyBoundingFs = false; /* ********************************************** @@ -392,6 +393,9 @@ public class SelectFSs_impl <T extends F @Override public SelectFSs_impl<T> limit(int alimit) { + if (alimit < 0) { + throw new IllegalArgumentException("limit argument must be >= 0, but was " + alimit); + } this.limit = alimit; return this; } @@ -431,10 +435,15 @@ public class SelectFSs_impl <T extends F @Override public SelectFSs_impl<T> between(AnnotationFS fs1, AnnotationFS fs2) { // AI - final boolean reverse = fs1.getEnd() > fs2.getBegin(); - this.boundingFs = makePosAnnot( - (reverse ? fs2 : fs1).getEnd(), - (reverse ? fs1 : fs2).getBegin()); + final boolean reverse = fs1.getEnd() > fs2.getBegin(); + int begin = (reverse ? fs2 : fs1).getEnd(); + int end = (reverse ? fs1 : fs2).getBegin(); + + if (begin > end) { + isEmptyBoundingFs = true; + } else { + this.boundingFs = makePosAnnot(begin, end); + } this.boundsUse = BoundsUse.coveredBy; this.isBackwards = reverse; // this.isIncludeAnnotWithEndBeyondBounds = true; // default @@ -481,8 +490,8 @@ public class SelectFSs_impl <T extends F private void prepareTerminalOp() { if (boundsUse == null) { boundsUse = BoundsUse.notBounded; - } - + } + maybeValidateAltSource(); final boolean isUseAnnotationIndex = @@ -507,8 +516,15 @@ public class SelectFSs_impl <T extends F ti = (TypeImpl) index.getType(); } } else { - if (index != null && ((TypeImpl)index.getType()).subsumes(ti)) { - index = ((LowLevelIndex)index).getSubIndex(ti); + // type is specified + if (index != null) { + if (((TypeImpl)index.getType()).subsumes(ti)) { + index = ((LowLevelIndex)index).getSubIndex(ti); + } + } else { + if (ti.isAnnotationType()) { + forceAnnotationIndex(); // when index is null, but ti is not null and is annotation + } } } @@ -524,6 +540,16 @@ public class SelectFSs_impl <T extends F isIncludeAnnotBeyondBounds = true; } + // force ordering + boolean orderingNeeded = + !isUnordered || + shift != 0 || + boundsUse != BoundsUse.notBounded || + isFollowing || isPreceding; + + isUnordered = ! orderingNeeded; + + } private void maybeValidateAltSource() { @@ -578,43 +604,72 @@ public class SelectFSs_impl <T extends F public FSIterator<T> fsIterator() { if (isFollowing && isBackwards) { isBackwards = false; - LowLevelIterator<T> baseIterator = fsIterator1(); - T[] a = (T[]) asArray(baseIterator); - FSIterator<T> it = new FsIterator_backwards<>( - new FsIterator_subtypes_snapshot<T>( - a, - (LowLevelIndex<T>) index, - IS_ORDERED, - baseIterator.getComparator())); - return (limit == 0) - ? it - // rewrap with limit - needs to be outer shell to get right invalid behavior - : new FsIterator_limited<>(it, limit); + return make_or_copy_snapshot(fsIterator1(), true); +// LowLevelIterator<T> baseIterator = fsIterator1(); +// FSIterator<T> it; +// if (baseIterator instanceof FsIterator_subtypes_snapshot) { +// it = new FsIterator_backwards<>(baseIterator.copy()); // avoid making another array +// } else { +// T[] a = (T[]) asArray(baseIterator); +// it = new FsIterator_backwards<>( +// new FsIterator_subtypes_snapshot<T>( +// a, +// (LowLevelIndex<T>) index, +// IS_ORDERED, +// baseIterator.getComparator())); +// } +// return (limit == -1) +// ? it +// // rewrap with limit - needs to be outer shell to get right invalid behavior +// : new FsIterator_limited<>(it, limit); } if (isPreceding) { - boolean bkwd = isBackwards; - isBackwards = true; - LowLevelIterator<T> baseIterator = fsIterator1(); - T[] a = (T[]) asArray(baseIterator); - FSIterator<T> it = new FsIterator_subtypes_snapshot<T>( - a, - (LowLevelIndex<T>) index, - IS_ORDERED, - baseIterator.getComparator()); - if (!bkwd) { - it = new FsIterator_backwards<>(it); // because array is backwards - } - return (limit == 0) - ? it - // rewrap with limit - needs to be outer shell to get right invalid behavior - : new FsIterator_limited<>(it, limit); + boolean bkwd = isBackwards; // save isBackwards flag. + // since preceding normally operates backwards, if this flag is set + // the user wants to operate "forwards" + isBackwards = true; // because need the iterator to move from the position to the front. + return make_or_copy_snapshot(fsIterator1(), bkwd); // this iterator fails to skip annotations whose end is > positioning begin +// LowLevelIterator<T> baseIterator = fsIterator1(); // this iterator fails to skip annotations whose end is > positioning begin +// T[] a = (T[]) asArray(baseIterator); +// FSIterator<T> it = new FsIterator_subtypes_snapshot<T>( +// a, +// (LowLevelIndex<T>) index, +// IS_ORDERED, +// baseIterator.getComparator()); +// if (!bkwd) { +// it = new FsIterator_backwards<>(it); // because array is backwards +// } +// return (limit == -1) +// ? it +// // rewrap with limit - needs to be outer shell to get right invalid behavior +// : new FsIterator_limited<>(it, limit); } // all others, including isFollowing but not backwards return fsIterator1(); } + private FSIterator<T> make_or_copy_snapshot(LowLevelIterator<T> baseIterator, boolean bkwd) { + FSIterator<T> it; + T[] a = (T[]) asArray(baseIterator); // array is in forward order because + // it's produced by a backwards iterator, but then the array is reversed + it = new FsIterator_subtypes_snapshot<T>( + a, + (LowLevelIndex<T>) index, + IS_ORDERED, + baseIterator.getComparator()); + + if (!bkwd) { + it = new FsIterator_backwards<>(it); + } + + return (limit == -1) + ? it + // rewrap with limit - needs to be outer shell to get right invalid behavior + : new FsIterator_limited<T>(it, limit); + } + private LowLevelIterator<T> fsIterator1() { prepareTerminalOp(); LowLevelIterator<T> it = isAllViews @@ -622,6 +677,7 @@ public class SelectFSs_impl <T extends F createFsIterator_for_all_views() : plainFsIterator(index, view); + it = maybeWrapBackwards(it); maybePosition(it); maybeShift(it); return (limit == -1) ? it : new FsIterator_limited<>(it, limit); @@ -706,7 +762,7 @@ public class SelectFSs_impl <T extends F LowLevelIterator<T> it; if (boundsUse == BoundsUse.notBounded) { if (!isSortedIndex) { - // set index + // set index or bag index it = (LowLevelIterator<T>) idx.iterator(); } else { // index is sorted but no bounds are being used. Varieties: @@ -714,13 +770,23 @@ public class SelectFSs_impl <T extends F // - overlapping / non-overlapping (ambiguous, unambiguous) // - any sorted index including AnnotationIndex: // - typePriority / ignore typePriority - // - orderNotNecessary / + // - orderNotNecessary / orderNeeded + // - preceding: need to skip over annotations whose end is > positioning-begin - it = (isAnnotationIndex) - ? (LowLevelIterator<T>) ai.iterator( ! isNonOverlapping, IS_NOT_STRICT /* because unbounded */, isUnordered, ! isTypePriority) + it = isAnnotationIndex + ? (LowLevelIterator<T>) ai.iterator( ! isNonOverlapping, IS_NOT_STRICT, isUnordered, ! isTypePriority) : idx.iterator(isUnordered, ! isTypePriority); + if (isPreceding) { + // filter the iterator to skip annotations whose end is > the position-begin + it = new FilteredIterator<T>(it, fs -> + // true if ok, false to skip + ((Annotation)fs).getEnd() <= ((Annotation)startingFs).getBegin()); + } } } else { + if (isEmptyBoundingFs) { + return (LowLevelIterator<T>) LowLevelIterator.FS_ITERATOR_LOW_LEVEL_EMPTY; + } // bounds in use, index must be annotation index, is ordered it = (LowLevelIterator<T>) new Subiterator<Annotation>( (FSIterator<Annotation>) idx.iterator(isUnordered, ! isTypePriority), @@ -731,14 +797,18 @@ public class SelectFSs_impl <T extends F isTypePriority, isSkipSameBeginEndType); } - - - it = isBackwards ? new FsIterator_backwards<>(it) : it; + + return it; + } + + private LowLevelIterator<T> maybeWrapBackwards(LowLevelIterator<T> it) { if (isBackwards) { - it.moveToFirst(); + it = new FsIterator_backwards<>(it); + it.moveToFirst(); } return it; } + private LowLevelIterator<T> altSourceIterator() { T[] filtered; @@ -797,28 +867,43 @@ public class SelectFSs_impl <T extends F public Iterator<T> iterator() { return fsIterator(); } - + + /* + * (non-Javadoc) + * @see org.apache.uima.cas.SelectFSs#asList() + * + * The operation of this is to make an iterator which is directly addressable, + * and then return an instance of AbstractList<N> + * + */ @Override public <N extends T> List<N> asList() { - prepareTerminalOp(); - - return new AbstractSequentialList<N>() { + + return new AbstractList<N>() { + + /** + * iterator used for two purposes: + * - as underlying impl for listIterator + * - to compute the size + */ + private final LowLevelIterator<T> it = (LowLevelIterator<T>) fsIterator(); + N[] a = asArrayFs(it); + @Override - public ListIterator<N> listIterator(int startingIndex) { - ListIterator<N> it = (ListIterator<N>) fsIterator(); - for (int i = 0; i < startingIndex; i++) { - it.next(); - } - return it; + public N get(int i) { + return a[i]; } @Override public int size() { - return (index == null) ? -1 : index.size(); + return it.size(); } - }; + + + + } /* (non-Javadoc) @@ -826,30 +911,22 @@ public class SelectFSs_impl <T extends F */ @Override public <N extends T> N[] asArray(Class<N> clazz) { - return asArray(fsIterator(), clazz); + return asArray((LowLevelIterator<T>)fsIterator()); } - private <N extends T> N[] asArray(FSIterator<T> it, Class<N> clazz) { - List<N> al = asArray1(it); - N[] r = (N[]) Array.newInstance(clazz, al.size()); - return al.toArray(r); + private <N extends T> N[] asArrayFs(LowLevelIterator<T> it) { + return (N[]) ((LowLevelIterator<T>)it).getArray(); } - private <N extends T> List<N> asArray1(FSIterator<T> it) { - List<N> al = new ArrayList<>(); - while (it.isValid()) { - al.add((N) it.getNvc()); // limit iterator might cause it to become invalid - it.moveToNext(); - } - return al; - } - - private FeatureStructure[] asArray(FSIterator<T> it) { - List<? super T> al = asArray1(it); - FeatureStructure[] r = (FeatureStructure[]) Array.newInstance(FeatureStructure.class, al.size()); - return al.toArray(r); + private <N extends T> N[] asArray(LowLevelIterator<T> it) { + return (N[]) ((LowLevelIterator<T>)it).getArray(); } + +// private FeatureStructure[] asArray(FSIterator<T> it) { +// return asArray(it, FeatureStructure.class); +// } + private Annotation makePosAnnot(int begin, int end) { if (end < begin) { throw new IllegalArgumentException("End value must be >= Begin value"); @@ -1245,9 +1322,6 @@ public class SelectFSs_impl <T extends F public SelectFSs<T> preceding(int position, int offset) { return commonPreceding(makePosAnnot(position, Integer.MAX_VALUE), offset); } - - - /************************ * NOT USED @@ -1292,13 +1366,14 @@ public class SelectFSs_impl <T extends F this.startingFs = annotation; this.shift = offset; isPreceding = true; - isBackwards = true; // always iterate backwards return this; } private void forceAnnotationIndex() { if (index == null) { - index = (LowLevelIndex<T>) view.getAnnotationIndex(); + index = (LowLevelIndex<T>) ( (ti == null) ? + view.getAnnotationIndex() : + view.getAnnotationIndex(ti)); } else { if (!(index instanceof AnnotationIndex)) { /** Index "{0}" must be an AnnotationIndex. */