1 /*
2  * Copyright (c) 2012, 2017, Oracle and/or its affiliates. All rights reserved.
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * This code is free software; you can redistribute it and/or modify it
6  * under the terms of the GNU General Public License version 2 only, as
7  * published by the Free Software Foundation.  Oracle designates this
8  * particular file as subject to the "Classpath" exception as provided
9  * by Oracle in the LICENSE file that accompanied this code.
10  *
11  * This code is distributed in the hope that it will be useful, but WITHOUT
12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
14  * version 2 for more details (a copy is included in the LICENSE file that
15  * accompanied this code).
16  *
17  * You should have received a copy of the GNU General Public License version
18  * 2 along with this work; if not, write to the Free Software Foundation,
19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20  *
21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22  * or visit www.oracle.com if you need additional information or have any
23  * questions.
24  */

25 package java.util.stream;
26
27 import java.util.EnumMap;
28 import java.util.Map;
29 import java.util.Spliterator;
30
31 /**
32  * Flags corresponding to characteristics of streams and operations. Flags are
33  * utilized by the stream framework to control, specialize or optimize
34  * computation.
35  *
36  * <p>
37  * Stream flags may be used to describe characteristics of several different
38  * entities associated with streams: stream sources, intermediate operations,
39  * and terminal operations.  Not all stream flags are meaningful for all
40  * entities; the following table summarizes which flags are meaningful in what
41  * contexts:
42  *
43  * <div>
44  * <table class="borderless">
45  *   <caption>Type Characteristics</caption>
46  *   <thead class="tableSubHeadingColor">
47  *     <tr>
48  *       <th colspan="2">&nbsp;</th>
49  *       <th>{@code DISTINCT}</th>
50  *       <th>{@code SORTED}</th>
51  *       <th>{@code ORDERED}</th>
52  *       <th>{@code SIZED}</th>
53  *       <th>{@code SHORT_CIRCUIT}</th>
54  *     </tr>
55  *   </thead>
56  *   <tbody>
57  *      <tr>
58  *        <th colspan="2" class="tableSubHeadingColor">Stream source</th>
59  *        <td>Y</td>
60  *        <td>Y</td>
61  *        <td>Y</td>
62  *        <td>Y</td>
63  *        <td>N</td>
64  *      </tr>
65  *      <tr>
66  *        <th colspan="2" class="tableSubHeadingColor">Intermediate operation</th>
67  *        <td>PCI</td>
68  *        <td>PCI</td>
69  *        <td>PCI</td>
70  *        <td>PC</td>
71  *        <td>PI</td>
72  *      </tr>
73  *      <tr>
74  *        <th colspan="2" class="tableSubHeadingColor">Terminal operation</th>
75  *        <td>N</td>
76  *        <td>N</td>
77  *        <td>PC</td>
78  *        <td>N</td>
79  *        <td>PI</td>
80  *      </tr>
81  *   </tbody>
82  *   <tfoot>
83  *       <tr>
84  *         <th class="tableSubHeadingColor" colspan="2">Legend</th>
85  *         <th colspan="6" rowspan="7">&nbsp;</th>
86  *       </tr>
87  *       <tr>
88  *         <th class="tableSubHeadingColor">Flag</th>
89  *         <th class="tableSubHeadingColor">Meaning</th>
90  *         <th colspan="6"></th>
91  *       </tr>
92  *       <tr><td>Y</td><td>Allowed</td></tr>
93  *       <tr><td>N</td><td>Invalid</td></tr>
94  *       <tr><td>P</td><td>Preserves</td></tr>
95  *       <tr><td>C</td><td>Clears</td></tr>
96  *       <tr><td>I</td><td>Injects</td></tr>
97  *   </tfoot>
98  * </table>
99  * </div>
100  *
101  * <p>In the above table, "PCI" means "may preserve, clear, or inject""PC"
102  * means "may preserve or clear""PI" means "may preserve or inject", and "N"
103  * means "not valid".
104  *
105  * <p>Stream flags are represented by unioned bit sets, so that a single word
106  * may describe all the characteristics of a given stream entity, and that, for
107  * example, the flags for a stream source can be efficiently combined with the
108  * flags for later operations on that stream.
109  *
110  * <p>The bit masks {@link #STREAM_MASK}, {@link #OP_MASK}, and
111  * {@link #TERMINAL_OP_MASK} can be ANDed with a bit set of stream flags to
112  * produce a mask containing only the valid flags for that entity type.
113  *
114  * <p>When describing a stream source, one only need describe what
115  * characteristics that stream has; when describing a stream operation, one need
116  * describe whether the operation preserves, injects, or clears that
117  * characteristic.  Accordingly, two bits are used for each flag, so as to allow
118  * representing not only the presence of a characteristic, but how an
119  * operation modifies that characteristic.  There are two common forms in which
120  * flag bits are combined into an {@code int} bit set.  <em>Stream flags</em>
121  * are a unioned bit set constructed by ORing the enum characteristic values of
122  * {@link #set()} (or, more commonly, ORing the corresponding static named
123  * constants prefixed with {@code IS_}).  <em>Operation flags</em> are a unioned
124  * bit set constructed by ORing the enum characteristic values of {@link #set()}
125  * or {@link #clear()} (to inject, or clear, respectively, the corresponding
126  * flag), or more commonly ORing the corresponding named constants prefixed with
127  * {@code IS_} or {@code NOT_}.  Flags that are not marked with {@code IS_} or
128  * {@code NOT_} are implicitly treated as preserved.  Care must be taken when
129  * combining bitsets that the correct combining operations are applied in the
130  * correct order.
131  *
132  * <p>
133  * With the exception of {@link #SHORT_CIRCUIT}, stream characteristics can be
134  * derived from the equivalent {@link java.util.Spliterator} characteristics:
135  * {@link java.util.Spliterator#DISTINCT}, {@link java.util.Spliterator#SORTED},
136  * {@link java.util.Spliterator#ORDERED}, and
137  * {@link java.util.Spliterator#SIZED}.  A spliterator characteristics bit set
138  * can be converted to stream flags using the method
139  * {@link #fromCharacteristics(java.util.Spliterator)} and converted back using
140  * {@link #toCharacteristics(int)}.  (The bit set
141  * {@link #SPLITERATOR_CHARACTERISTICS_MASK} is used to AND with a bit set to
142  * produce a valid spliterator characteristics bit set that can be converted to
143  * stream flags.)
144  *
145  * <p>
146  * The source of a stream encapsulates a spliterator. The characteristics of
147  * that source spliterator when transformed to stream flags will be a proper
148  * subset of stream flags of that stream.
149  * For example:
150  * <pre> {@code
151  *     Spliterator s = ...;
152  *     Stream stream = Streams.stream(s);
153  *     flagsFromSplitr = fromCharacteristics(s.characteristics());
154  *     assert(flagsFromSplitr & stream.getStreamFlags() == flagsFromSplitr);
155  * }</pre>
156  *
157  * <p>
158  * An intermediate operation, performed on an input stream to create a new
159  * output stream, may preserve, clear or inject stream or operation
160  * characteristics.  Similarly, a terminal operation, performed on an input
161  * stream to produce an output result may preserve, clear or inject stream or
162  * operation characteristics.  Preservation means that if that characteristic
163  * is present on the input, then it is also present on the output.  Clearing
164  * means that the characteristic is not present on the output regardless of the
165  * input.  Injection means that the characteristic is present on the output
166  * regardless of the input.  If a characteristic is not cleared or injected then
167  * it is implicitly preserved.
168  *
169  * <p>
170  * A pipeline consists of a stream source encapsulating a spliterator, one or
171  * more intermediate operations, and finally a terminal operation that produces
172  * a result.  At each stage of the pipeline, a combined stream and operation
173  * flags can be calculated, using {@link #combineOpFlags(intint)}.  Such flags
174  * ensure that preservation, clearing and injecting information is retained at
175  * each stage.
176  *
177  * The combined stream and operation flags for the source stage of the pipeline
178  * is calculated as follows:
179  * <pre> {@code
180  *     int flagsForSourceStage = combineOpFlags(sourceFlags, INITIAL_OPS_VALUE);
181  * }</pre>
182  *
183  * The combined stream and operation flags of each subsequent intermediate
184  * operation stage in the pipeline is calculated as follows:
185  * <pre> {@code
186  *     int flagsForThisStage = combineOpFlags(flagsForPreviousStage, thisOpFlags);
187  * }</pre>
188  *
189  * Finally the flags output from the last intermediate operation of the pipeline
190  * are combined with the operation flags of the terminal operation to produce
191  * the flags output from the pipeline.
192  *
193  * <p>Those flags can then be used to apply optimizations. For example, if
194  * {@code SIZED.isKnown(flags)} returns true then the stream size remains
195  * constant throughout the pipeline, this information can be utilized to
196  * pre-allocate data structures and combined with
197  * {@link java.util.Spliterator#SUBSIZED} that information can be utilized to
198  * perform concurrent in-place updates into a shared array.
199  *
200  * For specific details see the {@link AbstractPipeline} constructors.
201  *
202  * @since 1.8
203  */

