StreamOpFlag.java revision 289e51c2258b001f2aa6d6e67b21be7bb65d5102
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 * @hide Visible for CTS testing only (OpenJDK8 tests).
204 */
205public enum StreamOpFlag {
206
207    /*
208     * Each characteristic takes up 2 bits in a bit set to accommodate
209     * preserving, clearing and setting/injecting information.
210     *
211     * This applies to stream flags, intermediate/terminal operation flags, and
212     * combined stream and operation flags. Even though the former only requires
213     * 1 bit of information per characteristic, is it more efficient when
214     * combining flags to align set and inject bits.
215     *
216     * Characteristics belong to certain types, see the Type enum. Bit masks for
217     * the types are constructed as per the following table:
218     *
219     *                        DISTINCT  SORTED  ORDERED  SIZED  SHORT_CIRCUIT
220     *          SPLITERATOR      01       01       01      01        00
221     *               STREAM      01       01       01      01        00
222     *                   OP      11       11       11      10        01
223     *          TERMINAL_OP      00       00       10      00        01
224     * UPSTREAM_TERMINAL_OP      00       00       10      00        00
225     *
226     * 01 = set/inject
227     * 10 = clear
228     * 11 = preserve
229     *
230     * Construction of the columns is performed using a simple builder for
231     * non-zero values.
232     */
233
234
235    // The following flags correspond to characteristics on Spliterator
236    // and the values MUST be equal.
237    //
238
239    /**
240     * Characteristic value signifying that, for each pair of
241     * encountered elements in a stream {@code x, y}, {@code !x.equals(y)}.
242     * <p>
243     * A stream may have this value or an intermediate operation can preserve,
244     * clear or inject this value.
245     */
246    // 0, 0x00000001
247    // Matches Spliterator.DISTINCT
248    DISTINCT(0,
249             set(Type.SPLITERATOR).set(Type.STREAM).setAndClear(Type.OP)),
250
251    /**
252     * Characteristic value signifying that encounter order follows a natural
253     * sort order of comparable elements.
254     * <p>
255     * A stream can have this value or an intermediate operation can preserve,
256     * clear or inject this value.
257     * <p>
258     * Note: The {@link java.util.Spliterator#SORTED} characteristic can define
259     * a sort order with an associated non-null comparator.  Augmenting flag
260     * state with addition properties such that those properties can be passed
261     * to operations requires some disruptive changes for a singular use-case.
262     * Furthermore, comparing comparators for equality beyond that of identity
263     * is likely to be unreliable.  Therefore the {@code SORTED} characteristic
264     * for a defined non-natural sort order is not mapped internally to the
265     * {@code SORTED} flag.
266     */
267    // 1, 0x00000004
268    // Matches Spliterator.SORTED
269    SORTED(1,
270           set(Type.SPLITERATOR).set(Type.STREAM).setAndClear(Type.OP)),
271
272    /**
273     * Characteristic value signifying that an encounter order is
274     * defined for stream elements.
275     * <p>
276     * A stream can have this value, an intermediate operation can preserve,
277     * clear or inject this value, or a terminal operation can preserve or clear
278     * this value.
279     */
280    // 2, 0x00000010
281    // Matches Spliterator.ORDERED
282    ORDERED(2,
283            set(Type.SPLITERATOR).set(Type.STREAM).setAndClear(Type.OP).clear(Type.TERMINAL_OP)
284                    .clear(Type.UPSTREAM_TERMINAL_OP)),
285
286    /**
287     * Characteristic value signifying that size of the stream
288     * is of a known finite size that is equal to the known finite
289     * size of the source spliterator input to the first stream
290     * in the pipeline.
291     * <p>
292     * A stream can have this value or an intermediate operation can preserve or
293     * clear this value.
294     */
295    // 3, 0x00000040
296    // Matches Spliterator.SIZED
297    SIZED(3,
298          set(Type.SPLITERATOR).set(Type.STREAM).clear(Type.OP)),
299
300    // The following Spliterator characteristics are not currently used but a
301    // gap in the bit set is deliberately retained to enable corresponding
302    // stream flags if//when required without modification to other flag values.
303    //
304    // 4, 0x00000100 NONNULL(4, ...
305    // 5, 0x00000400 IMMUTABLE(5, ...
306    // 6, 0x00001000 CONCURRENT(6, ...
307    // 7, 0x00004000 SUBSIZED(7, ...
308
309    // The following 4 flags are currently undefined and a free for any further
310    // spliterator characteristics.
311    //
312    //  8, 0x00010000
313    //  9, 0x00040000
314    // 10, 0x00100000
315    // 11, 0x00400000
316
317    // The following flags are specific to streams and operations
318    //
319
320    /**
321     * Characteristic value signifying that an operation may short-circuit the
322     * stream.
323     * <p>
324     * An intermediate operation can preserve or inject this value,
325     * or a terminal operation can preserve or inject this value.
326     */
327    // 12, 0x01000000
328    SHORT_CIRCUIT(12,
329                  set(Type.OP).set(Type.TERMINAL_OP));
330
331    // The following 2 flags are currently undefined and a free for any further
332    // stream flags if/when required
333    //
334    // 13, 0x04000000
335    // 14, 0x10000000
336    // 15, 0x40000000
337
338    /**
339     * Type of a flag
340     */
341    enum Type {
342        /**
343         * The flag is associated with spliterator characteristics.
344         */
345        SPLITERATOR,
346
347        /**
348         * The flag is associated with stream flags.
349         */
350        STREAM,
351
352        /**
353         * The flag is associated with intermediate operation flags.
354         */
355        OP,
356
357        /**
358         * The flag is associated with terminal operation flags.
359         */
360        TERMINAL_OP,
361
362        /**
363         * The flag is associated with terminal operation flags that are
364         * propagated upstream across the last stateful operation boundary
365         */
366        UPSTREAM_TERMINAL_OP
367    }
368
369    /**
370     * The bit pattern for setting/injecting a flag.
371     */
372    private static final int SET_BITS = 0b01;
373
374    /**
375     * The bit pattern for clearing a flag.
376     */
377    private static final int CLEAR_BITS = 0b10;
378
379    /**
380     * The bit pattern for preserving a flag.
381     */
382    private static final int PRESERVE_BITS = 0b11;
383
384    private static MaskBuilder set(Type t) {
385        return new MaskBuilder(new EnumMap<>(Type.class)).set(t);
386    }
387
388    private static class MaskBuilder {
389        final Map<Type, Integer> map;
390
391        MaskBuilder(Map<Type, Integer> map) {
392            this.map = map;
393        }
394
395        MaskBuilder mask(Type t, Integer i) {
396            map.put(t, i);
397            return this;
398        }
399
400        MaskBuilder set(Type t) {
401            return mask(t, SET_BITS);
402        }
403
404        MaskBuilder clear(Type t) {
405            return mask(t, CLEAR_BITS);
406        }
407
408        MaskBuilder setAndClear(Type t) {
409            return mask(t, PRESERVE_BITS);
410        }
411
412        Map<Type, Integer> build() {
413            for (Type t : Type.values()) {
414                map.putIfAbsent(t, 0b00);
415            }
416            return map;
417        }
418    }
419
420    /**
421     * The mask table for a flag, this is used to determine if a flag
422     * corresponds to a certain flag type and for creating mask constants.
423     */
424    private final Map<Type, Integer> maskTable;
425
426    /**
427     * The bit position in the bit mask.
428     */
429    private final int bitPosition;
430
431    /**
432     * The set 2 bit set offset at the bit position.
433     */
434    private final int set;
435
436    /**
437     * The clear 2 bit set offset at the bit position.
438     */
439    private final int clear;
440
441    /**
442     * The preserve 2 bit set offset at the bit position.
443     */
444    private final int preserve;
445
446    private StreamOpFlag(int position, MaskBuilder maskBuilder) {
447        this.maskTable = maskBuilder.build();
448        // Two bits per flag
449        position *= 2;
450        this.bitPosition = position;
451        this.set = SET_BITS << position;
452        this.clear = CLEAR_BITS << position;
453        this.preserve = PRESERVE_BITS << position;
454    }
455
456    /**
457     * Gets the bitmap associated with setting this characteristic.
458     *
459     * @return the bitmap for setting this characteristic
460     */
461    public int set() {
462        return set;
463    }
464
465    /**
466     * Gets the bitmap associated with clearing this characteristic.
467     *
468     * @return the bitmap for clearing this characteristic
469     */
470    public int clear() {
471        return clear;
472    }
473
474    /**
475     * Determines if this flag is a stream-based flag.
476     *
477     * @return true if a stream-based flag, otherwise false.
478     */
479    public boolean isStreamFlag() {
480        return maskTable.get(Type.STREAM) > 0;
481    }
482
483    /**
484     * Checks if this flag is set on stream flags, injected on operation flags,
485     * and injected on combined stream and operation flags.
486     *
487     * @param flags the stream flags, operation flags, or combined stream and
488     *        operation flags
489     * @return true if this flag is known, otherwise false.
490     */
491    public boolean isKnown(int flags) {
492        return (flags & preserve) == set;
493    }
494
495    /**
496     * Checks if this flag is cleared on operation flags or combined stream and
497     * operation flags.
498     *
499     * @param flags the operation flags or combined stream and operations flags.
500     * @return true if this flag is preserved, otherwise false.
501     */
502    public boolean isCleared(int flags) {
503        return (flags & preserve) == clear;
504    }
505
506    /**
507     * Checks if this flag is preserved on combined stream and operation flags.
508     *
509     * @param flags the combined stream and operations flags.
510     * @return true if this flag is preserved, otherwise false.
511     */
512    public boolean isPreserved(int flags) {
513        return (flags & preserve) == preserve;
514    }
515
516    /**
517     * Determines if this flag can be set for a flag type.
518     *
519     * @param t the flag type.
520     * @return true if this flag can be set for the flag type, otherwise false.
521     */
522    public boolean canSet(Type t) {
523        return (maskTable.get(t) & SET_BITS) > 0;
524    }
525
526    /**
527     * The bit mask for spliterator characteristics
528     */
529    public static final int SPLITERATOR_CHARACTERISTICS_MASK = createMask(Type.SPLITERATOR);
530
531    /**
532     * The bit mask for source stream flags.
533     */
534    public static final int STREAM_MASK = createMask(Type.STREAM);
535
536    /**
537     * The bit mask for intermediate operation flags.
538     */
539    public static final int OP_MASK = createMask(Type.OP);
540
541    /**
542     * The bit mask for terminal operation flags.
543     */
544    public static final int TERMINAL_OP_MASK = createMask(Type.TERMINAL_OP);
545
546    /**
547     * The bit mask for upstream terminal operation flags.
548     */
549    public static final int UPSTREAM_TERMINAL_OP_MASK = createMask(Type.UPSTREAM_TERMINAL_OP);
550
551    private static int createMask(Type t) {
552        int mask = 0;
553        for (StreamOpFlag flag : StreamOpFlag.values()) {
554            mask |= flag.maskTable.get(t) << flag.bitPosition;
555        }
556        return mask;
557    }
558
559    /**
560     * Complete flag mask.
561     */
562    private static final int FLAG_MASK = createFlagMask();
563
564    private static int createFlagMask() {
565        int mask = 0;
566        for (StreamOpFlag flag : StreamOpFlag.values()) {
567            mask |= flag.preserve;
568        }
569        return mask;
570    }
571
572    /**
573     * Flag mask for stream flags that are set.
574     */
575    private static final int FLAG_MASK_IS = STREAM_MASK;
576
577    /**
578     * Flag mask for stream flags that are cleared.
579     */
580    private static final int FLAG_MASK_NOT = STREAM_MASK << 1;
581
582    /**
583     * The initial value to be combined with the stream flags of the first
584     * stream in the pipeline.
585     */
586    public static final int INITIAL_OPS_VALUE = FLAG_MASK_IS | FLAG_MASK_NOT;
587
588    /**
589     * The bit value to set or inject {@link #DISTINCT}.
590     */
591    public static final int IS_DISTINCT = DISTINCT.set;
592
593    /**
594     * The bit value to clear {@link #DISTINCT}.
595     */
596    public static final int NOT_DISTINCT = DISTINCT.clear;
597
598    /**
599     * The bit value to set or inject {@link #SORTED}.
600     */
601    public static final int IS_SORTED = SORTED.set;
602
603    /**
604     * The bit value to clear {@link #SORTED}.
605     */
606    public static final int NOT_SORTED = SORTED.clear;
607
608    /**
609     * The bit value to set or inject {@link #ORDERED}.
610     */
611    public static final int IS_ORDERED = ORDERED.set;
612
613    /**
614     * The bit value to clear {@link #ORDERED}.
615     */
616    public static final int NOT_ORDERED = ORDERED.clear;
617
618    /**
619     * The bit value to set {@link #SIZED}.
620     */
621    public static final int IS_SIZED = SIZED.set;
622
623    /**
624     * The bit value to clear {@link #SIZED}.
625     */
626    public static final int NOT_SIZED = SIZED.clear;
627
628    /**
629     * The bit value to inject {@link #SHORT_CIRCUIT}.
630     */
631    public static final int IS_SHORT_CIRCUIT = SHORT_CIRCUIT.set;
632
633    private static int getMask(int flags) {
634        return (flags == 0)
635               ? FLAG_MASK
636               : ~(flags | ((FLAG_MASK_IS & flags) << 1) | ((FLAG_MASK_NOT & flags) >> 1));
637    }
638
639    /**
640     * Combines stream or operation flags with previously combined stream and
641     * operation flags to produce updated combined stream and operation flags.
642     * <p>
643     * A flag set on stream flags or injected on operation flags,
644     * and injected combined stream and operation flags,
645     * will be injected on the updated combined stream and operation flags.
646     *
647     * <p>
648     * A flag set on stream flags or injected on operation flags,
649     * and cleared on the combined stream and operation flags,
650     * will be cleared on the updated combined stream and operation flags.
651     *
652     * <p>
653     * A flag set on the stream flags or injected on operation flags,
654     * and preserved on the combined stream and operation flags,
655     * will be injected on the updated combined stream and operation flags.
656     *
657     * <p>
658     * A flag not set on the stream flags or cleared/preserved on operation
659     * flags, and injected on the combined stream and operation flags,
660     * will be injected on the updated combined stream and operation flags.
661     *
662     * <p>
663     * A flag not set on the stream flags or cleared/preserved on operation
664     * flags, and cleared on the combined stream and operation flags,
665     * will be cleared on the updated combined stream and operation flags.
666     *
667     * <p>
668     * A flag not set on the stream flags,
669     * and preserved on the combined stream and operation flags
670     * will be preserved on the updated combined stream and operation flags.
671     *
672     * <p>
673     * A flag cleared on operation flags,
674     * and preserved on the combined stream and operation flags
675     * will be cleared on the updated combined stream and operation flags.
676     *
677     * <p>
678     * A flag preserved on operation flags,
679     * and preserved on the combined stream and operation flags
680     * will be preserved on the updated combined stream and operation flags.
681     *
682     * @param newStreamOrOpFlags the stream or operation flags.
683     * @param prevCombOpFlags previously combined stream and operation flags.
684     *        The value {#link INITIAL_OPS_VALUE} must be used as the seed value.
685     * @return the updated combined stream and operation flags.
686     */
687    public static int combineOpFlags(int newStreamOrOpFlags, int prevCombOpFlags) {
688        // 0x01 or 0x10 nibbles are transformed to 0x11
689        // 0x00 nibbles remain unchanged
690        // Then all the bits are flipped
691        // Then the result is logically or'ed with the operation flags.
692        return (prevCombOpFlags & StreamOpFlag.getMask(newStreamOrOpFlags)) | newStreamOrOpFlags;
693    }
694
695    /**
696     * Converts combined stream and operation flags to stream flags.
697     *
698     * <p>Each flag injected on the combined stream and operation flags will be
699     * set on the stream flags.
700     *
701     * @param combOpFlags the combined stream and operation flags.
702     * @return the stream flags.
703     */
704    public static int toStreamFlags(int combOpFlags) {
705        // By flipping the nibbles 0x11 become 0x00 and 0x01 become 0x10
706        // Shift left 1 to restore set flags and mask off anything other than the set flags
707        return ((~combOpFlags) >> 1) & FLAG_MASK_IS & combOpFlags;
708    }
709
710    /**
711     * Converts stream flags to a spliterator characteristic bit set.
712     *
713     * @param streamFlags the stream flags.
714     * @return the spliterator characteristic bit set.
715     */
716    public static int toCharacteristics(int streamFlags) {
717        return streamFlags & SPLITERATOR_CHARACTERISTICS_MASK;
718    }
719
720    /**
721     * Converts a spliterator characteristic bit set to stream flags.
722     *
723     * @implSpec
724     * If the spliterator is naturally {@code SORTED} (the associated
725     * {@code Comparator} is {@code null}) then the characteristic is converted
726     * to the {@link #SORTED} flag, otherwise the characteristic is not
727     * converted.
728     *
729     * @param spliterator the spliterator from which to obtain characteristic
730     *        bit set.
731     * @return the stream flags.
732     */
733    public static int fromCharacteristics(Spliterator<?> spliterator) {
734        int characteristics = spliterator.characteristics();
735        if ((characteristics & Spliterator.SORTED) != 0 && spliterator.getComparator() != null) {
736            // Do not propagate the SORTED characteristic if it does not correspond
737            // to a natural sort order
738            return characteristics & SPLITERATOR_CHARACTERISTICS_MASK & ~Spliterator.SORTED;
739        }
740        else {
741            return characteristics & SPLITERATOR_CHARACTERISTICS_MASK;
742        }
743    }
744
745    /**
746     * Converts a spliterator characteristic bit set to stream flags.
747     *
748     * @param characteristics the spliterator characteristic bit set.
749     * @return the stream flags.
750     */
751    public static int fromCharacteristics(int characteristics) {
752        return characteristics & SPLITERATOR_CHARACTERISTICS_MASK;
753    }
754}
755