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