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"> </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"> </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 set(Type t)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 MaskBuilder(Map<Type, Integer> map)391 MaskBuilder(Map<Type, Integer> map) { 392 this.map = map; 393 } 394 mask(Type t, Integer i)395 MaskBuilder mask(Type t, Integer i) { 396 map.put(t, i); 397 return this; 398 } 399 set(Type t)400 MaskBuilder set(Type t) { 401 return mask(t, SET_BITS); 402 } 403 clear(Type t)404 MaskBuilder clear(Type t) { 405 return mask(t, CLEAR_BITS); 406 } 407 setAndClear(Type t)408 MaskBuilder setAndClear(Type t) { 409 return mask(t, PRESERVE_BITS); 410 } 411 build()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 StreamOpFlag(int position, MaskBuilder maskBuilder)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 */ set()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 */ clear()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 */ isStreamFlag()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 */ isKnown(int flags)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 */ isCleared(int flags)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 */ isPreserved(int flags)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 */ canSet(Type t)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 createMask(Type t)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 createFlagMask()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 getMask(int flags)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 */ combineOpFlags(int newStreamOrOpFlags, int prevCombOpFlags)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 */ toStreamFlags(int combOpFlags)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 */ toCharacteristics(int streamFlags)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 */ fromCharacteristics(Spliterator<?> spliterator)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 */ fromCharacteristics(int characteristics)751 public static int fromCharacteristics(int characteristics) { 752 return characteristics & SPLITERATOR_CHARACTERISTICS_MASK; 753 } 754 } 755