• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * This code is free software; you can redistribute it and/or modify it
6  * under the terms of the GNU General Public License version 2 only, as
7  * published by the Free Software Foundation.  Oracle designates this
8  * particular file as subject to the "Classpath" exception as provided
9  * by Oracle in the LICENSE file that accompanied this code.
10  *
11  * This code is distributed in the hope that it will be useful, but WITHOUT
12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
14  * version 2 for more details (a copy is included in the LICENSE file that
15  * accompanied this code).
16  *
17  * You should have received a copy of the GNU General Public License version
18  * 2 along with this work; if not, write to the Free Software Foundation,
19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20  *
21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22  * or visit www.oracle.com if you need additional information or have any
23  * questions.
24  */
25 package java.util.stream;
26 
27 import java.util.EnumMap;
28 import java.util.Map;
29 import java.util.Spliterator;
30 
31 /**
32  * Flags corresponding to characteristics of streams and operations. Flags are
33  * utilized by the stream framework to control, specialize or optimize
34  * computation.
35  *
36  * <p>
37  * Stream flags may be used to describe characteristics of several different
38  * entities associated with streams: stream sources, intermediate operations,
39  * and terminal operations.  Not all stream flags are meaningful for all
40  * entities; the following table summarizes which flags are meaningful in what
41  * contexts:
42  *
43  * <div>
44  * <table>
45  *   <caption>Type Characteristics</caption>
46  *   <thead class="tableSubHeadingColor">
47  *     <tr>
48  *       <th colspan="2">&nbsp;</th>
49  *       <th>{@code DISTINCT}</th>
50  *       <th>{@code SORTED}</th>
51  *       <th>{@code ORDERED}</th>
52  *       <th>{@code SIZED}</th>
53  *       <th>{@code SHORT_CIRCUIT}</th>
54  *     </tr>
55  *   </thead>
56  *   <tbody>
57  *      <tr>
58  *        <th colspan="2" class="tableSubHeadingColor">Stream source</th>
59  *        <td>Y</td>
60  *        <td>Y</td>
61  *        <td>Y</td>
62  *        <td>Y</td>
63  *        <td>N</td>
64  *      </tr>
65  *      <tr>
66  *        <th colspan="2" class="tableSubHeadingColor">Intermediate operation</th>
67  *        <td>PCI</td>
68  *        <td>PCI</td>
69  *        <td>PCI</td>
70  *        <td>PC</td>
71  *        <td>PI</td>
72  *      </tr>
73  *      <tr>
74  *        <th colspan="2" class="tableSubHeadingColor">Terminal operation</th>
75  *        <td>N</td>
76  *        <td>N</td>
77  *        <td>PC</td>
78  *        <td>N</td>
79  *        <td>PI</td>
80  *      </tr>
81  *   </tbody>
82  *   <tfoot>
83  *       <tr>
84  *         <th class="tableSubHeadingColor" colspan="2">Legend</th>
85  *         <th colspan="6" rowspan="7">&nbsp;</th>
86  *       </tr>
87  *       <tr>
88  *         <th class="tableSubHeadingColor">Flag</th>
89  *         <th class="tableSubHeadingColor">Meaning</th>
90  *         <th colspan="6"></th>
91  *       </tr>
92  *       <tr><td>Y</td><td>Allowed</td></tr>
93  *       <tr><td>N</td><td>Invalid</td></tr>
94  *       <tr><td>P</td><td>Preserves</td></tr>
95  *       <tr><td>C</td><td>Clears</td></tr>
96  *       <tr><td>I</td><td>Injects</td></tr>
97  *   </tfoot>
98  * </table>
99  * </div>
100  *
101  * <p>In the above table, "PCI" means "may preserve, clear, or inject"; "PC"
102  * means "may preserve or clear", "PI" means "may preserve or inject", and "N"
103  * means "not valid".
104  *
105  * <p>Stream flags are represented by unioned bit sets, so that a single word
106  * may describe all the characteristics of a given stream entity, and that, for
107  * example, the flags for a stream source can be efficiently combined with the
108  * flags for later operations on that stream.
109  *
110  * <p>The bit masks {@link #STREAM_MASK}, {@link #OP_MASK}, and
111  * {@link #TERMINAL_OP_MASK} can be ANDed with a bit set of stream flags to
112  * produce a mask containing only the valid flags for that entity type.
113  *
114  * <p>When describing a stream source, one only need describe what
115  * characteristics that stream has; when describing a stream operation, one need
116  * describe whether the operation preserves, injects, or clears that
117  * characteristic.  Accordingly, two bits are used for each flag, so as to allow
118  * representing not only the presence of of a characteristic, but how an
119  * operation modifies that characteristic.  There are two common forms in which
120  * flag bits are combined into an {@code int} bit set.  <em>Stream flags</em>
121  * are a unioned bit set constructed by ORing the enum characteristic values of
122  * {@link #set()} (or, more commonly, ORing the corresponding static named
123  * constants prefixed with {@code IS_}).  <em>Operation flags</em> are a unioned
124  * bit set constructed by ORing the enum characteristic values of {@link #set()}
125  * or {@link #clear()} (to inject, or clear, respectively, the corresponding
126  * flag), or more commonly ORing the corresponding named constants prefixed with
127  * {@code IS_} or {@code NOT_}.  Flags that are not marked with {@code IS_} or
128  * {@code NOT_} are implicitly treated as preserved.  Care must be taken when
129  * combining bitsets that the correct combining operations are applied in the
130  * correct order.
131  *
132  * <p>
133  * With the exception of {@link #SHORT_CIRCUIT}, stream characteristics can be
134  * derived from the equivalent {@link java.util.Spliterator} characteristics:
135  * {@link java.util.Spliterator#DISTINCT}, {@link java.util.Spliterator#SORTED},
136  * {@link java.util.Spliterator#ORDERED}, and
137  * {@link java.util.Spliterator#SIZED}.  A spliterator characteristics bit set
138  * can be converted to stream flags using the method
139  * {@link #fromCharacteristics(java.util.Spliterator)} and converted back using
140  * {@link #toCharacteristics(int)}.  (The bit set
141  * {@link #SPLITERATOR_CHARACTERISTICS_MASK} is used to AND with a bit set to
142  * produce a valid spliterator characteristics bit set that can be converted to
143  * stream flags.)
144  *
145  * <p>
146  * The source of a stream encapsulates a spliterator. The characteristics of
147  * that source spliterator when transformed to stream flags will be a proper
148  * subset of stream flags of that stream.
149  * For example:
150  * <pre> {@code
151  *     Spliterator s = ...;
152  *     Stream stream = Streams.stream(s);
153  *     flagsFromSplitr = fromCharacteristics(s.characteristics());
154  *     assert(flagsFromSplitr & stream.getStreamFlags() == flagsFromSplitr);
155  * }</pre>
156  *
157  * <p>
158  * An intermediate operation, performed on an input stream to create a new
159  * output stream, may preserve, clear or inject stream or operation
160  * characteristics.  Similarly, a terminal operation, performed on an input
161  * stream to produce an output result may preserve, clear or inject stream or
162  * operation characteristics.  Preservation means that if that characteristic
163  * is present on the input, then it is also present on the output.  Clearing
164  * means that the characteristic is not present on the output regardless of the
165  * input.  Injection means that the characteristic is present on the output
166  * regardless of the input.  If a characteristic is not cleared or injected then
167  * it is implicitly preserved.
168  *
169  * <p>
170  * A pipeline consists of a stream source encapsulating a spliterator, one or
171  * more intermediate operations, and finally a terminal operation that produces
172  * a result.  At each stage of the pipeline, a combined stream and operation
173  * flags can be calculated, using {@link #combineOpFlags(int, int)}.  Such flags
174  * ensure that preservation, clearing and injecting information is retained at
175  * each stage.
176  *
177  * The combined stream and operation flags for the source stage of the pipeline
178  * is calculated as follows:
179  * <pre> {@code
180  *     int flagsForSourceStage = combineOpFlags(sourceFlags, INITIAL_OPS_VALUE);
181  * }</pre>
182  *
183  * The combined stream and operation flags of each subsequent intermediate
184  * operation stage in the pipeline is calculated as follows:
185  * <pre> {@code
186  *     int flagsForThisStage = combineOpFlags(flagsForPreviousStage, thisOpFlags);
187  * }</pre>
188  *
189  * Finally the flags output from the last intermediate operation of the pipeline
190  * are combined with the operation flags of the terminal operation to produce
191  * the flags output from the pipeline.
192  *
193  * <p>Those flags can then be used to apply optimizations. For example, if
194  * {@code SIZED.isKnown(flags)} returns true then the stream size remains
195  * constant throughout the pipeline, this information can be utilized to
196  * pre-allocate data structures and combined with
197  * {@link java.util.Spliterator#SUBSIZED} that information can be utilized to
198  * perform concurrent in-place updates into a shared array.
199  *
200  * For specific details see the {@link AbstractPipeline} constructors.
201  *
202  * @since 1.8
203  * @hide Visible for CTS testing only (OpenJDK8 tests).
204  */
205 public enum StreamOpFlag {
206 
207     /*
208      * Each characteristic takes up 2 bits in a bit set to accommodate
209      * preserving, clearing and setting/injecting information.
210      *
211      * This applies to stream flags, intermediate/terminal operation flags, and
212      * combined stream and operation flags. Even though the former only requires
213      * 1 bit of information per characteristic, is it more efficient when
214      * combining flags to align set and inject bits.
215      *
216      * Characteristics belong to certain types, see the Type enum. Bit masks for
217      * the types are constructed as per the following table:
218      *
219      *                        DISTINCT  SORTED  ORDERED  SIZED  SHORT_CIRCUIT
220      *          SPLITERATOR      01       01       01      01        00
221      *               STREAM      01       01       01      01        00
222      *                   OP      11       11       11      10        01
223      *          TERMINAL_OP      00       00       10      00        01
224      * UPSTREAM_TERMINAL_OP      00       00       10      00        00
225      *
226      * 01 = set/inject
227      * 10 = clear
228      * 11 = preserve
229      *
230      * Construction of the columns is performed using a simple builder for
231      * non-zero values.
232      */
233 
234 
235     // The following flags correspond to characteristics on Spliterator
236     // and the values MUST be equal.
237     //
238 
239     /**
240      * Characteristic value signifying that, for each pair of
241      * encountered elements in a stream {@code x, y}, {@code !x.equals(y)}.
242      * <p>
243      * A stream may have this value or an intermediate operation can preserve,
244      * clear or inject this value.
245      */
246     // 0, 0x00000001
247     // Matches Spliterator.DISTINCT
248     DISTINCT(0,
249              set(Type.SPLITERATOR).set(Type.STREAM).setAndClear(Type.OP)),
250 
251     /**
252      * Characteristic value signifying that encounter order follows a natural
253      * sort order of comparable elements.
254      * <p>
255      * A stream can have this value or an intermediate operation can preserve,
256      * clear or inject this value.
257      * <p>
258      * Note: The {@link java.util.Spliterator#SORTED} characteristic can define
259      * a sort order with an associated non-null comparator.  Augmenting flag
260      * state with addition properties such that those properties can be passed
261      * to operations requires some disruptive changes for a singular use-case.
262      * Furthermore, comparing comparators for equality beyond that of identity
263      * is likely to be unreliable.  Therefore the {@code SORTED} characteristic
264      * for a defined non-natural sort order is not mapped internally to the
265      * {@code SORTED} flag.
266      */
267     // 1, 0x00000004
268     // Matches Spliterator.SORTED
269     SORTED(1,
270            set(Type.SPLITERATOR).set(Type.STREAM).setAndClear(Type.OP)),
271 
272     /**
273      * Characteristic value signifying that an encounter order is
274      * defined for stream elements.
275      * <p>
276      * A stream can have this value, an intermediate operation can preserve,
277      * clear or inject this value, or a terminal operation can preserve or clear
278      * this value.
279      */
280     // 2, 0x00000010
281     // Matches Spliterator.ORDERED
282     ORDERED(2,
283             set(Type.SPLITERATOR).set(Type.STREAM).setAndClear(Type.OP).clear(Type.TERMINAL_OP)
284                     .clear(Type.UPSTREAM_TERMINAL_OP)),
285 
286     /**
287      * Characteristic value signifying that size of the stream
288      * is of a known finite size that is equal to the known finite
289      * size of the source spliterator input to the first stream
290      * in the pipeline.
291      * <p>
292      * A stream can have this value or an intermediate operation can preserve or
293      * clear this value.
294      */
295     // 3, 0x00000040
296     // Matches Spliterator.SIZED
297     SIZED(3,
298           set(Type.SPLITERATOR).set(Type.STREAM).clear(Type.OP)),
299 
300     // The following Spliterator characteristics are not currently used but a
301     // gap in the bit set is deliberately retained to enable corresponding
302     // stream flags if//when required without modification to other flag values.
303     //
304     // 4, 0x00000100 NONNULL(4, ...
305     // 5, 0x00000400 IMMUTABLE(5, ...
306     // 6, 0x00001000 CONCURRENT(6, ...
307     // 7, 0x00004000 SUBSIZED(7, ...
308 
309     // The following 4 flags are currently undefined and a free for any further
310     // spliterator characteristics.
311     //
312     //  8, 0x00010000
313     //  9, 0x00040000
314     // 10, 0x00100000
315     // 11, 0x00400000
316 
317     // The following flags are specific to streams and operations
318     //
319 
320     /**
321      * Characteristic value signifying that an operation may short-circuit the
322      * stream.
323      * <p>
324      * An intermediate operation can preserve or inject this value,
325      * or a terminal operation can preserve or inject this value.
326      */
327     // 12, 0x01000000
328     SHORT_CIRCUIT(12,
329                   set(Type.OP).set(Type.TERMINAL_OP));
330 
331     // The following 2 flags are currently undefined and a free for any further
332     // stream flags if/when required
333     //
334     // 13, 0x04000000
335     // 14, 0x10000000
336     // 15, 0x40000000
337 
338     /**
339      * Type of a flag
340      */
341     enum Type {
342         /**
343          * The flag is associated with spliterator characteristics.
344          */
345         SPLITERATOR,
346 
347         /**
348          * The flag is associated with stream flags.
349          */
350         STREAM,
351 
352         /**
353          * The flag is associated with intermediate operation flags.
354          */
355         OP,
356 
357         /**
358          * The flag is associated with terminal operation flags.
359          */
360         TERMINAL_OP,
361 
362         /**
363          * The flag is associated with terminal operation flags that are
364          * propagated upstream across the last stateful operation boundary
365          */
366         UPSTREAM_TERMINAL_OP
367     }
368 
369     /**
370      * The bit pattern for setting/injecting a flag.
371      */
372     private static final int SET_BITS = 0b01;
373 
374     /**
375      * The bit pattern for clearing a flag.
376      */
377     private static final int CLEAR_BITS = 0b10;
378 
379     /**
380      * The bit pattern for preserving a flag.
381      */
382     private static final int PRESERVE_BITS = 0b11;
383 
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