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  * <pre>
  43  *                        DISTINCT  SORTED  ORDERED  SIZED  SHORT_CIRCUIT  PARALLEL
  44  * Stream source             Y        Y        Y       Y         N            Y
  45  * Intermediate operation    PCI      PCI      PCI     PC        PI           PC
  46  * Terminal operation        N        N        PC      N         PI           N
  47  * </pre>
  48  *
  49  * <p>In the above table, "PCI" means "may preserve, clear, or inject"; "PC"
  50  * means "may preserve or clear", "PI" means "may preserve or inject", and "N"
  51  * means "not valid".
  52  *
  53  * <p>Stream flags are represented by unioned bit sets, so that a single word
  54  * may describe all the characteristics of a given stream entity, and that, for
  55  * example, the flags for a stream source can be efficiently combined with the
  56  * flags for later operations on that stream.
  57  *
  58  * <p>The bit masks {@link #STREAM_MASK}, {@link #OP_MASK}, and
  59  * {@link #TERMINAL_OP_MASK} can be ANDed with a bit set of stream flags to
  60  * produce a mask containing only the valid flags for that entity type.
  61  *
  62  * <p>When describing a stream source, one only need describe what
  63  * characteristics that stream has; when describing a stream operation, one need
  64  * describe whether the operation preserves, injects, or clears that
  65  * characteristic.  Accordingly, two bits are used for each flag, so as to allow
  66  * representing not only the presence of of a characteristic, but how an
  67  * operation modifies that characteristic.  There are two common forms in which
  68  * flag bits are combined into an {@code int} bit set.  <em>Stream flags</em>
  69  * are a unioned bit set constructed by ORing the enum characteristic values of
  70  * {@link #set()} (or, more commonly, ORing the corresponding static named
  71  * constants prefixed with {@code IS_}).  <em>Operation flags</em> are a unioned
  72  * bit set constructed by ORing the enum characteristic values of {@link #set()}
  73  * or {@link #clear()} (to inject, or clear, respectively, the corresponding
  74  * flag), or more commonly ORing the corresponding named constants prefixed with
  75  * {@code IS_} or {@code NOT_}.  Flags that are not marked with {@code IS_} or
  76  * {@code NOT_} are implicitly treated as preserved.  Care must be taken when
  77  * combining bitsets that the correct combining operations are applied in the
  78  * correct order.
  79  *
  80  * <p>
  81  * With the exception of {@link #PARALLEL}, stream characteristics can be
  82  * derived from the equivalent {@link java.util.Spliterator} characteristics:
  83  * {@link java.util.Spliterator#DISTINCT}, {@link java.util.Spliterator#SORTED},
  84  * {@link java.util.Spliterator#ORDERED}, and
  85  * {@link java.util.Spliterator#SIZED}.  A spliterator characteristics bit set
  86  * can be converted to stream flags using the method
  87  * {@link #fromCharacteristics(java.util.Spliterator)} and converted back using
  88  * {@link #toCharacteristics(int)}.  (The bit set
  89  * {@link #SPLITERATOR_CHARACTERISTICS_MASK} is used to AND with a bit set to
  90  * produce a valid spliterator characteristics bit set that can be converted to
  91  * stream flags.)
  92  *
  93  * <p>
  94  * The source of a stream encapsulates a spliterator. The characteristics of
  95  * that source spliterator when transformed to stream flags will be a proper
  96  * subset of stream flags of that stream.
  97  * For example:
  98  * <pre> {@code
  99  *     Spliterator s = ...;
 100  *     Stream stream = Streams.stream(s);
 101  *     flagsFromSplitr = fromCharacteristics(s.characteristics());
 102  *     assert(flagsFromSplitr & stream.getStreamFlags() == flagsFromSplitr);
 103  * }</pre>
 104  *
 105  * <p>
 106  * An intermediate operation, performed on an input stream to create a new
 107  * output stream, may preserve, clear or inject stream or operation
 108  * characteristics.  Similarly, a terminal operation, performed on an input
 109  * stream to produce an output result may preserve, clear or inject stream or
 110  * operation characteristics.  Preservation means that if that characteristic
 111  * is present on the input, then it is also present on the output.  Clearing
 112  * means that the characteristic is not present on the output regardless of the
 113  * input.  Injection means that the characteristic is present on the output
 114  * regardless of the input.  If a characteristic is not cleared or injected then
 115  * it is implicitly preserved.
 116  *
 117  * <p>
 118  * A pipeline consists of a stream source encapsulating a spliterator, one or
 119  * more intermediate operations, and finally a terminal operation that produces
 120  * a result.  At each stage of the pipeline, a combined stream and operation
 121  * flags can be calculated, using {@link #combineOpFlags(int, int)}.  Such flags
 122  * ensure that preservation, clearing and injecting information is retained at
 123  * each stage.
 124  *
 125  * The combined stream and operation flags for the source stage of the pipeline
 126  * is calculated as follows:
 127  * <pre> {@code
 128  *     int flagsForSourceStage = combineOpFlags(sourceFlags, INITIAL_OPS_VALUE);
 129  * }</pre>
 130  *
 131  * The combined stream and operation flags of each subsequent intermediate
 132  * operation stage in the pipeline is calculated as follows:
 133  * <pre> {@code
 134  *     int flagsForThisStage = combineOpFlags(flagsForPreviousStage, thisOpFlags);
 135  * }</pre>
 136  *
 137  * Finally the flags output from the last intermediate operation of the pipeline
 138  * are combined with the operation flags of the terminal operation to produce
 139  * the flags output from the pipeline.
 140  *
 141  * <p>Those flags can then be used to apply optimizations. For example, if
 142  * {@code SIZED.isKnown(flags)} returns true then the stream size remains
 143  * constant throughout the pipeline, this information can be utilized to
 144  * pre-allocate data structures and combined with
 145  * {@link java.util.Spliterator#SUBSIZED} that information can be utilized to
 146  * perform concurrent in-place updates into a shared array.
 147  *
 148  * For specific details see the {@link AbstractPipeline} constructors.
 149  *
 150  * @since 1.8
 151  */
 152 // @@@ When a new flag is added what should happen for existing operations?
 153 //     Need to move to a builder approach used by ops where the masks for the new flag are
 154 //     taken into account for default behaviour.
 155 enum StreamOpFlag {
 156 
 157     /*
 158      * Each characteristic takes up 2 bits in a bit set to accommodate
 159      * preserving, clearing and setting/injecting information.
 160      *
 161      * This applies to stream flags, intermediate/terminal operation flags, and
 162      * combined stream and operation flags. Even though the former only requires
 163      * 1 bit of information per characteristic, is it more efficient when
 164      * combining flags to align set and inject bits.
 165      *
 166      * Characteristics belong to certain types, see the Type enum. Bit masks for
 167      * the types are constructed as per the following table:
 168      *
 169      *                        DISTINCT  SORTED  ORDERED  SIZED  SHORT_CIRCUIT  PARALLEL
 170      *          SPLITERATOR      01       01       01      01        00           00
 171      *               STREAM      01       01       01      01        00           01
 172      *                   OP      11       11       11      10        01           10
 173      *          TERMINAL_OP      00       00       10      00        01           00
 174      * UPSTREAM_TERMINAL_OP      00       00       10      00        00           00
 175      *
 176      * 01 = set/inject
 177      * 10 = clear
 178      * 11 = preserve
 179      *
 180      * Construction of the columns is performed using a simple builder for
 181      * non-zero values.
 182      */
 183 
 184 
 185     // The following flags correspond to characteristics on Spliterator
 186     // and the values MUST be equal.
 187     //
 188 
 189     /**
 190      * Characteristic value signifying that, for each pair of
 191      * encountered elements in a stream {@code x, y}, {@code !x.equals(y)}.
 192      * <p>
 193      * A stream may have this value or an intermediate operation can preserve,
 194      * clear or inject this value.
 195      */
 196     // 0, 0x00000001
 197     // Matches Spliterator.DISTINCT
 198     DISTINCT(0,
 199              set(Type.SPLITERATOR).set(Type.STREAM).setAndClear(Type.OP)),
 200 
 201     /**
 202      * Characteristic value signifying that encounter order follows a natural
 203      * sort order of comparable elements.
 204      * <p>
 205      * A stream can have this value or an intermediate operation can preserve,
 206      * clear or inject this value.
 207      * <p>
 208      * Note: The {@link java.util.Spliterator#SORTED} characteristic can define
 209      * a sort order with an associated non-null comparator.  Augmenting flag
 210      * state with addition properties such that those properties can be passed
 211      * to operations requires some disruptive changes for a singular use-case.
 212      * Furthermore, comparing comparators for equality beyond that of identity
 213      * is likely to be unreliable.  Therefore the {@code SORTED} characteristic
 214      * for a defined non-natural sort order is not mapped internally to the
 215      * {@code SORTED} flag.
 216      */
 217     // 1, 0x00000004
 218     // Matches Spliterator.SORTED
 219     SORTED(1,
 220            set(Type.SPLITERATOR).set(Type.STREAM).setAndClear(Type.OP)),
 221 
 222     /**
 223      * Characteristic value signifying that an encounter order is
 224      * defined for stream elements.
 225      * <p>
 226      * A stream can have this value, an intermediate operation can preserve,
 227      * clear or inject this value, or a terminal operation can preserve or clear
 228      * this value.
 229      */
 230     // 2, 0x00000010
 231     // Matches Spliterator.ORDERED
 232     ORDERED(2,
 233             set(Type.SPLITERATOR).set(Type.STREAM).setAndClear(Type.OP).clear(Type.TERMINAL_OP)
 234                     .clear(Type.UPSTREAM_TERMINAL_OP)),
 235 
 236     /**
 237      * Characteristic value signifying that size of the stream
 238      * is of a known finite size that is equal to the known finite
 239      * size of the source spliterator input to the first stream
 240      * in the pipeline.
 241      * <p>
 242      * A stream can have this value or an intermediate operation can preserve or
 243      * clear this value.
 244      */
 245     // 3, 0x00000040
 246     // Matches Spliterator.SIZED
 247     SIZED(3,
 248           set(Type.SPLITERATOR).set(Type.STREAM).clear(Type.OP)),
 249 
 250     // The following Spliterator characteristics are not currently used but a
 251     // gap in the bit set is deliberately retained to enable corresponding
 252     // stream flags if//when required without modification to other flag values.
 253     //
 254     // 4, 0x00000100 INFINITE(4, ...
 255     // 5, 0x00000400 NONNULL(5, ...
 256     // 6, 0x00001000 IMMUTABLE(6, ...
 257     // 7, 0x00004000 CONCURRENT(7, ...
 258     // 8, 0x00010000 SUBSIZED(8, ...)
 259 
 260     // The following 3 flags are currently undefined and a free for any further
 261     // spliterator characteristics.
 262     //
 263     //  9, 0x00040000
 264     // 10, 0x00100000
 265     // 11, 0x00400000
 266 
 267     // The following flags are specific to streams and operations
 268     //
 269 
 270     /**
 271      * Characteristic value signifying that an operation may short-circuit the
 272      * stream.
 273      * <p>
 274      * An intermediate operation can preserve or inject this value,
 275      * or a terminal operation can preserve or inject this value.
 276      */
 277     // 12, 0x01000000
 278     SHORT_CIRCUIT(12,
 279                   set(Type.OP).set(Type.TERMINAL_OP)),
 280 
 281 
 282     /**
 283      * Characteristic value signifying that the stream is to be evaluated in
 284      * parallel rather than sequentially.
 285      * <p>
 286      * A stream can have this value or an intermediate operation can preserve or
 287      * clear this value.
 288      */
 289     // 13, 0x04000000
 290     PARALLEL(13,
 291              set(Type.STREAM).clear(Type.OP));
 292 
 293     // The following 2 flags are currently undefined and a free for any further
 294     // stream flags if/when required
 295     //
 296     // 14, 0x10000000
 297     // 15, 0x40000000
 298 
 299     /**
 300      * Type of a flag
 301      */
 302     enum Type {
 303         /** The flag is associated with spliterator characteristics. */
 304         SPLITERATOR,
 305 
 306         /** The flag is associated with stream flags. */
 307         STREAM,
 308 
 309         /** The flag is associated with intermediate operation flags. */
 310         OP,
 311 
 312         /** The flag is associated with terminal operation flags. */
 313         TERMINAL_OP,
 314 
 315         /**
 316          * The flag is associated with terminal operation flags that are
 317          * propagated upstream across the last stateful operation boundary
 318          */
 319         UPSTREAM_TERMINAL_OP
 320     }
 321 
 322     /**
 323      * The bit pattern for setting/injecting a flag.
 324      */
 325     private static final int SET_BITS = 0b01;
 326 
 327     /**
 328      * The bit pattern for clearing a flag.
 329      */
 330     private static final int CLEAR_BITS = 0b10;
 331 
 332     /**
 333      * The bit pattern for preserving a flag.
 334      */
 335     private static final int PRESERVE_BITS = 0b11;
 336 
 337     private static MaskBuilder set(Type t) {
 338         return new MaskBuilder(new EnumMap<>(Type.class)).set(t);
 339     }
 340 
 341     private static class MaskBuilder {
 342         final Map<Type, Integer> map;
 343 
 344         MaskBuilder(Map<Type, Integer> map) {
 345             this.map = map;
 346         }
 347 
 348         MaskBuilder mask(Type t, Integer i) {
 349             map.put(t, i);
 350             return this;
 351         }
 352 
 353         MaskBuilder set(Type t) {
 354             return mask(t, SET_BITS);
 355         }
 356 
 357         MaskBuilder clear(Type t) {
 358             return mask(t, CLEAR_BITS);
 359         }
 360 
 361         MaskBuilder setAndClear(Type t) {
 362             return mask(t, PRESERVE_BITS);
 363         }
 364 
 365         Map<Type, Integer> build() {
 366             for (Type t : Type.values()) {
 367                 map.putIfAbsent(t, 0b00);
 368             }
 369             return map;
 370         }
 371     }
 372 
 373     // The mask table for a flag, this is used to determine
 374     // if a flag corresponds to a certain flag type and for creating
 375     // mask constants.
 376     private final Map<Type, Integer> maskTable;
 377 
 378     // The bit position in the bit mask
 379     private final int bitPosition;
 380 
 381     // The set 2 bit set offset at the bit position
 382     private final int set;
 383 
 384     // The clear 2 bit set offset at the bit position
 385     private final int clear;
 386 
 387     // The preserve 2 bit set offset at the bit position
 388     private final int preserve;
 389 
 390     private StreamOpFlag(int position, MaskBuilder maskBuilder) {
 391         this.maskTable = maskBuilder.build();
 392         // Two bits per flag
 393         position *= 2;
 394         this.bitPosition = position;
 395         this.set = SET_BITS << position;
 396         this.clear = CLEAR_BITS << position;
 397         this.preserve = PRESERVE_BITS << position;
 398     }
 399 
 400     /**
 401      * Gets the bitmap associated with setting this characteristic
 402      * @return the bitmap for setting this characteristic
 403      */
 404     int set() {
 405         return set;
 406     }
 407 
 408     /**
 409      * Gets the bitmap associated with clearing this characteristic
 410      * @return the bitmap for clearing this characteristic
 411      */
 412     int clear() {
 413         return clear;
 414     }
 415 
 416     /**
 417      * Determines if this flag is a stream-based flag.
 418      *
 419      * @return true if a stream-based flag, otherwise false.
 420      */
 421     boolean isStreamFlag() {
 422         return maskTable.get(Type.STREAM) > 0;
 423     }
 424 
 425     /**
 426      * Checks if this flag is set on stream flags, injected on operation flags,
 427      * and injected on combined stream and operation flags.
 428      *
 429      * @param flags the stream flags, operation flags, or combined stream and
 430      *        operation flags
 431      * @return true if this flag is known, otherwise false.
 432      */
 433     boolean isKnown(int flags) {
 434         return (flags & preserve) == set;
 435     }
 436 
 437     /**
 438      * Checks if this flag is cleared on operation flags or combined stream and
 439      * operation flags.
 440      *
 441      * @param flags the operation flags or combined stream and operations flags.
 442      * @return true if this flag is preserved, otherwise false.
 443      */
 444     boolean isCleared(int flags) {
 445         return (flags & preserve) == clear;
 446     }
 447 
 448     /**
 449      * Checks if this flag is preserved on combined stream and operation flags.
 450      *
 451      * @param flags the combined stream and operations flags.
 452      * @return true if this flag is preserved, otherwise false.
 453      */
 454     boolean isPreserved(int flags) {
 455         return (flags & preserve) == preserve;
 456     }
 457 
 458     /**
 459      * Determines if this flag can be set for a flag type.
 460      *
 461      * @param t the flag type.
 462      * @return true if this flag can be set for the flag type, otherwise false.
 463      */
 464     boolean canSet(Type t) {
 465         return (maskTable.get(t) & SET_BITS) > 0;
 466     }
 467 
 468     /**
 469      * The bit mask for spliterator characteristics
 470      */
 471     static final int SPLITERATOR_CHARACTERISTICS_MASK = createMask(Type.SPLITERATOR);
 472 
 473     /**
 474      * The bit mask for source stream flags.
 475      */
 476     static final int STREAM_MASK = createMask(Type.STREAM);
 477 
 478     /**
 479      * The bit mask for intermediate operation flags.
 480      */
 481     static final int OP_MASK = createMask(Type.OP);
 482 
 483     /**
 484      * The bit mask for terminal operation flags.
 485      */
 486     static final int TERMINAL_OP_MASK = createMask(Type.TERMINAL_OP);
 487 
 488     /**
 489      * The bit mask for upstream terminal operation flags.
 490      */
 491     static final int UPSTREAM_TERMINAL_OP_MASK = createMask(Type.UPSTREAM_TERMINAL_OP);
 492 
 493     private static int createMask(Type t) {
 494         int mask = 0;
 495         for (StreamOpFlag flag : StreamOpFlag.values()) {
 496             mask |= flag.maskTable.get(t) << flag.bitPosition;
 497         }
 498         return mask;
 499     }
 500 
 501     // Complete flag mask
 502     private static final int FLAG_MASK = createFlagMask();
 503 
 504     private static int createFlagMask() {
 505         int mask = 0;
 506         for (StreamOpFlag flag : StreamOpFlag.values()) {
 507             mask |= flag.preserve;
 508         }
 509         return mask;
 510     }
 511 
 512     // Flag mask for stream flags that are set
 513     private static final int FLAG_MASK_IS = STREAM_MASK;
 514 
 515     // Flag mask for stream flags that are cleared
 516     private static final int FLAG_MASK_NOT = STREAM_MASK << 1;
 517 
 518     /**
 519      * The initial value to be combined with the stream flags of the first
 520      * stream in the pipeline.
 521      */
 522     static final int INITIAL_OPS_VALUE = FLAG_MASK_IS | FLAG_MASK_NOT;
 523 
 524     /**
 525      * The bit value to set or inject {@link #DISTINCT}
 526      */
 527     static final int IS_DISTINCT = DISTINCT.set;
 528 
 529     /**
 530      * The bit value to clear {@link #DISTINCT}
 531      */
 532     static final int NOT_DISTINCT = DISTINCT.clear;
 533 
 534     /**
 535      * The bit value to set or inject {@link #SORTED}
 536      */
 537     static final int IS_SORTED = SORTED.set;
 538 
 539     /**
 540      * The bit value to clear {@link #SORTED}
 541      */
 542     static final int NOT_SORTED = SORTED.clear;
 543 
 544     /**
 545      * The bit value to set or inject {@link #ORDERED}
 546      */
 547     static final int IS_ORDERED = ORDERED.set;
 548 
 549     /**
 550      * The bit value to clear {@link #ORDERED}
 551      */
 552     static final int NOT_ORDERED = ORDERED.clear;
 553 
 554     /**
 555      * The bit value to set {@link #SIZED}
 556      */
 557     static final int IS_SIZED = SIZED.set;
 558 
 559     /**
 560      * The bit value to clear {@link #SIZED}
 561      */
 562     static final int NOT_SIZED = SIZED.clear;
 563 
 564     /**
 565      * The bit value to inject {@link #SHORT_CIRCUIT}
 566      */
 567     static final int IS_SHORT_CIRCUIT = SHORT_CIRCUIT.set;
 568 
 569     /**
 570      * The bit value to set {@link #PARALLEL}
 571      */
 572     static final int IS_PARALLEL = PARALLEL.set;
 573 
 574     /**
 575      * The bit value to clear {@link #PARALLEL}
 576      */
 577     static final int NOT_PARALLEL = PARALLEL.clear;
 578 
 579     private static int getMask(int flags) {
 580         return (flags == 0)
 581                ? FLAG_MASK
 582                : ~(flags | ((FLAG_MASK_IS & flags) << 1) | ((FLAG_MASK_NOT & flags) >> 1));
 583     }
 584 
 585     /**
 586      * Combines stream or operation flags with previously combined stream and
 587      * operation flags to produce updated combined stream and operation flags.
 588      * <p>
 589      * A flag set on stream flags or injected on operation flags,
 590      * and injected combined stream and operation flags,
 591      * will be injected on the updated combined stream and operation flags.
 592      * </p>
 593      * <p>
 594      * A flag set on stream flags or injected on operation flags,
 595      * and cleared on the combined stream and operation flags,
 596      * will be cleared on the updated combined stream and operation flags.
 597      * </p>
 598      * <p>
 599      * A flag set on the stream flags or injected on operation flags,
 600      * and preserved on the combined stream and operation flags,
 601      * will be injected on the updated combined stream and operation flags.
 602      * </p>
 603      * <p>
 604      * A flag not set on the stream flags or cleared/preserved on operation
 605      * flags, and injected on the combined stream and operation flags,
 606      * will be injected on the updated combined stream and operation flags.
 607      * </p>
 608      * <p>
 609      * A flag not set on the stream flags or cleared/preserved on operation
 610      * flags, and cleared on the combined stream and operation flags,
 611      * will be cleared on the updated combined stream and operation flags.
 612      * </p>
 613      * <p>
 614      * A flag not set on the stream flags,
 615      * and preserved on the combined stream and operation flags
 616      * will be preserved on the updated combined stream and operation flags.
 617      * </p>
 618      * <p>
 619      * A flag cleared on operation flags,
 620      * and preserved on the combined stream and operation flags
 621      * will be cleared on the updated combined stream and operation flags.
 622      * </p>
 623      * <p>
 624      * A flag preserved on operation flags,
 625      * and preserved on the combined stream and operation flags
 626      * will be preserved on the updated combined stream and operation flags.
 627      * </p>
 628      *
 629      * @param newStreamOrOpFlags the stream or operation flags.
 630      * @param prevCombOpFlags previously combined stream and operation flags.
 631      *        The value {#link INITIAL_OPS_VALUE} must be used as the seed value.
 632      * @return the updated combined stream and operation flags.
 633      */
 634     static int combineOpFlags(int newStreamOrOpFlags, int prevCombOpFlags) {
 635         // 0x01 or 0x10 nibbles are transformed to 0x11
 636         // 0x00 nibbles remain unchanged
 637         // Then all the bits are flipped
 638         // Then the result is logically or'ed with the operation flags.
 639         return (prevCombOpFlags & StreamOpFlag.getMask(newStreamOrOpFlags)) | newStreamOrOpFlags;
 640     }
 641 
 642     /**
 643      * Converts combined stream and operation flags to stream flags.
 644      *
 645      * <p>Each flag injected on the combined stream and operation flags will be
 646      * set on the stream flags.
 647      *
 648      * @param combOpFlags the combined stream and operation flags.
 649      * @return the stream flags.
 650      */
 651     static int toStreamFlags(int combOpFlags) {
 652         // By flipping the nibbles 0x11 become 0x00 and 0x01 become 0x10
 653         // Shift left 1 to restore set flags and mask off anything other than the set flags
 654         return ((~combOpFlags) >> 1) & FLAG_MASK_IS & combOpFlags;
 655     }
 656 
 657     /**
 658      * Converts stream flags to a spliterator characteristic bit set.
 659      *
 660      * @param streamFlags the stream flags.
 661      * @return the spliterator characteristic bit set.
 662      */
 663     static int toCharacteristics(int streamFlags) {
 664         return streamFlags & SPLITERATOR_CHARACTERISTICS_MASK;
 665     }
 666 
 667     /**
 668      * Converts a spliterator characteristic bit set to stream flags.
 669      *
 670      * @implSpec
 671      * If the spliterator is naturally {@code SORTED} (the associated
 672      * {@code Comparator} is {@code null}) then the characteristic is converted
 673      * to the {@link #SORTED} flag, otherwise the characteristic is not
 674      * converted.
 675      *
 676      * @param spliterator the spliterator from which to obtain characteristic
 677      *        bit set.
 678      * @return the stream flags.
 679      */
 680     static int fromCharacteristics(Spliterator<?> spliterator) {
 681         int characteristics = spliterator.characteristics();
 682         if ((characteristics & Spliterator.SORTED) != 0 && spliterator.getComparator() != null) {
 683             // Do not propagate the SORTED characteristic if it does not correspond
 684             // to a natural sort order
 685             return characteristics & SPLITERATOR_CHARACTERISTICS_MASK & ~Spliterator.SORTED;
 686         }
 687         else {
 688             return characteristics & SPLITERATOR_CHARACTERISTICS_MASK;
 689         }
 690     }
 691 
 692     /**
 693      * Converts a spliterator characteristic bit set to stream flags.
 694      *
 695      * @param characteristics the spliterator characteristic bit set.
 696      * @return the stream flags.
 697      */
 698     static int fromCharacteristics(int characteristics) {
 699         return characteristics & SPLITERATOR_CHARACTERISTICS_MASK;
 700     }
 701 }