1 /*
2 * Copyright (c) 2012, 2017, 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 class="borderless">
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 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 */
204 enum 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