< prev index next >

src/java.base/share/classes/java/util/stream/FindOps.java

Print this page




  90      *        first element in the encounter order
  91      * @return a {@code TerminalOp} implementing the find operation
  92      */
  93     public static TerminalOp<Double, OptionalDouble> makeDouble(boolean mustFindFirst) {
  94         return new FindOp<>(mustFindFirst, StreamShape.DOUBLE_VALUE, OptionalDouble.empty(),
  95                             OptionalDouble::isPresent, FindSink.OfDouble::new);
  96     }
  97 
  98     /**
  99      * A short-circuiting {@code TerminalOp} that searches for an element in a
 100      * stream pipeline, and terminates when it finds one.  Implements both
 101      * find-first (find the first element in the encounter order) and find-any
 102      * (find any element, may not be the first in encounter order.)
 103      *
 104      * @param <T> the output type of the stream pipeline
 105      * @param <O> the result type of the find operation, typically an optional
 106      *        type
 107      */
 108     private static final class FindOp<T, O> implements TerminalOp<T, O> {
 109         private final StreamShape shape;
 110         final boolean mustFindFirst;
 111         final O emptyValue;
 112         final Predicate<O> presentPredicate;
 113         final Supplier<TerminalSink<T, O>> sinkSupplier;
 114 
 115         /**
 116          * Constructs a {@code FindOp}.
 117          *
 118          * @param mustFindFirst if true, must find the first element in
 119          *        encounter order, otherwise can find any element
 120          * @param shape stream shape of elements to search
 121          * @param emptyValue result value corresponding to "found nothing"
 122          * @param presentPredicate {@code Predicate} on result value
 123          *        corresponding to "found something"
 124          * @param sinkSupplier supplier for a {@code TerminalSink} implementing
 125          *        the matching functionality
 126          */
 127         FindOp(boolean mustFindFirst,
 128                        StreamShape shape,
 129                        O emptyValue,
 130                        Predicate<O> presentPredicate,
 131                        Supplier<TerminalSink<T, O>> sinkSupplier) {
 132             this.mustFindFirst = mustFindFirst;
 133             this.shape = shape;
 134             this.emptyValue = emptyValue;
 135             this.presentPredicate = presentPredicate;
 136             this.sinkSupplier = sinkSupplier;
 137         }
 138 
 139         @Override
 140         public int getOpFlags() {
 141             return StreamOpFlag.IS_SHORT_CIRCUIT | (mustFindFirst ? 0 : StreamOpFlag.NOT_ORDERED);
 142         }
 143 
 144         @Override
 145         public StreamShape inputShape() {
 146             return shape;
 147         }
 148 
 149         @Override
 150         public <S> O evaluateSequential(PipelineHelper<T> helper,
 151                                         Spliterator<S> spliterator) {
 152             O result = helper.wrapAndCopyInto(sinkSupplier.get(), spliterator).get();
 153             return result != null ? result : emptyValue;
 154         }
 155 
 156         @Override
 157         public <P_IN> O evaluateParallel(PipelineHelper<T> helper,
 158                                          Spliterator<P_IN> spliterator) {
 159             return new FindTask<>(this, helper, spliterator).invoke();



 160         }
 161     }
 162 
 163     /**
 164      * Implementation of @{code TerminalSink} that implements the find
 165      * functionality, requesting cancellation when something has been found
 166      *
 167      * @param <T> The type of input element
 168      * @param <O> The result type, typically an optional type
 169      */
 170     private abstract static class FindSink<T, O> implements TerminalSink<T, O> {
 171         boolean hasValue;
 172         T value;
 173 
 174         FindSink() {} // Avoid creation of special accessor
 175 
 176         @Override
 177         public void accept(T value) {
 178             if (!hasValue) {
 179                 hasValue = true;


 233                 accept((Double) value);
 234             }
 235 
 236             @Override
 237             public OptionalDouble get() {
 238                 return hasValue ? OptionalDouble.of(value) : null;
 239             }
 240         }
 241     }
 242 
 243     /**
 244      * {@code ForkJoinTask} implementing parallel short-circuiting search
 245      * @param <P_IN> Input element type to the stream pipeline
 246      * @param <P_OUT> Output element type from the stream pipeline
 247      * @param <O> Result type from the find operation
 248      */
 249     @SuppressWarnings("serial")
 250     private static final class FindTask<P_IN, P_OUT, O>
 251             extends AbstractShortCircuitTask<P_IN, P_OUT, O, FindTask<P_IN, P_OUT, O>> {
 252         private final FindOp<P_OUT, O> op;

 253 
 254         FindTask(FindOp<P_OUT, O> op,

 255                  PipelineHelper<P_OUT> helper,
 256                  Spliterator<P_IN> spliterator) {
 257             super(helper, spliterator);

 258             this.op = op;
 259         }
 260 
 261         FindTask(FindTask<P_IN, P_OUT, O> parent, Spliterator<P_IN> spliterator) {
 262             super(parent, spliterator);

 263             this.op = parent.op;
 264         }
 265 
 266         @Override
 267         protected FindTask<P_IN, P_OUT, O> makeChild(Spliterator<P_IN> spliterator) {
 268             return new FindTask<>(this, spliterator);
 269         }
 270 
 271         @Override
 272         protected O getEmptyResult() {
 273             return op.emptyValue;
 274         }
 275 
 276         private void foundResult(O answer) {
 277             if (isLeftmostNode())
 278                 shortCircuit(answer);
 279             else
 280                 cancelLaterNodes();
 281         }
 282 
 283         @Override
 284         protected O doLeaf() {
 285             O result = helper.wrapAndCopyInto(op.sinkSupplier.get(), spliterator).get();
 286             if (!op.mustFindFirst) {
 287                 if (result != null)
 288                     shortCircuit(result);
 289                 return null;
 290             }
 291             else {
 292                 if (result != null) {
 293                     foundResult(result);
 294                     return result;
 295                 }
 296                 else
 297                     return null;
 298             }
 299         }
 300 
 301         @Override
 302         public void onCompletion(CountedCompleter<?> caller) {
 303             if (op.mustFindFirst) {
 304                     for (FindTask<P_IN, P_OUT, O> child = leftChild, p = null; child != p;
 305                          p = child, child = rightChild) {
 306                     O result = child.getLocalResult();
 307                     if (result != null && op.presentPredicate.test(result)) {
 308                         setLocalResult(result);
 309                         foundResult(result);
 310                         break;
 311                     }
 312                 }
 313             }
 314             super.onCompletion(caller);
 315         }
 316     }
 317 }
 318 


  90      *        first element in the encounter order
  91      * @return a {@code TerminalOp} implementing the find operation
  92      */
  93     public static TerminalOp<Double, OptionalDouble> makeDouble(boolean mustFindFirst) {
  94         return new FindOp<>(mustFindFirst, StreamShape.DOUBLE_VALUE, OptionalDouble.empty(),
  95                             OptionalDouble::isPresent, FindSink.OfDouble::new);
  96     }
  97 
  98     /**
  99      * A short-circuiting {@code TerminalOp} that searches for an element in a
 100      * stream pipeline, and terminates when it finds one.  Implements both
 101      * find-first (find the first element in the encounter order) and find-any
 102      * (find any element, may not be the first in encounter order.)
 103      *
 104      * @param <T> the output type of the stream pipeline
 105      * @param <O> the result type of the find operation, typically an optional
 106      *        type
 107      */
 108     private static final class FindOp<T, O> implements TerminalOp<T, O> {
 109         private final StreamShape shape;
 110         final int opFlags;
 111         final O emptyValue;
 112         final Predicate<O> presentPredicate;
 113         final Supplier<TerminalSink<T, O>> sinkSupplier;
 114 
 115         /**
 116          * Constructs a {@code FindOp}.
 117          *
 118          * @param mustFindFirst if true, must find the first element in
 119          *        encounter order, otherwise can find any element
 120          * @param shape stream shape of elements to search
 121          * @param emptyValue result value corresponding to "found nothing"
 122          * @param presentPredicate {@code Predicate} on result value
 123          *        corresponding to "found something"
 124          * @param sinkSupplier supplier for a {@code TerminalSink} implementing
 125          *        the matching functionality
 126          */
 127         FindOp(boolean mustFindFirst,
 128                        StreamShape shape,
 129                        O emptyValue,
 130                        Predicate<O> presentPredicate,
 131                        Supplier<TerminalSink<T, O>> sinkSupplier) {
 132             this.opFlags = StreamOpFlag.IS_SHORT_CIRCUIT | (mustFindFirst ? 0 : StreamOpFlag.NOT_ORDERED);
 133             this.shape = shape;
 134             this.emptyValue = emptyValue;
 135             this.presentPredicate = presentPredicate;
 136             this.sinkSupplier = sinkSupplier;
 137         }
 138 
 139         @Override
 140         public int getOpFlags() {
 141             return opFlags;
 142         }
 143 
 144         @Override
 145         public StreamShape inputShape() {
 146             return shape;
 147         }
 148 
 149         @Override
 150         public <S> O evaluateSequential(PipelineHelper<T> helper,
 151                                         Spliterator<S> spliterator) {
 152             O result = helper.wrapAndCopyInto(sinkSupplier.get(), spliterator).get();
 153             return result != null ? result : emptyValue;
 154         }
 155 
 156         @Override
 157         public <P_IN> O evaluateParallel(PipelineHelper<T> helper,
 158                                          Spliterator<P_IN> spliterator) {
 159             // This takes into account the upstream ops flags and the terminal
 160             // op flags and therefore takes into account findFirst or findAny
 161             boolean mustFindFirst = StreamOpFlag.ORDERED.isKnown(helper.getStreamAndOpFlags());
 162             return new FindTask<>(this, mustFindFirst, helper, spliterator).invoke();
 163         }
 164     }
 165 
 166     /**
 167      * Implementation of @{code TerminalSink} that implements the find
 168      * functionality, requesting cancellation when something has been found
 169      *
 170      * @param <T> The type of input element
 171      * @param <O> The result type, typically an optional type
 172      */
 173     private abstract static class FindSink<T, O> implements TerminalSink<T, O> {
 174         boolean hasValue;
 175         T value;
 176 
 177         FindSink() {} // Avoid creation of special accessor
 178 
 179         @Override
 180         public void accept(T value) {
 181             if (!hasValue) {
 182                 hasValue = true;


 236                 accept((Double) value);
 237             }
 238 
 239             @Override
 240             public OptionalDouble get() {
 241                 return hasValue ? OptionalDouble.of(value) : null;
 242             }
 243         }
 244     }
 245 
 246     /**
 247      * {@code ForkJoinTask} implementing parallel short-circuiting search
 248      * @param <P_IN> Input element type to the stream pipeline
 249      * @param <P_OUT> Output element type from the stream pipeline
 250      * @param <O> Result type from the find operation
 251      */
 252     @SuppressWarnings("serial")
 253     private static final class FindTask<P_IN, P_OUT, O>
 254             extends AbstractShortCircuitTask<P_IN, P_OUT, O, FindTask<P_IN, P_OUT, O>> {
 255         private final FindOp<P_OUT, O> op;
 256         private final boolean mustFindFirst;
 257 
 258         FindTask(FindOp<P_OUT, O> op,
 259                  boolean mustFindFirst,
 260                  PipelineHelper<P_OUT> helper,
 261                  Spliterator<P_IN> spliterator) {
 262             super(helper, spliterator);
 263             this.mustFindFirst = mustFindFirst;
 264             this.op = op;
 265         }
 266 
 267         FindTask(FindTask<P_IN, P_OUT, O> parent, Spliterator<P_IN> spliterator) {
 268             super(parent, spliterator);
 269             this.mustFindFirst = parent.mustFindFirst;
 270             this.op = parent.op;
 271         }
 272 
 273         @Override
 274         protected FindTask<P_IN, P_OUT, O> makeChild(Spliterator<P_IN> spliterator) {
 275             return new FindTask<>(this, spliterator);
 276         }
 277 
 278         @Override
 279         protected O getEmptyResult() {
 280             return op.emptyValue;
 281         }
 282 
 283         private void foundResult(O answer) {
 284             if (isLeftmostNode())
 285                 shortCircuit(answer);
 286             else
 287                 cancelLaterNodes();
 288         }
 289 
 290         @Override
 291         protected O doLeaf() {
 292             O result = helper.wrapAndCopyInto(op.sinkSupplier.get(), spliterator).get();
 293             if (!this.mustFindFirst) {
 294                 if (result != null)
 295                     shortCircuit(result);
 296                 return null;
 297             }
 298             else {
 299                 if (result != null) {
 300                     foundResult(result);
 301                     return result;
 302                 }
 303                 else
 304                     return null;
 305             }
 306         }
 307 
 308         @Override
 309         public void onCompletion(CountedCompleter<?> caller) {
 310             if (this.mustFindFirst) {
 311                     for (FindTask<P_IN, P_OUT, O> child = leftChild, p = null; child != p;
 312                          p = child, child = rightChild) {
 313                     O result = child.getLocalResult();
 314                     if (result != null && op.presentPredicate.test(result)) {
 315                         setLocalResult(result);
 316                         foundResult(result);
 317                         break;
 318                     }
 319                 }
 320             }
 321             super.onCompletion(caller);
 322         }
 323     }
 324 }
 325 
< prev index next >