StreamOpFlag.java revision ff18b5f136f92154f2e05217e3953d10f459e561
1/*
2 * Copyright (c) 2012, 2013, 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 */
25package java.util.stream;
26
27import java.util.EnumMap;
28import java.util.Map;
29import 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>
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 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(int, int)}.  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 */
204enum 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