| /* |
| * 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 static org.apache.uima.cas.impl.Subiterator.BoundsUse.notBounded; |
| import static org.apache.uima.jcas.tcas.Annotation._createMarkerAnnotation; |
| |
| import java.lang.reflect.Array; |
| import java.util.ArrayList; |
| import java.util.Comparator; |
| import java.util.Iterator; |
| import java.util.List; |
| import java.util.Optional; |
| import java.util.Spliterator; |
| import java.util.function.BiConsumer; |
| import java.util.function.BiFunction; |
| import java.util.function.BinaryOperator; |
| import java.util.function.Consumer; |
| import java.util.function.Function; |
| import java.util.function.IntFunction; |
| import java.util.function.Predicate; |
| import java.util.function.Supplier; |
| import java.util.function.ToDoubleFunction; |
| import java.util.function.ToIntFunction; |
| import java.util.function.ToLongFunction; |
| import java.util.stream.Collector; |
| import java.util.stream.DoubleStream; |
| import java.util.stream.IntStream; |
| import java.util.stream.LongStream; |
| import java.util.stream.Stream; |
| import java.util.stream.StreamSupport; |
| |
| import org.apache.uima.cas.CAS; |
| import org.apache.uima.cas.CASRuntimeException; |
| import org.apache.uima.cas.FSIndex; |
| import org.apache.uima.cas.FSIterator; |
| import org.apache.uima.cas.FeatureStructure; |
| import org.apache.uima.cas.SelectFSs; |
| import org.apache.uima.cas.Type; |
| import org.apache.uima.cas.impl.Subiterator.BoundsUse; |
| import org.apache.uima.cas.text.AnnotationFS; |
| import org.apache.uima.cas.text.AnnotationIndex; |
| import org.apache.uima.cas.text.AnnotationPredicates; |
| import org.apache.uima.jcas.cas.EmptyFSList; |
| import org.apache.uima.jcas.cas.FSArray; |
| import org.apache.uima.jcas.cas.FSList; |
| import org.apache.uima.jcas.cas.NonEmptyFSList; |
| import org.apache.uima.jcas.cas.TOP; |
| import org.apache.uima.jcas.impl.JCasImpl; |
| import org.apache.uima.jcas.tcas.Annotation; |
| |
| // @formatter:off |
| /** |
| * Collection of builder style methods to specify selection of FSs from indexes |
| * shift handled in this routine |
| * Comment codes: |
| * AI = implies AnnotationIndex |
| * |
| * Iterator varieties and impl |
| * |
| * bounded? type order not unambig? strict? skipEq |
| * Priority? Needed? |
| * no |
| * coveredBy |
| * covering |
| * sameas |
| * |
| * 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 |
| * - no Type Priority - need to pass in as arg to fsIterator_multiple_indexes |
| * == if no type priority, need to prevent rattling off the == type while compare is equal |
| * == affects both FsIterator_aggregation_common and FsIterator_subtypes_ordered |
| * for 3 other boundings: |
| * - use subiterator, pass in strict and skipeq |
| * |
| finish this javadoc comment edit |
| * T extends FeatureStructure, not TOP, because of ref from FSIndex |
| * which uses FeatureStructure for backwards compatibility |
| */ |
| //@formatter:on |
| public class SelectFSs_impl<T extends FeatureStructure> implements SelectFSs<T> { |
| |
| private final static boolean IS_UNORDERED = true; |
| private final static boolean IS_ORDERED = false; |
| private final static boolean IS_UNAMBIGUOUS = false; |
| private final static boolean IS_NOT_STRICT = false; |
| |
| private CASImpl view; |
| private JCasImpl jcas; |
| private LowLevelIndex<T> index; |
| private TypeImpl ti; |
| private int shift; |
| private int limit = -1; |
| |
| private FeatureStructure[] sourceFSArray = null; // alternate source |
| private FSList sourceFSList = null; // alternate source |
| |
| private boolean isTypePriority = false; |
| // private boolean isPositionUsesType = false; // REMOVED see |
| // https://issues.apache.org/jira/browse/UIMA-5536 |
| private boolean isSkipSameBeginEndType = false; // for boundsUse only |
| private boolean isNonOverlapping = IS_UNAMBIGUOUS; |
| private boolean isIncludeAnnotBeyondBounds = false; |
| private boolean isAllViews = false; |
| private boolean isNullOK = false; |
| private boolean isUnordered = false; |
| private boolean isBackwards = false; |
| private boolean isFollowing = false; |
| private boolean isPreceding = false; |
| |
| private boolean isAltSource = false; |
| |
| private BoundsUse boundsUse = null; |
| |
| /** |
| * This is used for non-annotation positioning too Used for preceding since we tweak the end |
| * offset of the reference annotation |
| */ |
| private TOP startingFs = null; |
| private AnnotationFS boundingFs = null; |
| private boolean noResult = false; |
| |
| //@formatter:off |
| /* ********************************************** |
| * Constructors |
| * always need the cas |
| * might also have the type |
| * Caller will convert other forms for the cas (e.g. jcas) |
| * and type (e.g. type name, MyType.type, MyType.class) to |
| * these arg forms. |
| ************************************************/ |
| //@formatter:on |
| public SelectFSs_impl(CAS cas) { |
| view = (CASImpl) cas.getLowLevelCAS(); |
| jcas = (JCasImpl) view.getJCas(); |
| } |
| |
| public SelectFSs_impl(FSArray source) { |
| this(source._casView); |
| isAltSource = true; |
| sourceFSArray = source._getTheArray(); |
| } |
| |
| public SelectFSs_impl(FeatureStructure[] source, CAS cas) { |
| this(cas); |
| isAltSource = true; |
| sourceFSArray = source; |
| } |
| |
| public SelectFSs_impl(FSList source) { |
| this(source._casView); |
| isAltSource = true; |
| sourceFSList = source; |
| } |
| |
| /************************************************ |
| * Builders |
| ************************************************/ |
| /** |
| * INDEX If not specified, defaults to all FSs (orderNotNeeded) unless AnnotationIndex implied |
| * |
| * @param indexName |
| * - |
| * @return - |
| */ |
| public SelectFSs_impl<T> index(String indexName) { |
| index = view.indexRepository.getIndex(indexName); |
| return this; |
| } |
| |
| public SelectFSs_impl<T> index(FSIndex<T> aIndex) { |
| index = (LowLevelIndex<T>) aIndex; |
| return this; |
| } |
| |
| /** |
| * Select the index's uppermost type. |
| */ |
| public <N extends T> SelectFSs_impl<N> anyType() { |
| ti = (TypeImpl) null; |
| return (SelectFSs_impl<N>) this; |
| } |
| |
| public <N extends T> SelectFSs_impl<N> type(Type uimaType) { |
| if (uimaType == null) { |
| throw new IllegalArgumentException("Must specify a type"); |
| } |
| |
| if (view.getTypeSystemImpl() != ((TypeImpl) uimaType).getTypeSystem()) { |
| Type type = view.getTypeSystem().getType(uimaType.getName()); |
| if (type == null) { |
| throw new IllegalArgumentException("Undefined type: [" + uimaType.getName() + "]"); |
| } |
| } |
| |
| ti = (TypeImpl) uimaType; |
| return (SelectFSs_impl<N>) this; |
| } |
| |
| public <N extends T> SelectFSs_impl<N> type(String fullyQualifiedTypeName) { |
| if (fullyQualifiedTypeName == null) { |
| throw new IllegalArgumentException("Must specify a type"); |
| } |
| |
| TypeImpl type = view.getTypeSystemImpl().getType(fullyQualifiedTypeName); |
| if (type == null) { |
| throw new IllegalArgumentException("Undefined type: [" + fullyQualifiedTypeName + "]"); |
| } |
| |
| ti = type; |
| return (SelectFSs_impl<N>) this; |
| } |
| |
| public <N extends T> SelectFSs_impl<N> type(int jcasClass_dot_type) { |
| ti = (TypeImpl) view.getJCas().getCasType(jcasClass_dot_type); |
| return (SelectFSs_impl<N>) this; |
| } |
| |
| public <N extends T> SelectFSs_impl<N> type(Class<N> jcasClass_dot_class) { |
| if (jcasClass_dot_class == null) { |
| throw new IllegalArgumentException("Must specify a type"); |
| } |
| ti = (TypeImpl) view.getJCasImpl().getCasType(jcasClass_dot_class); |
| return (SelectFSs_impl<N>) this; |
| } |
| |
| /* |
| * (non-Javadoc) |
| * |
| * @see org.apache.uima.cas.SelectFSs#typePriority() |
| */ |
| @Override |
| public SelectFSs<T> typePriority() { |
| isTypePriority = true; |
| return this; |
| } |
| |
| /* |
| * (non-Javadoc) |
| * |
| * @see org.apache.uima.cas.SelectFSs#typePriority(boolean) |
| */ |
| @Override |
| public SelectFSs<T> typePriority(boolean aTypePriority) { |
| isTypePriority = aTypePriority; |
| return this; |
| } |
| |
| // For testing |
| boolean usesTypePriority() { |
| return isTypePriority; |
| } |
| |
| /********************************* |
| * boolean operations |
| *********************************/ |
| |
| // REMOVED see https://issues.apache.org/jira/browse/UIMA-5536 |
| // /* (non-Javadoc) |
| // * @see org.apache.uima.cas.SelectFSs#positionUsesType() |
| // */ |
| // @Override |
| // public SelectFSs<T> positionUsesType() { |
| // this.isPositionUsesType = true; |
| // return this; |
| // } |
| // |
| // /* (non-Javadoc) |
| // * @see org.apache.uima.cas.SelectFSs#positionUsesType(boolean) |
| // */ |
| // @Override |
| // public SelectFSs<T> positionUsesType(boolean aPositionUsesType) { |
| // this.isPositionUsesType = aPositionUsesType; |
| // return this; |
| // } |
| |
| /* |
| * (non-Javadoc) |
| * |
| * @see org.apache.uima.cas.SelectFSs#skipEquals() |
| */ |
| @Override |
| public SelectFSs<T> skipWhenSameBeginEndType() { |
| isSkipSameBeginEndType = true; |
| return this; |
| } |
| |
| /* |
| * (non-Javadoc) |
| * |
| * @see org.apache.uima.cas.SelectFSs#skipEquals(boolean) |
| */ |
| @Override |
| public SelectFSs<T> useAnnotationEquals(boolean useAnnotationEquals) { |
| isSkipSameBeginEndType = useAnnotationEquals; |
| return this; |
| } |
| |
| /** |
| * Filters while iterating |
| **/ |
| |
| @Override |
| public SelectFSs_impl<T> nonOverlapping() { // AI known as unambiguous |
| isNonOverlapping = true; |
| return this; |
| } |
| |
| @Override |
| public SelectFSs_impl<T> nonOverlapping(boolean bNonOverlapping) { // AI |
| isNonOverlapping = bNonOverlapping; |
| return this; |
| } |
| |
| @Override |
| public SelectFSs_impl<T> includeAnnotationsWithEndBeyondBounds() { // AI known as "not strict" |
| isIncludeAnnotBeyondBounds = true; |
| return this; |
| } |
| |
| @Override |
| public SelectFSs_impl<T> includeAnnotationsWithEndBeyondBounds( |
| boolean includeAnnotationsWithEndBeyondBounds) { // AI |
| isIncludeAnnotBeyondBounds = includeAnnotationsWithEndBeyondBounds; |
| return this; |
| } |
| |
| // public SelectFSs_impl<T> useTypePriorities() { |
| // return this; |
| // } |
| // public SelectFSs_impl<T> useTypePriorities(boolean useTypePriorities) { |
| // return this; |
| // } |
| |
| /** |
| * Miscellaneous |
| **/ |
| |
| @Override |
| public SelectFSs_impl<T> allViews() { |
| isAllViews = true; |
| return this; |
| } |
| |
| @Override |
| public SelectFSs_impl<T> allViews(boolean bAllViews) { |
| isAllViews = bAllViews; |
| return this; |
| } |
| |
| @Override |
| public SelectFSs_impl<T> nullOK() { // applies to get() and single() |
| isNullOK = true; |
| return this; |
| } |
| |
| @Override |
| public SelectFSs_impl<T> nullOK(boolean bNullOk) { // applies to get() and single() |
| isNullOK = bNullOk; |
| return this; |
| } |
| |
| @Override |
| public SelectFSs_impl<T> orderNotNeeded() { // ignored if not ordered index |
| isUnordered = true; |
| return this; |
| } |
| |
| @Override |
| public SelectFSs_impl<T> orderNotNeeded(boolean bUnordered) { // ignored if not ordered index |
| isUnordered = bUnordered; |
| return this; |
| } |
| |
| @Override |
| public SelectFSs_impl<T> backwards() { // ignored if not ordered index |
| isBackwards = true; |
| return this; |
| } |
| |
| @Override |
| public SelectFSs_impl<T> backwards(boolean bBackwards) { // ignored if not ordered index |
| isBackwards = bBackwards; |
| return this; |
| } |
| |
| // public SelectFSs_impl<T> noSubtypes() { |
| // return this; |
| // } |
| // public SelectFSs_impl<T> noSubtypes(boolean noSubtypes) { |
| // return this; |
| // } |
| |
| /********************************* |
| * starting position |
| *********************************/ |
| |
| @Override |
| public SelectFSs_impl<T> shifted(int shiftAmount) { |
| shift = shiftAmount; |
| return this; |
| } |
| |
| @Override |
| public SelectFSs_impl<T> startAt(FeatureStructure fs) { |
| startingFs = (TOP) fs; |
| return this; |
| } |
| |
| @Override |
| public SelectFSs_impl<T> startAt(TOP fs) { // Ordered |
| startingFs = fs; |
| return this; |
| } |
| // @Override |
| // public SelectFSs_impl<T> startAt(AnnotationFS fs) { |
| // return (startAt((TOP)fs)); |
| // } |
| // @Override |
| // public SelectFSs_impl<T> startAt(Annotation fs) { |
| // return (startAt((TOP)fs)); |
| // } |
| |
| @Override |
| public SelectFSs_impl<T> startAt(int begin) { |
| isTypePriority = false; |
| startingFs = makePosAnnot(begin, Integer.MAX_VALUE); |
| return this; |
| } |
| |
| @Override |
| public SelectFSs_impl<T> startAt(int begin, int end) { // AI |
| startingFs = makePosAnnot(begin, end); |
| return this; |
| } |
| |
| @Override |
| public SelectFSs_impl<T> startAt(TOP fs, int offset) { // Ordered |
| startingFs = fs; |
| shift = offset; |
| return this; |
| } |
| |
| @Override |
| public SelectFSs_impl<T> startAt(FeatureStructure fs, int offset) { // Ordered |
| startingFs = (TOP) fs; |
| shift = offset; |
| return this; |
| } |
| |
| @Override |
| public SelectFSs_impl<T> startAt(int begin, int end, int offset) { // AI |
| startingFs = makePosAnnot(begin, end); |
| shift = offset; |
| return this; |
| } |
| |
| @Override |
| public SelectFSs_impl<T> limit(int alimit) { |
| if (alimit < 0) { |
| throw new IllegalArgumentException("limit argument must be >= 0, but was " + alimit); |
| } |
| limit = alimit; |
| return this; |
| } |
| |
| /********************************* |
| * subselection based on boundingFs |
| *********************************/ |
| @Override |
| public SelectFSs_impl<T> coveredBy(AnnotationFS fs) { // AI |
| boundsUse = BoundsUse.coveredBy; |
| boundingFs = fs; |
| // this.isIncludeAnnotWithEndBeyondBounds = false; //default |
| return this; |
| } |
| |
| @Override |
| public SelectFSs_impl<T> coveredBy(int begin, int end) { // AI |
| boundsUse = BoundsUse.coveredBy; |
| boundingFs = makePosAnnot(begin, end); |
| // this.isIncludeAnnotWithEndBeyondBounds = true; //default |
| return this; |
| } |
| |
| @Override |
| public SelectFSs_impl<T> covering(AnnotationFS fs) { // AI |
| boundsUse = BoundsUse.covering; |
| boundingFs = fs; |
| return this; |
| } |
| |
| @Override |
| public SelectFSs_impl<T> covering(int begin, int end) { // AI |
| boundsUse = BoundsUse.covering; |
| boundingFs = makePosAnnot(begin, end); |
| return this; |
| } |
| |
| @Override |
| public SelectFSs_impl<T> between(AnnotationFS fs1, AnnotationFS fs2) { // AI |
| final boolean reverse = fs1.getEnd() > fs2.getBegin(); |
| int begin = (reverse ? fs2 : fs1).getEnd(); |
| int end = (reverse ? fs1 : fs2).getBegin(); |
| |
| if (begin > end) { |
| noResult = true; |
| return this; |
| } |
| |
| return coveredBy(begin, end); |
| } |
| |
| /* |
| * (non-Javadoc) |
| * |
| * @see org.apache.uima.cas.SelectFSs#at(org.apache.uima.jcas.tcas.Annotation) |
| */ |
| @Override |
| public SelectFSs<T> at(AnnotationFS fs) { |
| boundsUse = BoundsUse.sameBeginEnd; |
| boundingFs = fs; |
| return this; |
| } |
| |
| /* |
| * (non-Javadoc) |
| * |
| * @see org.apache.uima.cas.SelectFSs#at(int, int) |
| */ |
| @Override |
| public SelectFSs<T> at(int begin, int end) { |
| return at(makePosAnnot(begin, end)); |
| } |
| |
| private String maybeMsgPosition() { |
| StringBuilder sb = new StringBuilder(); |
| if (startingFs != null) { |
| if (startingFs instanceof Annotation) { |
| Annotation a = (Annotation) startingFs; |
| sb.append(" at position begin: ").append(a.getBegin()).append(", end: ").append(a.getEnd()); |
| } else { |
| sb.append(" at moveTo position given by Feature Structure:\n"); |
| startingFs.prettyPrint(2, 2, sb, false); |
| sb.append("\n "); |
| } |
| } |
| if (shift != 0) { |
| sb.append(" shifted by: ").append(shift); |
| } |
| return sb.toString(); |
| } |
| |
| private void prepareTerminalOp() { |
| if (boundsUse == null) { |
| boundsUse = BoundsUse.notBounded; |
| } |
| |
| maybeValidateAltSource(); |
| |
| final boolean isUseAnnotationIndex = ((index != null) && (index instanceof AnnotationIndex)) |
| || isNonOverlapping || |
| // isPositionUsesType || REMOVED see https://issues.apache.org/jira/browse/UIMA-5536 |
| isTypePriority || isIncludeAnnotBeyondBounds || boundsUse != BoundsUse.notBounded |
| || isFollowing || isPreceding; |
| |
| if (isUseAnnotationIndex) { |
| forceAnnotationIndex(); // throws if non-null index not an annotation index |
| } |
| // REMOVED see https://issues.apache.org/jira/browse/UIMA-5536 |
| // if (isTypePriority) { |
| // isPositionUsesType = true; |
| // } |
| |
| if (ti == null) { |
| if (index != null) { |
| ti = (TypeImpl) index.getType(); |
| } |
| } else { |
| // type is specified |
| if (index != null) { |
| if (((TypeImpl) index.getType()).subsumes(ti)) { |
| index = ((LowLevelIndex) index).getSubIndex(ti); |
| } |
| } else { |
| if (ti.isAnnotationType() && !isAltSource) { |
| forceAnnotationIndex(); // when index is null, but ti is not null and is annotation |
| } |
| } |
| } |
| |
| if (isUseAnnotationIndex && null == ti) { |
| ti = (TypeImpl) view.getAnnotationType(); |
| } |
| |
| if (ti == null) { |
| ti = view.getTypeSystemImpl().getTopType(); |
| } |
| |
| if (boundsUse == BoundsUse.covering) { |
| isIncludeAnnotBeyondBounds = true; |
| } |
| |
| // force ordering |
| boolean orderingNeeded = !isUnordered || shift != 0 || boundsUse != BoundsUse.notBounded |
| || isFollowing || isPreceding; |
| |
| isUnordered = !orderingNeeded; |
| |
| // If there is a boundary for the selection start and the shift would try to cross this |
| // boundary, it would result in an invalid iterator causing the selection operation to return |
| // an empty result. To avoid this potentially surprising behavior, reduce the shift to 0 in |
| // such a case. |
| if ((isFollowing || isPreceding || boundsUse != BoundsUse.notBounded) && shift < 0) { |
| shift = 0; |
| } |
| } |
| |
| private void maybeValidateAltSource() { |
| if (!isAltSource) { |
| return; |
| } |
| |
| if (index != null || boundsUse != BoundsUse.notBounded || isAllViews || isFollowing |
| || isPreceding || startingFs != null) { |
| /** |
| * Select with FSList or FSArray may not specify bounds, starting position, following, or |
| * preceding. |
| */ |
| throw new CASRuntimeException(CASRuntimeException.SELECT_ALT_SRC_INVALID); |
| } |
| } |
| |
| private void incr(FSIterator<T> it) { |
| it.moveToNext(); |
| } |
| |
| // @formatter:off |
| /********************************* |
| * terminal operations |
| * returning other than SelectFSs |
| * |
| * Hierarchy of interpretation of setup: |
| * - index |
| * - type |
| * |
| * - allViews: ignored: things only with annotation index |
| * order among views is arbitrary, each view done together |
| * base view skipped |
| * |
| *********************************/ |
| // @formatter:on |
| |
| // @formatter:off |
| /** |
| * F S I t e r a t o r |
| * ------------------- |
| */ |
| // @formatter:on |
| @Override |
| public FSIterator<T> fsIterator() { |
| if (isFollowing && isBackwards) { |
| isBackwards = false; |
| return make_or_copy_snapshot(fsIterator1(), false); |
| } |
| |
| if (isPreceding) { |
| // save isBackwards flag. |
| boolean bkwd = isBackwards; |
| // because need the iterator to move from the position to the front. |
| isBackwards = true; |
| // this iterator fails to skip annotations whose end is > positioning begin |
| return make_or_copy_snapshot(fsIterator1(), bkwd); |
| } |
| |
| // all others, including isFollowing but not backwards |
| return fsIterator1(); |
| } |
| |
| private LowLevelIterator<T> make_or_copy_snapshot(LowLevelIterator<T> baseIterator, |
| boolean bkwd) { |
| LowLevelIterator<T> it; |
| // array is in forward order because it's produced by a backwards iterator, but then the array |
| // is reversed |
| T[] a = (T[]) asArray(baseIterator, FeatureStructure.class); |
| |
| it = new FsIterator_subtypes_snapshot<>(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<>(it, limit); |
| } |
| |
| private LowLevelIterator<T> fsIterator1() { |
| prepareTerminalOp(); |
| LowLevelIterator<T> it = new SelectFSIterator(() -> { |
| LowLevelIterator<T> baseIt = isAllViews ? createFsIterator_for_all_views() |
| : plainFsIterator(index, view); |
| |
| baseIt = maybeWrapBackwards(baseIt); |
| // position needs to come after backwards because that sets the position |
| maybePosition(baseIt); |
| // shift semantically needs to come after backwards |
| maybeShift(baseIt); |
| return baseIt; |
| }); |
| |
| return maybeLimit(it); |
| } |
| |
| /** |
| * for a selected index, return an iterator over all the views for that index |
| * |
| * @return iterator over all views for that index, unordered |
| */ |
| private FsIterator_aggregation_common<T> createFsIterator_for_all_views() { |
| final int nbrViews = view.getNumberOfViews(); |
| LowLevelIterator<T>[] ita = new LowLevelIterator[nbrViews]; |
| // LowLevelIndex<T>[] indexes = new LowLevelIndex[nbrViews]; |
| |
| for (int i = 1; i <= nbrViews; i++) { |
| CASImpl v = (i == 1) ? view.getInitialView() : (CASImpl) view.getView(i); |
| LowLevelIndex<T> index_local = (LowLevelIndex<T>) getIndexForView(v); |
| ita[i - 1] = plainFsIterator(index_local, v); |
| // indexes[i - 1] = index; |
| } |
| // return new FsIterator_aggregation_common<T>(ita, new FsIndex_aggr<>(indexes)); |
| return new FsIterator_aggregation_common<>(ita, null, null); |
| |
| } |
| |
| // private LowLevelIterator<T>[] getPlainIteratorsForAllViews() { |
| // final int nbrViews = view.getNumberOfViews(); |
| // LowLevelIterator<T>[] ita = new LowLevelIterator[nbrViews]; |
| // |
| // for (int i = 1; i <= nbrViews; i++) { |
| // CASImpl v = (i == 1) ? view.getInitialView() : (CASImpl) view.getView(i); |
| // ita[i - 1] = plainFsIterator(getIndexForView(v), v); |
| // } |
| // return ita; |
| // } |
| |
| /** |
| * gets the index for a view that corresponds to the specified index by matching the index specs |
| * and type code |
| * |
| * @param v |
| * - |
| * @return - |
| */ |
| private LowLevelIndex<T> getIndexForView(CASImpl v) { |
| if (index == null) { |
| return null; |
| } |
| |
| FSIndexRepositoryImpl ir = (FSIndexRepositoryImpl) v.getIndexRepository(); |
| if (index instanceof FsIndex_iicp) { |
| FsIndex_iicp idx = (FsIndex_iicp) index; |
| return ir.getIndexBySpec(idx.getTypeCode(), idx.getIndexingStrategy(), |
| idx.getComparatorImplForIndexSpecs()); |
| } |
| FsIndex_singletype idx = (FsIndex_singletype) index; |
| return ir.getIndexBySpec(idx.getTypeCode(), idx.getIndexingStrategy(), |
| idx.getComparatorImplForIndexSpecs()); |
| } |
| |
| /** |
| * |
| * @param idx |
| * the index selected, corresponds to a type + its subtypes, or if null, either an |
| * alternate source or means all types |
| * @param v |
| * the cas |
| * @return an iterator |
| */ |
| private LowLevelIterator<T> plainFsIterator(LowLevelIndex<T> idx, CASImpl v) { |
| if (null == idx) { |
| // no bounds, not ordered |
| // type could be null |
| // could be alternate source |
| |
| if (isAltSource) { |
| return altSourceIterator(); |
| } else { |
| // idx is null after prepareTerminalOp has been called. |
| // guaranteed not annotationindex or any op that requires that |
| return v.indexRepository.getAllIndexedFS(ti); |
| } |
| } |
| |
| final boolean isSortedIndex = idx.getIndexingStrategy() == FSIndex.SORTED_INDEX; |
| final boolean isAnnotationIndex = idx instanceof AnnotationIndex; |
| final FsIndex_annotation<Annotation> ai = isAnnotationIndex ? (FsIndex_annotation) idx : null; |
| |
| if (boundsUse == notBounded && |
| // For ambiguous (overlapping) select, we can take a shortcut by using a FilteredIterator |
| // instead of having to use a Subiterator. However, for an unambiguous, we can no longer |
| // rely on the index iterator to handle the unambiguous mode all alone because the filtered |
| // annotator will skip results but is unable to update the previous bounds state in the |
| // index iterator. |
| ((!isFollowing && !isPreceding) |
| || (!isNonOverlapping && (isFollowing || isPreceding)))) { |
| if (noResult) { |
| return (LowLevelIterator<T>) LowLevelIterator.FS_ITERATOR_LOW_LEVEL_EMPTY; |
| } |
| |
| if (!isSortedIndex) { |
| // set index or bag index |
| return (LowLevelIterator<T>) idx.iterator(); |
| } |
| |
| // index is sorted but no bounds are being used. Varieties: |
| // - AnnotationIndex: |
| // - overlapping / non-overlapping (ambiguous, unambiguous) |
| // - any sorted index including AnnotationIndex: |
| // - typePriority / ignore typePriority |
| // - orderNotNecessary / orderNeeded |
| // - preceding: need to skip over annotations whose end is > positioning-begin |
| // - following: need to skip over zero-width annotations at positioning-end |
| LowLevelIterator<T> 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 |
| // and also if the reference annotation is a zero-width annotation, skip any |
| // annotations that end at the zero-width annotation because those would rather be seen as |
| // covering the zero-width annotation |
| int startingFSStart = ((Annotation) startingFs).getBegin(); |
| int startingFSEnd = ((Annotation) startingFs).getEnd(); |
| it = new FilteredIterator<>(it, fs -> { |
| return fs._id() != startingFs._id && AnnotationPredicates.preceding((Annotation) fs, |
| startingFSStart, startingFSEnd); |
| }); |
| } |
| |
| if (isFollowing) { |
| // Annotations are following the startFS if their begin is >= the end of the startFS |
| // except if they are zero-width FSes at the end of the startFS in which case they are |
| // considered to be covered and not following |
| int startingFSStart = ((Annotation) startingFs).getBegin(); |
| int startingFSEnd = ((Annotation) startingFs).getEnd(); |
| it = new FilteredIterator<>(it, fs -> { |
| return fs._id() != startingFs._id && AnnotationPredicates.following((Annotation) fs, |
| startingFSStart, startingFSEnd); |
| }); |
| } |
| |
| return it; |
| } |
| |
| // bounds in use or non-overlapping, so index must be annotation index, is ordered |
| Annotation secondaryBoundingFs = null; |
| boolean isIncludeZeroWidthAtBegin = true; |
| boolean isIncludeZeroWidthAtEnd = true; |
| if (isPreceding) { |
| isIncludeAnnotBeyondBounds = false; |
| boundsUse = BoundsUse.coveredBy; |
| boundingFs = makePosAnnot(0, ((Annotation) startingFs).getBegin()); |
| secondaryBoundingFs = (Annotation) startingFs; |
| isIncludeZeroWidthAtEnd = true; |
| } |
| |
| if (isFollowing) { |
| isIncludeAnnotBeyondBounds = false; |
| boundsUse = BoundsUse.coveredBy; |
| boundingFs = makePosAnnot(((Annotation) startingFs).getEnd(), Integer.MAX_VALUE); |
| secondaryBoundingFs = (Annotation) startingFs; |
| isIncludeZeroWidthAtEnd = true; |
| } |
| |
| return (LowLevelIterator<T>) new Subiterator<>( |
| (FSIterator<Annotation>) idx.iterator(isUnordered, !isTypePriority), boundingFs, |
| secondaryBoundingFs, !isNonOverlapping, // ambiguous |
| !isIncludeAnnotBeyondBounds, // strict |
| boundsUse, isTypePriority, isSkipSameBeginEndType, false, // isStrictIncludesAnnotationsStartingAtEndPosition |
| isIncludeZeroWidthAtBegin, isIncludeZeroWidthAtEnd); |
| } |
| |
| private LowLevelIterator<T> maybeWrapBackwards(LowLevelIterator<T> it) { |
| if (isBackwards) { |
| it = new FsIterator_backwards<>(it); // positions the underlying iterator to last, |
| // which is first for going backwards |
| } |
| return it; |
| } |
| |
| private LowLevelIterator<T> altSourceIterator() { |
| T[] filtered; |
| if (sourceFSList != null) { |
| List<T> filteredItems = new ArrayList<>(); |
| FSList fsl = sourceFSList; |
| while (!(fsl instanceof EmptyFSList)) { |
| NonEmptyFSList nefsl = (NonEmptyFSList) fsl; |
| T item = (T) nefsl.getHead(); |
| if ((isNullOK || null != item) && ti.subsumes((TypeImpl) item.getType())) { |
| filteredItems.add(item); |
| } |
| fsl = nefsl.getTail(); |
| } |
| filtered = filteredItems |
| .toArray((T[]) Array.newInstance(FeatureStructure.class, filteredItems.size())); |
| } else { |
| |
| // skip filtering if nullOK and no subsumption test needed because type = TOP or higher |
| boolean noTypeFilter = ti == view.getTypeSystemImpl().topType; |
| if (!isNullOK && noTypeFilter) { |
| return new FsIterator_subtypes_snapshot<>((T[]) sourceFSArray, null, IS_UNORDERED, null); |
| } |
| |
| List<T> filteredItems = new ArrayList<>(); |
| boolean noNullsWereFiltered = true; |
| for (FeatureStructure item : sourceFSArray) { |
| if (!isNullOK && null == item) { |
| noNullsWereFiltered = false; |
| continue; // null items may be skipped |
| } |
| |
| if (noTypeFilter || ti.subsumes((TypeImpl) item.getType())) { |
| filteredItems.add((T) item); |
| } |
| } |
| |
| if (noTypeFilter && !noNullsWereFiltered) { |
| return new FsIterator_subtypes_snapshot<>((T[]) sourceFSArray, null, IS_UNORDERED, null); |
| } |
| |
| filtered = filteredItems |
| .toArray((T[]) Array.newInstance(FeatureStructure.class, filteredItems.size())); |
| } |
| return new FsIterator_subtypes_snapshot<>(filtered, null, IS_UNORDERED, null); // items not |
| // sorted |
| } |
| |
| @Override |
| 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 ArrayList<T> asList() { |
| return asArrayList((LowLevelIterator<T>) fsIterator()); |
| } |
| |
| private ArrayList<T> asArrayList(LowLevelIterator<T> it) { |
| ArrayList<T> al = new ArrayList<>(); |
| it.getArrayList(al); |
| return al; |
| } |
| |
| /* |
| * (non-Javadoc) |
| * |
| * @see org.apache.uima.cas.SelectFSs#asArray() |
| */ |
| @Override |
| public T[] asArray(Class<? super T> clazz) { |
| return asArray((LowLevelIterator<T>) fsIterator(), clazz); |
| } |
| |
| /** |
| * This is a terminal operation, so can use/modify the original iterator |
| * |
| * @param it |
| * the iterator positioned at the start position |
| * @param clazz |
| * the class of the result |
| * @return an array of elements from the position to the end |
| */ |
| private T[] asArray(LowLevelIterator<T> it, Class<? super T> clazz) { |
| // can't use the iterator's getArray method, because that returns the entire |
| // array, starting from the first position thru the last position, |
| // and the iterator might have been positioned other than the starting spot |
| // by a following or startAt etc. |
| |
| ArrayList<T> a = asArrayList(it); |
| T[] r = (T[]) Array.newInstance(clazz, a.size()); |
| return a.toArray(r); |
| } |
| |
| // private T[] asArray(LowLevelIterator<T> it) { |
| // return asArray(it, (Class<? super T>) ((TypeImpl)it.getType()).javaClass); |
| // } |
| |
| private Annotation makePosAnnot(int begin, int end) { |
| return _createMarkerAnnotation(jcas, begin, end); |
| } |
| |
| //@formatter:off |
| /** |
| * Iterator respects backwards |
| * |
| * Sets the characteristics from the context: |
| * IMMUTABLE / NONNULL / DISTINCT - always |
| * CONCURRENT - never |
| * ORDERED - unless orderNotNeeded index or not SORTED_INDEX or SET_INDEX |
| * SORTED - only for SORTED_INDEX (and not orderNotNeeded?) |
| * SIZED - if exact size is (easily) known, just from index. |
| * false if bounded, unambiguous |
| * SUBSIZED - if spliterator result from trysplit also is SIZED, set to true for now |
| * |
| * trySplit impl: |
| * always returns null (no parallelism support for now) |
| * @return the spliterator |
| */ |
| //@formatter:on |
| @Override |
| public Spliterator<T> spliterator() { |
| return new Spliterator<T>() { |
| |
| private final FSIterator<T> it = fsIterator(); |
| |
| private final FSIndex<T> localIndex = index; |
| |
| private final Comparator<? super T> comparator = (localIndex != null |
| && localIndex.getIndexingStrategy() == FSIndex.SORTED_INDEX) |
| ? (Comparator<? super T>) localIndex |
| : null; |
| |
| private final int characteristics; |
| { // set the characteristics and comparator |
| // always set |
| int c = Spliterator.IMMUTABLE | Spliterator.NONNULL | Spliterator.DISTINCT; |
| |
| if (!isAltSource && boundsUse == BoundsUse.notBounded && !isNonOverlapping) { |
| c |= Spliterator.SIZED | Spliterator.SUBSIZED; |
| } |
| |
| // set per indexing strategy |
| switch ((null == localIndex) ? -1 : localIndex.getIndexingStrategy()) { |
| case FSIndex.SORTED_INDEX: |
| c |= Spliterator.ORDERED | Spliterator.SORTED; |
| break; |
| case FSIndex.SET_INDEX: |
| c |= Spliterator.ORDERED; |
| break; |
| default: // do nothing |
| } |
| |
| characteristics = c; |
| } |
| |
| @Override |
| public boolean tryAdvance(Consumer<? super T> action) { |
| if (it.isValid()) { |
| action.accept(it.getNvc()); |
| incr(it); |
| return true; |
| } |
| return false; |
| } |
| |
| @Override |
| public Spliterator<T> trySplit() { |
| // return null for now |
| // could implement something based on type of fsIterator. |
| return null; |
| } |
| |
| @Override |
| public long estimateSize() { |
| return ((characteristics & Spliterator.SIZED) == Spliterator.SIZED && localIndex != null) |
| ? localIndex.size() |
| : Long.MAX_VALUE; |
| } |
| |
| @Override |
| public int characteristics() { |
| return characteristics; |
| } |
| |
| @Override |
| public Comparator<? super T> getComparator() { |
| if (comparator != null) { |
| return comparator; |
| } |
| if ((characteristics & Spliterator.SORTED) == Spliterator.SORTED) { |
| return null; |
| } |
| throw new IllegalStateException(); |
| } |
| }; |
| } |
| |
| /* |
| * returns the item the select is pointing to, or null if nullOK(false) then throws on null |
| * (non-Javadoc) |
| * |
| * @see org.apache.uima.cas.SelectFSs#get() |
| */ |
| @Override |
| public T get() { |
| return getNullChk(); |
| } |
| |
| private T getNullChk() { |
| FSIterator<T> it = fsIterator(); |
| if (it.isValid()) { |
| return it.getNvc(); |
| } |
| if (!isNullOK) { // if not specified, isNullOK == false |
| throw new CASRuntimeException(CASRuntimeException.SELECT_GET_NO_INSTANCES, ti.getName(), |
| maybeMsgPosition()); |
| } |
| return null; |
| |
| } |
| |
| /* |
| * like get() but throws if more than one item (non-Javadoc) |
| * |
| * @see org.apache.uima.cas.SelectFSs#single() |
| */ |
| @Override |
| public T single() { |
| T v = singleOrNull(); |
| if (v == null && !isNullOK) { |
| throw new CASRuntimeException(CASRuntimeException.SELECT_GET_NO_INSTANCES, ti.getName(), |
| maybeMsgPosition()); |
| } |
| return v; |
| } |
| |
| /* |
| * like get() but throws if more than 1 item, always OK to return null if none (non-Javadoc) |
| * |
| * @see org.apache.uima.cas.SelectFSs#singleOrNull() |
| */ |
| @Override |
| public T singleOrNull() { |
| FSIterator<T> it = fsIterator(); |
| if (it.isValid()) { |
| T v = it.getNvc(); |
| if (shift >= 0) { |
| it.moveToNext(); |
| } else { |
| it.moveToPrevious(); |
| } |
| if (it.isValid()) { |
| throw new CASRuntimeException(CASRuntimeException.SELECT_GET_TOO_MANY_INSTANCES, |
| ti.getName(), maybeMsgPosition()); |
| } |
| return v; |
| } |
| return null; |
| } |
| |
| @Override |
| public T get(int offset) { |
| shift = offset; |
| return getNullChk(); |
| } |
| |
| @Override |
| public T single(int offset) { |
| shift = offset; |
| return single(); |
| } |
| |
| @Override |
| public T singleOrNull(int offset) { |
| shift = offset; |
| return singleOrNull(); |
| } |
| |
| @Override |
| public T get(TOP fs) { |
| startAt(fs); |
| return getNullChk(); |
| } |
| |
| @Override |
| public T get(FeatureStructure fs) { |
| startAt(fs); |
| return getNullChk(); |
| } |
| |
| @Override |
| public T single(TOP fs) { |
| startAt(fs); |
| return single(); |
| } |
| |
| @Override |
| public T single(FeatureStructure fs) { |
| startAt(fs); |
| return single(); |
| } |
| |
| @Override |
| public T singleOrNull(TOP fs) { |
| startAt(fs); |
| return singleOrNull(); |
| } |
| |
| @Override |
| public T singleOrNull(FeatureStructure fs) { |
| startAt(fs); |
| return singleOrNull(); |
| } |
| |
| @Override |
| public T get(TOP fs, int offset) { |
| startAt(fs, offset); |
| return getNullChk(); |
| } |
| |
| @Override |
| public T get(FeatureStructure fs, int offset) { |
| startAt(fs, offset); |
| return getNullChk(); |
| } |
| |
| @Override |
| public T single(TOP fs, int offset) { |
| startAt(fs, offset); |
| return single(); |
| } |
| |
| @Override |
| public T single(FeatureStructure fs, int offset) { |
| startAt(fs, offset); |
| return single(); |
| } |
| |
| @Override |
| public T singleOrNull(TOP fs, int offset) { |
| startAt(fs, offset); |
| return singleOrNull(); |
| } |
| |
| @Override |
| public T singleOrNull(FeatureStructure fs, int offset) { |
| startAt(fs, offset); |
| return singleOrNull(); |
| } |
| |
| @Override |
| public T get(int begin, int end) { |
| startAt(begin, end); |
| return getNullChk(); |
| } |
| |
| @Override |
| public T single(int begin, int end) { |
| startAt(begin, end); |
| return single(); |
| } |
| |
| @Override |
| public T singleOrNull(int begin, int end) { |
| startAt(begin, end); |
| return singleOrNull(); |
| } |
| |
| @Override |
| public T get(int begin, int end, int offset) { |
| startAt(begin, end, offset); |
| return getNullChk(); |
| } |
| |
| @Override |
| public T single(int begin, int end, int offset) { |
| startAt(begin, end, offset); |
| return single(); |
| } |
| |
| @Override |
| public T singleOrNull(int begin, int end, int offset) { |
| startAt(begin, end, offset); |
| return singleOrNull(); |
| } |
| |
| //@formatter:off |
| /** |
| * works for AnnotationIndex or general index |
| * |
| * position taken from startingFs (not necessarily an Annotation subtype) |
| * - goes to left-most "equal" using comparator, or if none equal, to the first one > startingFs |
| * -- using moveTo(fs) |
| * |
| * special processing for AnnotationIndex (only): |
| * - typePriority - use or ignore |
| * -- ignored: after moveTo(fs), moveToPrevious while begin and end == |
| * // REMOVED see https://issues.apache.org/jira/browse/UIMA-5536 --- and if isPositionUsesType types are == |
| * @param it iterator to position |
| * @return it positioned if needed |
| */ |
| //@formatter:on |
| private FSIterator<T> maybePosition(FSIterator<T> it) { |
| if (!it.isValid() || startingFs == null || boundsUse != BoundsUse.notBounded) { |
| return it; |
| } |
| |
| if (isFollowing) { |
| Annotation start = (Annotation) startingFs; |
| if (start.getBegin() == start.getEnd()) { |
| // We cannot moveTo(startingFS) because if startingFS has zero-width, then we would |
| // end up positioning the iterator after a non-zero-width annotation which would be |
| // considered to follow the startingFS. |
| // Example: |
| // [83,83] startingFS |
| // [83,84] annotation that should be considered following the startingFS |
| // but [83,84] comes *AFTER* [83,83] in index iteration order! |
| it.moveTo(makePosAnnot(start.getBegin(), Integer.MAX_VALUE)); |
| } else { |
| it.moveTo(startingFs); |
| |
| final int begin = ((Annotation) startingFs).getBegin(); |
| final int end = ((Annotation) startingFs).getEnd(); |
| while (it.isValid()) { |
| int aBegin = ((Annotation) it.get()).getBegin(); |
| if (aBegin >= end && aBegin != begin) { |
| break; |
| } |
| it.moveToNext(); |
| } |
| } |
| } else if (isPreceding) { |
| Annotation start = (Annotation) startingFs; |
| |
| // A zero-width annotation will appear *after* a non-zero width annotation in the index, so |
| // if we simply seek to a non-zero-width startingFs, we might miss a zero-width annotation |
| // occurring at the beginning of startingFs. So instead, we seek to a zero-width position |
| // at the begin of the startingFs and leave the rest to the filtering iterator we use for |
| // preceding selection. |
| // it.moveTo(startingFs); |
| it.moveTo(makePosAnnot(start.getBegin(), start.getBegin())); |
| |
| final int begin = start.getBegin(); |
| while (it.isValid() && ((Annotation) it.get()).getEnd() > begin) { |
| it.moveToPrevious(); |
| } |
| } else { |
| it.moveTo(startingFs); |
| } |
| |
| return it; |
| } |
| |
| private FSIterator<T> maybeShift(FSIterator<T> it) { |
| if (shift != 0) { |
| int ps = Math.abs(shift); |
| |
| for (int i = 0; i < ps; i++) { |
| if (shift < 0) { |
| it.moveToPrevious(); |
| } else { |
| it.moveToNext(); |
| } |
| } |
| } |
| |
| return it; |
| } |
| |
| private LowLevelIterator<T> maybeLimit(LowLevelIterator<T> it) { |
| return (limit == -1) ? it : new FsIterator_limited<>(it, limit); |
| } |
| |
| // ******************************************* |
| // The methods below are alternatives |
| // to the methods above, that combine |
| // frequently used patterns into more |
| // concise forms using positional arguments |
| // ******************************************* |
| |
| /* |
| * (non-Javadoc) |
| * |
| * @see org.apache.uima.cas.SelectFSs#following(org.apache.uima.jcas.cas.TOP) |
| */ |
| @Override |
| public SelectFSs<T> following(Annotation fs) { |
| return following(fs, 0); |
| } |
| |
| /* |
| * (non-Javadoc) |
| * |
| * @see org.apache.uima.cas.SelectFSs#following(int, int) |
| */ |
| @Override |
| public SelectFSs<T> following(int position) { |
| return following(position, 0); |
| } |
| |
| /* |
| * (non-Javadoc) |
| * |
| * @see org.apache.uima.cas.SelectFSs#following(org.apache.uima.jcas.cas.TOP, int) |
| */ |
| @Override |
| public SelectFSs<T> following(Annotation fs, int offset) { |
| return commonFollowing(fs, offset); |
| } |
| |
| /* |
| * (non-Javadoc) |
| * |
| * @see org.apache.uima.cas.SelectFSs#following(int, int, int) |
| */ |
| @Override |
| public SelectFSs<T> following(int position, int offset) { |
| return commonFollowing(makePosAnnot(position, position), offset); |
| } |
| |
| /* |
| * (non-Javadoc) |
| * |
| * @see org.apache.uima.cas.SelectFSs#preceding(org.apache.uima.jcas.cas.TOP) |
| */ |
| @Override |
| public SelectFSs<T> preceding(Annotation fs) { |
| return preceding(fs, 0); |
| } |
| |
| /* |
| * (non-Javadoc) |
| * |
| * @see org.apache.uima.cas.SelectFSs#preceding(int, int) |
| */ |
| @Override |
| public SelectFSs<T> preceding(int position) { |
| return preceding(position, 0); |
| } |
| |
| /* |
| * (non-Javadoc) |
| * |
| * @see org.apache.uima.cas.SelectFSs#preceding(org.apache.uima.jcas.cas.TOP, int) |
| */ |
| @Override |
| public SelectFSs<T> preceding(Annotation annotation, int offset) { |
| return commonPreceding(annotation, offset); |
| } |
| |
| /* |
| * (non-Javadoc) |
| * |
| * @see org.apache.uima.cas.SelectFSs#preceding(int, int, int) |
| */ |
| @Override |
| public SelectFSs<T> preceding(int position, int offset) { |
| return commonPreceding(makePosAnnot(position, Integer.MAX_VALUE), offset); |
| } |
| |
| /************************ |
| * NOT USED |
| */ |
| // public SelectFSs_impl<T> sameBeginEnd() { // AI |
| // boundsUse = BoundsUse.sameBeginEnd; |
| // return this; |
| // } |
| |
| //@formatter:off |
| /** |
| * validations |
| * isAnnotationIndex => startingFs is Annotation |
| * isAllViews: doesn't support startAt, coveredBy and friends, backwards |
| * isAllViews: supports limit, shift |
| */ |
| //@formatter:on |
| // private void validateSinglePosition(TOP fs, int offset) { |
| // if (startingFs != null) { |
| // /* Select - multiple starting positions not allowed */ |
| // throw CASRuntimeException(CASRuntimeException.); |
| // } |
| // startingFs = fs; |
| // |
| // if (offset != 0) { |
| // if (shift != 0) { |
| // /* Select - multiple offset shifting not allowed */ |
| // throw CASRuntimeException(CASRuntimeException.); |
| // } |
| // shift = offset; |
| // } |
| // } |
| |
| private SelectFSs<T> commonFollowing(Annotation annotation, int offset) { |
| startingFs = annotation; |
| shift = offset; |
| isFollowing = true; |
| return this; |
| } |
| |
| private SelectFSs<T> commonPreceding(Annotation annotation, int offset) { |
| // validateSinglePosition(fs, offset); |
| startingFs = annotation; |
| shift = offset; |
| isPreceding = true; |
| return this; |
| } |
| |
| private void forceAnnotationIndex() { |
| if (index == null) { |
| index = (LowLevelIndex<T>) ((ti == null) ? view.getAnnotationIndex() |
| : view.getAnnotationIndex(ti)); |
| } else { |
| if (!(index instanceof AnnotationIndex)) { |
| /** Index "{0}" must be an AnnotationIndex. */ |
| throw new CASRuntimeException(CASRuntimeException.ANNOTATION_INDEX_REQUIRED, index); |
| } |
| } |
| } |
| |
| private Stream<T> stream() { |
| return StreamSupport.stream(spliterator(), false); // false = default not parallel |
| } |
| |
| //@formatter:off |
| /* *************************************** |
| * S T R E A M methods |
| * these convert the result to a stream and apply the method |
| */ |
| //@formatter:on |
| @Override |
| public Stream<T> filter(Predicate<? super T> predicate) { |
| return stream().filter(predicate); |
| } |
| |
| @Override |
| public <R> Stream<R> map(Function<? super T, ? extends R> mapper) { |
| return stream().map(mapper); |
| } |
| |
| @Override |
| public IntStream mapToInt(ToIntFunction<? super T> mapper) { |
| return stream().mapToInt(mapper); |
| } |
| |
| @Override |
| public LongStream mapToLong(ToLongFunction<? super T> mapper) { |
| return stream().mapToLong(mapper); |
| } |
| |
| @Override |
| public DoubleStream mapToDouble(ToDoubleFunction<? super T> mapper) { |
| return stream().mapToDouble(mapper); |
| } |
| |
| @Override |
| public <R> Stream<R> flatMap(Function<? super T, ? extends Stream<? extends R>> mapper) { |
| return stream().flatMap(mapper); |
| } |
| |
| @Override |
| public IntStream flatMapToInt(Function<? super T, ? extends IntStream> mapper) { |
| return stream().flatMapToInt(mapper); |
| } |
| |
| @Override |
| public LongStream flatMapToLong(Function<? super T, ? extends LongStream> mapper) { |
| return stream().flatMapToLong(mapper); |
| } |
| |
| @Override |
| public DoubleStream flatMapToDouble(Function<? super T, ? extends DoubleStream> mapper) { |
| return stream().flatMapToDouble(mapper); |
| } |
| |
| @Override |
| public Stream<T> distinct() { |
| return stream().distinct(); |
| } |
| |
| @Override |
| public Stream<T> sorted() { |
| return stream().sorted(); |
| } |
| |
| @Override |
| public Stream<T> sorted(Comparator<? super T> comparator) { |
| return stream().sorted(comparator); |
| } |
| |
| @Override |
| public Stream<T> peek(Consumer<? super T> action) { |
| return stream().peek(action); |
| } |
| |
| @Override |
| public Stream<T> limit(long maxSize) { |
| return stream().limit(maxSize); |
| } |
| |
| @Override |
| public Stream<T> skip(long n) { |
| return stream().skip(n); |
| } |
| |
| @Override |
| public void forEach(Consumer<? super T> action) { |
| stream().forEach(action); |
| } |
| |
| @Override |
| public void forEachOrdered(Consumer<? super T> action) { |
| stream().forEachOrdered(action); |
| } |
| |
| @Override |
| public Object[] toArray() { |
| return stream().toArray(); |
| } |
| |
| @Override |
| public <A> A[] toArray(IntFunction<A[]> generator) { |
| return stream().toArray(generator); |
| } |
| |
| @Override |
| public T reduce(T identity, BinaryOperator<T> accumulator) { |
| return stream().reduce(identity, accumulator); |
| } |
| |
| @Override |
| public Optional<T> reduce(BinaryOperator<T> accumulator) { |
| return stream().reduce(accumulator); |
| } |
| |
| @Override |
| public <U> U reduce(U identity, BiFunction<U, ? super T, U> accumulator, |
| BinaryOperator<U> combiner) { |
| return stream().reduce(identity, accumulator, combiner); |
| } |
| |
| @Override |
| public <R> R collect(Supplier<R> supplier, BiConsumer<R, ? super T> accumulator, |
| BiConsumer<R, R> combiner) { |
| return stream().collect(supplier, accumulator, combiner); |
| } |
| |
| @Override |
| public <R, A> R collect(Collector<? super T, A, R> collector) { |
| return stream().collect(collector); |
| } |
| |
| @Override |
| public Optional<T> min(Comparator<? super T> comparator) { |
| return stream().min(comparator); |
| } |
| |
| @Override |
| public Optional<T> max(Comparator<? super T> comparator) { |
| return stream().max(comparator); |
| } |
| |
| @Override |
| public long count() { |
| return stream().count(); |
| } |
| |
| @Override |
| public boolean anyMatch(Predicate<? super T> predicate) { |
| return stream().anyMatch(predicate); |
| } |
| |
| @Override |
| public boolean allMatch(Predicate<? super T> predicate) { |
| return stream().allMatch(predicate); |
| } |
| |
| @Override |
| public boolean noneMatch(Predicate<? super T> predicate) { |
| return stream().noneMatch(predicate); |
| } |
| |
| @Override |
| public Optional<T> findFirst() { |
| return stream().findFirst(); |
| } |
| |
| @Override |
| public Optional<T> findAny() { |
| return stream().findAny(); |
| } |
| |
| @Override |
| public boolean isParallel() { |
| return stream().isParallel(); |
| } |
| |
| @Override |
| public Stream<T> sequential() { |
| return stream().sequential(); |
| } |
| |
| @Override |
| public Stream<T> parallel() { |
| return stream().parallel(); |
| } |
| |
| @Override |
| public Stream<T> onClose(Runnable closeHandler) { |
| return stream().onClose(closeHandler); |
| } |
| |
| @Override |
| public void close() { |
| // SelectFSs_impl holds no resources that would need to be cleaned up |
| } |
| |
| @Override |
| public Stream<T> unordered() { |
| return stream().unordered(); |
| } |
| |
| @Override |
| public boolean isEmpty() { |
| if (limit == 0) { |
| return true; |
| } |
| return fsIterator().size() == 0; |
| } |
| |
| private final class SelectFSIterator implements LowLevelIterator<T> { |
| |
| private Supplier<LowLevelIterator<T>> iteratorSupplier; |
| private LowLevelIterator<T> it; |
| |
| private SelectFSIterator(Supplier<LowLevelIterator<T>> aIteratorSupplier) { |
| iteratorSupplier = aIteratorSupplier; |
| |
| it = iteratorSupplier.get(); |
| } |
| |
| @Override |
| public boolean isValid() { |
| return it.isValid(); |
| } |
| |
| @Override |
| public T getNvc() { |
| return it.getNvc(); |
| } |
| |
| @Override |
| public void moveToNextNvc() { |
| it.moveToNextNvc(); |
| } |
| |
| @Override |
| public void moveToPreviousNvc() { |
| it.moveToPreviousNvc(); |
| } |
| |
| @Override |
| public void moveToFirst() { |
| // There is quite a bit of logic in SelectFS that happens *after* the iterator has been |
| // created using fsIterator1() that positions the iterator at the starting position required |
| // by the SelectFS settings. In order to avoid having to duplicate that repositioning code, |
| // we just make a new iterator here. |
| it = iteratorSupplier.get(); |
| } |
| |
| @Override |
| public void moveToLast() { |
| it.moveToLast(); |
| } |
| |
| @Override |
| public void moveTo(FeatureStructure aFs) { |
| it.moveTo(aFs); |
| } |
| |
| @Override |
| public FSIterator<T> copy() { |
| return it.copy(); |
| } |
| |
| @Override |
| public int ll_indexSizeMaybeNotCurrent() { |
| return it.ll_indexSizeMaybeNotCurrent(); |
| } |
| |
| @Override |
| public LowLevelIndex<T> ll_getIndex() { |
| return it.ll_getIndex(); |
| } |
| |
| @Override |
| public int ll_maxAnnotSpan() { |
| return it.ll_maxAnnotSpan(); |
| } |
| |
| @Override |
| public boolean isIndexesHaveBeenUpdated() { |
| return it.isIndexesHaveBeenUpdated(); |
| } |
| |
| @Override |
| public boolean maybeReinitIterator() { |
| return it.maybeReinitIterator(); |
| } |
| |
| @Override |
| public void moveToFirstNoReinit() { |
| moveToFirst(); |
| } |
| |
| @Override |
| public void moveToLastNoReinit() { |
| it.moveToLastNoReinit(); |
| } |
| |
| @Override |
| public void moveToNoReinit(FeatureStructure aFs) { |
| it.moveToNoReinit(aFs); |
| } |
| |
| @Override |
| public Comparator<TOP> getComparator() { |
| return it.getComparator(); |
| } |
| } |
| } |