Home | History | Annotate | Download | only in stream
      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  */
     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>
     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  */
    205 public 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