204 enum StreamOpFlag {
205
206     /*
207      * Each characteristic takes up 2 bits in a bit set to accommodate
208      * preserving, clearing and setting/injecting information.
209      *
210      * This applies to stream flags, intermediate/terminal operation flags, and
211      * combined stream and operation flags. Even though the former only requires
212      * 1 bit of information per characteristic, is it more efficient when
213      * combining flags to align set and inject bits.
214      *
215      * Characteristics belong to certain types, see the Type enum. Bit masks for
216      * the types are constructed as per the following table:
217      *
218      *                        DISTINCT  SORTED  ORDERED  SIZED  SHORT_CIRCUIT
219      *          SPLITERATOR      01       01       01      01        00
220      *               STREAM      01       01       01      01        00
221      *                   OP      11       11       11      10        01
222      *          TERMINAL_OP      00       00       10      00        01
223      * UPSTREAM_TERMINAL_OP      00       00       10      00        00
224      *
225      * 01 = set/inject
226      * 10 = clear
227      * 11 = preserve
228      *
229      * Construction of the columns is performed using a simple builder for
230      * non-zero values.
231      */

232
233
234     // The following flags correspond to characteristics on Spliterator
235     // and the values MUST be equal.
236     //
237
238     /**
239      * Characteristic value signifying that, for each pair of
240      * encountered elements in a stream {@code x, y}, {@code !x.equals(y)}.
241      * <p>
242      * A stream may have this value or an intermediate operation can preserve,
243      * clear or inject this value.
244      */

245     // 0, 0x00000001
246     // Matches Spliterator.DISTINCT
247     DISTINCT(0,
248              set(Type.SPLITERATOR).set(Type.STREAM).setAndClear(Type.OP)),
249
250     /**
251      * Characteristic value signifying that encounter order follows a natural
252      * sort order of comparable elements.
253      * <p>
254      * A stream can have this value or an intermediate operation can preserve,
255      * clear or inject this value.
256      * <p>
257      * Note: The {@link java.util.Spliterator#SORTED} characteristic can define
258      * a sort order with an associated non-null comparator.  Augmenting flag
259      * state with addition properties such that those properties can be passed
260      * to operations requires some disruptive changes for a singular use-case.
261      * Furthermore, comparing comparators for equality beyond that of identity
262      * is likely to be unreliable.  Therefore the {@code SORTED} characteristic
263      * for a defined non-natural sort order is not mapped internally to the
264      * {@code SORTED} flag.
265      */

266     // 1, 0x00000004
267     // Matches Spliterator.SORTED
268     SORTED(1,
269            set(Type.SPLITERATOR).set(Type.STREAM).setAndClear(Type.OP)),
270
271     /**
272      * Characteristic value signifying that an encounter order is
273      * defined for stream elements.
274      * <p>
275      * A stream can have this value, an intermediate operation can preserve,
276      * clear or inject this value, or a terminal operation can preserve or clear
277      * this value.
278      */

279     // 2, 0x00000010
280     // Matches Spliterator.ORDERED
281     ORDERED(2,
282             set(Type.SPLITERATOR).set(Type.STREAM).setAndClear(Type.OP).clear(Type.TERMINAL_OP)
283                     .clear(Type.UPSTREAM_TERMINAL_OP)),
284
285     /**
286      * Characteristic value signifying that size of the stream
287      * is of a known finite size that is equal to the known finite
288      * size of the source spliterator input to the first stream
289      * in the pipeline.
290      * <p>
291      * A stream can have this value or an intermediate operation can preserve or
292      * clear this value.
293      */

294     // 3, 0x00000040
295     // Matches Spliterator.SIZED
296     SIZED(3,
297           set(Type.SPLITERATOR).set(Type.STREAM).clear(Type.OP)),
298
299     // The following Spliterator characteristics are not currently used but a
300     // gap in the bit set is deliberately retained to enable corresponding
301     // stream flags if//when required without modification to other flag values.
302     //
303     // 4, 0x00000100 NONNULL(4, ...
304     // 5, 0x00000400 IMMUTABLE(5, ...
305     // 6, 0x00001000 CONCURRENT(6, ...
306     // 7, 0x00004000 SUBSIZED(7, ...
307
308     // The following 4 flags are currently undefined and a free for any further
309     // spliterator characteristics.
310     //
311     //  8, 0x00010000
312     //  9, 0x00040000
313     // 10, 0x00100000
314     // 11, 0x00400000
315
316     // The following flags are specific to streams and operations
317     //
318
319     /**
320      * Characteristic value signifying that an operation may short-circuit the
321      * stream.
322      * <p>
323      * An intermediate operation can preserve or inject this value,
324      * or a terminal operation can preserve or inject this value.
325      */

326     // 12, 0x01000000
327     SHORT_CIRCUIT(12,
328                   set(Type.OP).set(Type.TERMINAL_OP));
329
330     // The following 2 flags are currently undefined and a free for any further
331     // stream flags if/when required
332     //
333     // 13, 0x04000000
334     // 14, 0x10000000
335     // 15, 0x40000000
336
337     /**
338      * Type of a flag
339      */

340     enum Type {
341         /**
342          * The flag is associated with spliterator characteristics.
343          */

344         SPLITERATOR,
345
346         /**
347          * The flag is associated with stream flags.
348          */

349         STREAM,
350
351         /**
352          * The flag is associated with intermediate operation flags.
353          */

354         OP,
355
356         /**
357          * The flag is associated with terminal operation flags.
358          */

359         TERMINAL_OP,
360
361         /**
362          * The flag is associated with terminal operation flags that are
363          * propagated upstream across the last stateful operation boundary
364          */

365         UPSTREAM_TERMINAL_OP
366     }
367
368     /**
369      * The bit pattern for setting/injecting a flag.
370      */

371     private static final int SET_BITS = 0b01;
372
373     /**
374      * The bit pattern for clearing a flag.
375      */

376     private static final int CLEAR_BITS = 0b10;
377
378     /**
379      * The bit pattern for preserving a flag.
380      */

381     private static final int PRESERVE_BITS = 0b11;
382
383     private static MaskBuilder set(Type t) {
384         return new MaskBuilder(new EnumMap<>(Type.class)).set(t);
385     }
386
387     private static class MaskBuilder {
388         final Map<Type, Integer> map;
389
390         MaskBuilder(Map<Type, Integer> map) {
391             this.map = map;
392         }
393
394         MaskBuilder mask(Type t, Integer i) {
395             map.put(t, i);
396             return this;
397         }
398
399         MaskBuilder set(Type t) {
400             return mask(t, SET_BITS);
401         }
402
403         MaskBuilder clear(Type t) {
404             return mask(t, CLEAR_BITS);
405         }
406
407         MaskBuilder setAndClear(Type t) {
408             return mask(t, PRESERVE_BITS);
409         }
410
411         Map<Type, Integer> build() {
412             for (Type t : Type.values()) {
413                 map.putIfAbsent(t, 0b00);
414             }
415             return map;
416         }
417     }
418
419     /**
420      * The mask table for a flag, this is used to determine if a flag
421      * corresponds to a certain flag type and for creating mask constants.
422      */

423     private final Map<Type, Integer> maskTable;
424
425     /**
426      * The bit position in the bit mask.
427      */

428     private final int bitPosition;
429
430     /**
431      * The set 2 bit set offset at the bit position.
432      */

433     private final int set;
434
435     /**
436      * The clear 2 bit set offset at the bit position.
437      */

438     private final int clear;
439
440     /**
441      * The preserve 2 bit set offset at the bit position.
442      */

443     private final int preserve;
444
445     private StreamOpFlag(int position, MaskBuilder maskBuilder) {
446         this.maskTable = maskBuilder.build();
447         // Two bits per flag
448         position *= 2;
449         this.bitPosition = position;
450         this.set = SET_BITS << position;
451         this.clear = CLEAR_BITS << position;
452         this.preserve = PRESERVE_BITS << position;
453     }
454
455     /**
456      * Gets the bitmap associated with setting this characteristic.
457      *
458      * @return the bitmap for setting this characteristic
459      */

460     int set() {
461         return set;
462     }
463
464     /**
465      * Gets the bitmap associated with clearing this characteristic.
466      *
467      * @return the bitmap for clearing this characteristic
468      */

469     int clear() {
470         return clear;
471     }
472
473     /**
474      * Determines if this flag is a stream-based flag.
475      *
476      * @return true if a stream-based flag, otherwise false.
477      */

478     boolean isStreamFlag() {
479         return maskTable.get(Type.STREAM) > 0;
480     }
481
482     /**
483      * Checks if this flag is set on stream flags, injected on operation flags,
484      * and injected on combined stream and operation flags.
485      *
486      * @param flags the stream flags, operation flags, or combined stream and
487      *        operation flags
488      * @return true if this flag is known, otherwise false.
489      */

490     boolean isKnown(int flags) {
491         return (flags & preserve) == set;
492     }
493
494     /**
495      * Checks if this flag is cleared on operation flags or combined stream and
496      * operation flags.
497      *
498      * @param flags the operation flags or combined stream and operations flags.
499      * @return true if this flag is preserved, otherwise false.
500      */

501     boolean isCleared(int flags) {
502         return (flags & preserve) == clear;
503     }
504
505     /**
506      * Checks if this flag is preserved on combined stream and operation flags.
507      *
508      * @param flags the combined stream and operations flags.
509      * @return true if this flag is preserved, otherwise false.
510      */

511     boolean isPreserved(int flags) {
512         return (flags & preserve) == preserve;
513     }
514
515     /**
516      * Determines if this flag can be set for a flag type.
517      *
518      * @param t the flag type.
519      * @return true if this flag can be set for the flag type, otherwise false.
520      */

521     boolean canSet(Type t) {
522         return (maskTable.get(t) & SET_BITS) > 0;
523     }
524
525     /**
526      * The bit mask for spliterator characteristics
527      */

528     static final int SPLITERATOR_CHARACTERISTICS_MASK = createMask(Type.SPLITERATOR);
529
530     /**
531      * The bit mask for source stream flags.
532      */

533     static final int STREAM_MASK = createMask(Type.STREAM);
534
535     /**
536      * The bit mask for intermediate operation flags.
537      */

538     static final int OP_MASK = createMask(Type.OP);
539
540     /**
541      * The bit mask for terminal operation flags.
542      */

543     static final int TERMINAL_OP_MASK = createMask(Type.TERMINAL_OP);
544
545     /**
546      * The bit mask for upstream terminal operation flags.
547      */

548     static final int UPSTREAM_TERMINAL_OP_MASK = createMask(Type.UPSTREAM_TERMINAL_OP);
549
550     private static int createMask(Type t) {
551         int mask = 0;
552         for (StreamOpFlag flag : StreamOpFlag.values()) {
553             mask |= flag.maskTable.get(t) << flag.bitPosition;
554         }
555         return mask;
556     }
557
558     /**
559      * Complete flag mask.
560      */

561     private static final int FLAG_MASK = createFlagMask();
562
563     private static int createFlagMask() {
564         int mask = 0;
565         for (StreamOpFlag flag : StreamOpFlag.values()) {
566             mask |= flag.preserve;
567         }
568         return mask;
569     }
570
571     /**
572      * Flag mask for stream flags that are set.
573      */

574     private static final int FLAG_MASK_IS = STREAM_MASK;
575
576     /**
577      * Flag mask for stream flags that are cleared.
578      */

579     private static final int FLAG_MASK_NOT = STREAM_MASK << 1;
580
581     /**
582      * The initial value to be combined with the stream flags of the first
583      * stream in the pipeline.
584      */

585     static final int INITIAL_OPS_VALUE = FLAG_MASK_IS | FLAG_MASK_NOT;
586
587     /**
588      * The bit value to set or inject {@link #DISTINCT}.
589      */

590     static final int IS_DISTINCT = DISTINCT.set;
591
592     /**
593      * The bit value to clear {@link #DISTINCT}.
594      */

595     static final int NOT_DISTINCT = DISTINCT.clear;
596
597     /**
598      * The bit value to set or inject {@link #SORTED}.
599      */

600     static final int IS_SORTED = SORTED.set;
601
602     /**
603      * The bit value to clear {@link #SORTED}.
604      */

605     static final int NOT_SORTED = SORTED.clear;
606
607     /**
608      * The bit value to set or inject {@link #ORDERED}.
609      */

610     static final int IS_ORDERED = ORDERED.set;
611
612     /**
613      * The bit value to clear {@link #ORDERED}.
614      */

615     static final int NOT_ORDERED = ORDERED.clear;
616
617     /**
618      * The bit value to set {@link #SIZED}.
619      */

620     static final int IS_SIZED = SIZED.set;
621
622     /**
623      * The bit value to clear {@link #SIZED}.
624      */

625     static final int NOT_SIZED = SIZED.clear;
626
627     /**
628      * The bit value to inject {@link #SHORT_CIRCUIT}.
629      */

630     static final int IS_SHORT_CIRCUIT = SHORT_CIRCUIT.set;
631
632     private static int getMask(int flags) {
633         return (flags == 0)
634                ? FLAG_MASK
635                : ~(flags | ((FLAG_MASK_IS & flags) << 1) | ((FLAG_MASK_NOT & flags) >> 1));
636     }
637
638     /**
639      * Combines stream or operation flags with previously combined stream and
640      * operation flags to produce updated combined stream and operation flags.
641      * <p>
642      * A flag set on stream flags or injected on operation flags,
643      * and injected combined stream and operation flags,
644      * will be injected on the updated combined stream and operation flags.
645      *
646      * <p>
647      * A flag set on stream flags or injected on operation flags,
648      * and cleared on the combined stream and operation flags,
649      * will be cleared on the updated combined stream and operation flags.
650      *
651      * <p>
652      * A flag set on the stream flags or injected on operation flags,
653      * and preserved on the combined stream and operation flags,
654      * will be injected on the updated combined stream and operation flags.
655      *
656      * <p>
657      * A flag not set on the stream flags or cleared/preserved on operation
658      * flags, and injected on the combined stream and operation flags,
659      * will be injected on the updated combined stream and operation flags.
660      *
661      * <p>
662      * A flag not set on the stream flags or cleared/preserved on operation
663      * flags, and cleared on the combined stream and operation flags,
664      * will be cleared on the updated combined stream and operation flags.
665      *
666      * <p>
667      * A flag not set on the stream flags,
668      * and preserved on the combined stream and operation flags
669      * will be preserved on the updated combined stream and operation flags.
670      *
671      * <p>
672      * A flag cleared on operation flags,
673      * and preserved on the combined stream and operation flags
674      * will be cleared on the updated combined stream and operation flags.
675      *
676      * <p>
677      * A flag preserved on operation flags,
678      * and preserved on the combined stream and operation flags
679      * will be preserved on the updated combined stream and operation flags.
680      *
681      * @param newStreamOrOpFlags the stream or operation flags.
682      * @param prevCombOpFlags previously combined stream and operation flags.
683      *        The value {#link INITIAL_OPS_VALUE} must be used as the seed value.
684      * @return the updated combined stream and operation flags.
685      */

686     static int combineOpFlags(int newStreamOrOpFlags, int prevCombOpFlags) {
687         // 0x01 or 0x10 nibbles are transformed to 0x11
688         // 0x00 nibbles remain unchanged
689         // Then all the bits are flipped
690         // Then the result is logically or'ed with the operation flags.
691         return (prevCombOpFlags & StreamOpFlag.getMask(newStreamOrOpFlags)) | newStreamOrOpFlags;
692     }
693
694     /**
695      * Converts combined stream and operation flags to stream flags.
696      *
697      * <p>Each flag injected on the combined stream and operation flags will be
698      * set on the stream flags.
699      *
700      * @param combOpFlags the combined stream and operation flags.
701      * @return the stream flags.
702      */

703     static int toStreamFlags(int combOpFlags) {
704         // By flipping the nibbles 0x11 become 0x00 and 0x01 become 0x10
705         // Shift left 1 to restore set flags and mask off anything other than the set flags
706         return ((~combOpFlags) >> 1) & FLAG_MASK_IS & combOpFlags;
707     }
708
709     /**
710      * Converts stream flags to a spliterator characteristic bit set.
711      *
712      * @param streamFlags the stream flags.
713      * @return the spliterator characteristic bit set.
714      */

715     static int toCharacteristics(int streamFlags) {
716         return streamFlags & SPLITERATOR_CHARACTERISTICS_MASK;
717     }
718
719     /**
720      * Converts a spliterator characteristic bit set to stream flags.
721      *
722      * @implSpec
723      * If the spliterator is naturally {@code SORTED} (the associated
724      * {@code Comparator} is {@code null}) then the characteristic is converted
725      * to the {@link #SORTED} flag, otherwise the characteristic is not
726      * converted.
727      *
728      * @param spliterator the spliterator from which to obtain characteristic
729      *        bit set.
730      * @return the stream flags.
731      */

732     static int fromCharacteristics(Spliterator<?> spliterator) {
733         int characteristics = spliterator.characteristics();
734         if ((characteristics & Spliterator.SORTED) != 0 && spliterator.getComparator() != null) {
735             // Do not propagate the SORTED characteristic if it does not correspond
736             // to a natural sort order
737             return characteristics & SPLITERATOR_CHARACTERISTICS_MASK & ~Spliterator.SORTED;
738         }
739         else {
740             return characteristics & SPLITERATOR_CHARACTERISTICS_MASK;
741         }
742     }
743
744     /**
745      * Converts a spliterator characteristic bit set to stream flags.
746      *
747      * @param characteristics the spliterator characteristic bit set.
748      * @return the stream flags.
749      */

750     static int fromCharacteristics(int characteristics) {
751         return characteristics & SPLITERATOR_CHARACTERISTICS_MASK;
752     }
753 }
754