changeset 6078:121debc3d4be

Declarative flags defined using an enum.
author psandoz
date Mon, 15 Oct 2012 15:35:20 -0700
parents c6f42702e95f
children f55d346fb998
files src/share/classes/java/util/LinkedHashMap.java src/share/classes/java/util/LinkedHashSet.java src/share/classes/java/util/List.java src/share/classes/java/util/Set.java src/share/classes/java/util/SortedMap.java src/share/classes/java/util/SortedSet.java src/share/classes/java/util/streams/AbstractPipeline.java src/share/classes/java/util/streams/PipelineHelper.java src/share/classes/java/util/streams/Stream.java src/share/classes/java/util/streams/StreamAccessor.java src/share/classes/java/util/streams/StreamOpFlags.java src/share/classes/java/util/streams/Streams.java src/share/classes/java/util/streams/ops/BiFilterOp.java src/share/classes/java/util/streams/ops/BiMapOp.java src/share/classes/java/util/streams/ops/BiTeeOp.java src/share/classes/java/util/streams/ops/ConcatOp.java src/share/classes/java/util/streams/ops/CumulateOp.java src/share/classes/java/util/streams/ops/FilterOp.java src/share/classes/java/util/streams/ops/FlatMapOp.java src/share/classes/java/util/streams/ops/GroupByOp.java src/share/classes/java/util/streams/ops/IntermediateOp.java src/share/classes/java/util/streams/ops/LimitOp.java src/share/classes/java/util/streams/ops/MapExtractKeysOp.java src/share/classes/java/util/streams/ops/MapExtractValuesOp.java src/share/classes/java/util/streams/ops/MapFilterKeysOp.java src/share/classes/java/util/streams/ops/MapFilterValuesOp.java src/share/classes/java/util/streams/ops/MapLimitOp.java src/share/classes/java/util/streams/ops/MapMapValuesOp.java src/share/classes/java/util/streams/ops/MapOp.java src/share/classes/java/util/streams/ops/MapSkipOp.java src/share/classes/java/util/streams/ops/MapSwapOp.java src/share/classes/java/util/streams/ops/MappedOp.java src/share/classes/java/util/streams/ops/SkipOp.java src/share/classes/java/util/streams/ops/SortedOp.java src/share/classes/java/util/streams/ops/TeeOp.java src/share/classes/java/util/streams/ops/ToArrayOp.java src/share/classes/java/util/streams/ops/TreeUtils.java src/share/classes/java/util/streams/ops/UniqOp.java test-ng/tests/org/openjdk/tests/java/util/streams/StreamOpFlagsTest.java test-ng/tests/org/openjdk/tests/java/util/streams/ops/StreamOpTestCase.java test-ng/tests/org/openjdk/tests/java/util/streams/ops/ToArrayOpTest.java
diffstat 41 files changed, 457 insertions(+), 211 deletions(-) [+]
line wrap: on
line diff
--- a/src/share/classes/java/util/LinkedHashMap.java	Mon Oct 15 15:31:14 2012 -0700
+++ b/src/share/classes/java/util/LinkedHashMap.java	Mon Oct 15 15:35:20 2012 -0700
@@ -25,7 +25,7 @@
 
 package java.util;
 import java.util.streams.MapStream;
-import java.util.streams.Stream;
+import java.util.streams.StreamOpFlags;
 import java.util.streams.Streams;
 
 /**
@@ -494,6 +494,6 @@
 
     @Override
     public MapStream<K,V> stream() {
-        return Streams.stream(this, Stream.FLAG_ORDERED);
+        return Streams.stream(this, StreamOpFlags.IS_ORDERED);
     }
 }
--- a/src/share/classes/java/util/LinkedHashSet.java	Mon Oct 15 15:31:14 2012 -0700
+++ b/src/share/classes/java/util/LinkedHashSet.java	Mon Oct 15 15:35:20 2012 -0700
@@ -26,6 +26,7 @@
 package java.util;
 
 import java.util.streams.Stream;
+import java.util.streams.StreamOpFlags;
 import java.util.streams.Streams;
 
 /**
@@ -174,6 +175,6 @@
 
     @Override
     public Stream<E> stream() {
-        return Streams.stream(this, Stream.FLAG_DISTINCT | Stream.FLAG_ORDERED);
+        return Streams.stream(this, StreamOpFlags.IS_DISTINCT | StreamOpFlags.IS_ORDERED);
     }
 }
--- a/src/share/classes/java/util/List.java	Mon Oct 15 15:31:14 2012 -0700
+++ b/src/share/classes/java/util/List.java	Mon Oct 15 15:35:20 2012 -0700
@@ -26,6 +26,7 @@
 package java.util;
 
 import java.util.streams.Stream;
+import java.util.streams.StreamOpFlags;
 import java.util.streams.Streams;
 
 /**
@@ -616,6 +617,6 @@
     @Override
     Stream<E> stream() default {
         // @@@ If instance of RandomAccess, then can choose optimial implementation RandomAccessListStreamAccessor
-        return Streams.stream(this, Stream.FLAG_ORDERED);
+        return Streams.stream(this, StreamOpFlags.IS_ORDERED);
     }
 }
--- a/src/share/classes/java/util/Set.java	Mon Oct 15 15:31:14 2012 -0700
+++ b/src/share/classes/java/util/Set.java	Mon Oct 15 15:35:20 2012 -0700
@@ -26,6 +26,7 @@
 package java.util;
 
 import java.util.streams.Stream;
+import java.util.streams.StreamOpFlags;
 import java.util.streams.Streams;
 
 /**
@@ -388,6 +389,6 @@
 
     @Override
     Stream<E> stream() default {
-        return Streams.stream(this, Stream.FLAG_DISTINCT);
+        return Streams.stream(this, StreamOpFlags.IS_DISTINCT);
     }
 }
--- a/src/share/classes/java/util/SortedMap.java	Mon Oct 15 15:31:14 2012 -0700
+++ b/src/share/classes/java/util/SortedMap.java	Mon Oct 15 15:35:20 2012 -0700
@@ -26,7 +26,7 @@
 package java.util;
 
 import java.util.streams.MapStream;
-import java.util.streams.Stream;
+import java.util.streams.StreamOpFlags;
 import java.util.streams.Streams;
 
 /**
@@ -288,6 +288,6 @@
 
     @Override
     MapStream<K,V> stream() default {
-        return Streams.stream(this, Stream.FLAG_SORTED | Stream.FLAG_ORDERED);
+        return Streams.stream(this, StreamOpFlags.IS_SORTED | StreamOpFlags.IS_ORDERED);
     }
 }
--- a/src/share/classes/java/util/SortedSet.java	Mon Oct 15 15:31:14 2012 -0700
+++ b/src/share/classes/java/util/SortedSet.java	Mon Oct 15 15:35:20 2012 -0700
@@ -26,6 +26,7 @@
 package java.util;
 
 import java.util.streams.Stream;
+import java.util.streams.StreamOpFlags;
 import java.util.streams.Streams;
 
 /**
@@ -225,6 +226,6 @@
 
     @Override
     Stream<E> stream() default {
-        return Streams.stream(this, Stream.FLAG_DISTINCT | Stream.FLAG_SORTED | Stream.FLAG_ORDERED);
+        return Streams.stream(this, StreamOpFlags.IS_DISTINCT | StreamOpFlags.IS_SORTED | StreamOpFlags.IS_ORDERED);
     }
 }
--- a/src/share/classes/java/util/streams/AbstractPipeline.java	Mon Oct 15 15:31:14 2012 -0700
+++ b/src/share/classes/java/util/streams/AbstractPipeline.java	Mon Oct 15 15:35:20 2012 -0700
@@ -114,7 +114,7 @@
                 // @@@ Inherit other flags from pipeline e.g. the intermediate result may be sorted and/or distinct,
                 //     and is ordered
                 accessor = new Streams.SpliteratorStreamAccessor(intermediateResult.spliterator(),
-                                                                 intermediateResult.size(), Stream.FLAG_ORDERED);
+                                                                 intermediateResult.size(), StreamOpFlags.IS_ORDERED);
 
                 fromOp = ++upToOp;
             }
@@ -143,7 +143,7 @@
         final IntermediateOp[] ops;
         final int from;
         final int to;
-        final boolean isIntermediateShortCircuit;
+        final int opsFlags;
         final int flags;
 
         AbstractPipelineHelper(StreamAccessor<P_IN> source, IntermediateOp[] ops) {
@@ -151,19 +151,26 @@
         }
 
         AbstractPipelineHelper(StreamAccessor<P_IN> source, IntermediateOp[] ops, int from, int to) {
-            boolean isIntermediateShortCircuit = false;
-            int flags = source.getStreamFlags();
+            int opsFlags = StreamOpFlags.INITIAL_OPS_VALUE;
             for (int i = from; i < to; i++) {
-                isIntermediateShortCircuit |= ops[i].isShortCircuit();
-                flags = ops[i].getStreamFlags(flags);
+                int opFlags = ops[i].getOpFlags();
+                opsFlags = StreamOpFlags.combineOpFlags(opFlags, opsFlags);
             }
 
             this.source = source;
             this.ops = ops;
             this.from = from;
             this.to = to;
-            this.isIntermediateShortCircuit = isIntermediateShortCircuit;
-            this.flags = flags;
+            this.opsFlags = opsFlags;
+            this.flags = StreamOpFlags.combineStreamFlags(source.getStreamFlags(), opsFlags);
+        }
+
+        boolean isShortCircuit() {
+            return StreamOpFlags.SHORT_CIRCUIT.isKnown(flags);
+        }
+
+        boolean isInfintelySized() {
+            return StreamOpFlags.INFINITELY_SIZED.isKnown(flags);
         }
 
         public int getFlags() {
@@ -207,8 +214,8 @@
             // @@@ There is currently no mechanism to differentiate between SortedOp and CumulateOp, they are both
             //     stateful but the latter does not need to consume all the input
 
-            if (!terminal.isShortCircuit() && ((flags & Stream.FLAG_INFINITE) != 0)) {
-                throw new IllegalStateException("An stream of known infinite size is input to a non-short-circuiting terminal operation");
+            if (!terminal.isShortCircuit() && isInfintelySized()) {
+                throw new IllegalStateException("A stream of known infinite size is input to a non-short-circuiting terminal operation");
             }
         }
 
@@ -217,7 +224,7 @@
             Objects.requireNonNull(sink);
 
             // @@@ Need to check if any upstream streams have been pulled using iterator
-            if (isIntermediateShortCircuit || iterator != null) {
+            if (isShortCircuit() || iterator != null) {
                 into(AbstractPipeline.this.iterator(), sink);
             }  else {
                 getStreamAccessor().into(wrapSink(sink));
--- a/src/share/classes/java/util/streams/PipelineHelper.java	Mon Oct 15 15:31:14 2012 -0700
+++ b/src/share/classes/java/util/streams/PipelineHelper.java	Mon Oct 15 15:35:20 2012 -0700
@@ -34,8 +34,9 @@
 public interface PipelineHelper<P_IN, P_OUT> {
 
     /**
+     * @return the combined stream and operation flags.
      *
-     * @return the resultant flags of all source and the operations.
+     * @see {@link StreamOpFlags}
      */
     int getFlags();
 
--- a/src/share/classes/java/util/streams/Stream.java	Mon Oct 15 15:31:14 2012 -0700
+++ b/src/share/classes/java/util/streams/Stream.java	Mon Oct 15 15:35:20 2012 -0700
@@ -39,60 +39,6 @@
  */
 public interface Stream<T> extends BaseStream<T, Iterator<T>> {
 
-    /**
-     * Stream elements are distinct. No two elements contained in the stream
-     * are equivalent via {@code equals()} or equality ({@code ==}) operator.
-     */
-    public static final int FLAG_DISTINCT = 1 << 0;
-
-    /**
-     * Stream elements are sorted. Each element is greater or equal to the element which
-     * preceed it (if any) and less than or equal to the element which follows it (if any).
-     * <p>Implies encounter order.</p>
-     */
-    // @@@ logical or with FLAG_ORDERED? works in the positive sense but does not imply in the negative sense,
-    //     for example the map operation will result in output elements that are not known to be sorted but encounter
-    //     order is preserved
-    public static final int FLAG_SORTED = 1 << 1;
-
-    /**
-     * Stream elements have an encounter order.
-     * <p>Certain collections have an expected order when encoutering elements in the collection while traversing,
-     * such as an array or {@link List}. That order is referred to as encounter order.
-     * Other collections may have no such order, such as a {@link HashSet},
-     * or {@link HashMap} when traversing the keys.</p>
-     * <p>Encounter order is important when the order at the input to a pipeline should be preserved at the output,
-     * for example when a list of elements is mapped to another list of elements the encouter order of the output
-     * list should correlate with the encouter order of the input list.</p>
-     * <p>Encounter order is also relevant when choosing an algorithm to process elements in parallel.
-     * If encounter order is to be preserved the parallel algorithm will need to apply associative only functions
-     * i.e. a function can be applied to any grouping of elements but the order of elements cannot change.</p>
-     * <p>Stream elements sourced from an array have an encounter order that is also a spatial order.</p>
-     * <p>An infinite stream of elements may have an encounter order.</p>
-     */
-    public static final int FLAG_ORDERED = 1 << 2;
-
-    /**
-     * Stream size can be calculated in less than {@code O(n)} time.
-     */
-    public static final int FLAG_SIZED = 1 << 3;
-
-    /**
-     * Stream size is known to be infinite. Mutually exclusive to {@link #FLAG_SIZED}.
-     */
-    public static final int FLAG_INFINITE = 1 << 4;
-
-    /**
-     * Mask of state bits for defined states.
-     */
-    public static final int FLAG_MASK = (1 << 5) - 1;
-
-    /**
-     * Mask of undefined state bits.
-     */
-    public static final int FLAG_UNKNOWN_MASK_V1 = ~FLAG_MASK;
-
-
     Stream<T> filter(Predicate<? super T> predicate);
 
     <R> Stream<R> map(Mapper<? super T, ? extends R> mapper);
--- a/src/share/classes/java/util/streams/StreamAccessor.java	Mon Oct 15 15:31:14 2012 -0700
+++ b/src/share/classes/java/util/streams/StreamAccessor.java	Mon Oct 15 15:35:20 2012 -0700
@@ -53,6 +53,12 @@
      */
     Iterator<T> iterator();
 
+    /**
+     * Get the known properties of the stream.
+     *
+     * @return the known properties of the stream.
+     * @see {@link StreamOpFlags}
+     */
     public int getStreamFlags();
 
    /**
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/share/classes/java/util/streams/StreamOpFlags.java	Mon Oct 15 15:35:20 2012 -0700
@@ -0,0 +1,251 @@
+/*
+ * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package java.util.streams;
+
+/**
+ * Flags for known and not known properties of streams and operations.
+ *
+ * <p>A stream accessor can logically or flags for the set of properties of the stream.</p>
+ * <p>An operation can logically or flags the set of known and and not known properties of the output stream.</p>
+ *
+ */
+// @@@ When a new flag is added what should happen for existing operations?
+//     Need to move to a builder approach used by ops where the masks for the new flag are
+//     taken into account for default behaviour.
+public enum StreamOpFlags {
+
+    DISTINCT(0),
+
+    SORTED(1),
+
+    ORDERED(2),
+
+    SIZED(3),
+
+    INFINITELY_SIZED(4),
+
+    SHORT_CIRCUIT(5, false)
+    ;
+
+    /**
+     * The bit pattern for setting a flag.
+     */
+    private static final int SET_BITS = 0b01;
+
+    /**
+     * The bit pattern for clearing a flag.
+     */
+    private static final int CLEAR_BITS = 0b10;
+
+    /**
+     * The bit pattern for preserving a flag.
+     */
+    private static final int PRESERVE_BITS = 0b11;
+
+
+    private final boolean isStreamFlag;
+
+    private final int bitPosition;
+
+    private final int set;
+
+    private final int clear;
+
+    private final int preserve;
+
+    private StreamOpFlags(int position) {
+        this(position, true);
+    }
+
+    private StreamOpFlags(int position, boolean isStreamFlag) {
+        // Two bits per flag
+        position *= 2;
+        this.isStreamFlag = isStreamFlag;
+        this.bitPosition = position;
+        this.set = SET_BITS << position;
+        this.clear = CLEAR_BITS << position;
+        this.preserve = PRESERVE_BITS << position;
+    }
+
+    /**
+     * Check if a property is known on the combined stream and operations flags.
+     *
+     * @param flags the combined stream and operations flags.
+     * @return true if the property is known, otherwise false.
+     */
+    public boolean isKnown(int flags) {
+        return (flags & preserve) == set;
+    }
+
+    /**
+     * Check if a property is known on the combined operations flags.
+     *
+     * @param opFlags the combined operations flags.
+     * @return true if the property is known, otherwise false.
+     */
+    public boolean isKnownOnOpFlags(int opFlags) {
+        return (opFlags & set) > 0;
+    }
+
+    /**
+     * The initial value to be combined with the flags of the first operation in the pipeline.
+     */
+    public static final int INITIAL_OPS_VALUE = createMask(0b11, 0b00); // 0b00_11_11_11_11_11;
+
+    // Flag mask for stream and operation flags
+    private static final int        FLAG_MASK = createMask(0b11, 0b11); // 0b11_11_11_11_11_11;
+
+    // Flag mask for stream flags that are set
+    private static final int     FLAG_MASK_IS = createMask(0b01, 0b00); // 0b00_01_01_01_01_01;
+
+    // Flag mask for stream flags that are cleared
+    private static final int    FLAG_MASK_NOT = createMask(0b10, 0b00); // 0b00_10_10_10_10_10;
+
+    private static int createMask(int s, int o) {
+        int mask = 0;
+        for (StreamOpFlags flag : StreamOpFlags.values()) {
+            mask |= (flag.isStreamFlag) ? s << flag.bitPosition : o << flag.bitPosition;
+        }
+        return mask;
+    }
+
+    /**
+     * Stream elements are known to be distinct. No two elements contained in the stream
+     * are equivalent via {@code equals()} or equality ({@code ==}) operator.
+     */
+    public static final int IS_DISTINCT = DISTINCT.set;
+
+    /**
+     * Stream elements are not known to be distinct.
+     */
+    public static final int NOT_DISTINCT = DISTINCT.clear;
+
+    /**
+     * Stream elements are known to be sorted. Elements are {@code Comparable} and each
+     * element is greater or equal to the element which preceed it (if any) and
+     * less than or equal to the element which follows it (if any).
+     */
+    public static final int IS_SORTED = SORTED.set;
+
+    /**
+     * Stream elements are not known to be sorted.
+     */
+    public static final int NOT_SORTED = SORTED.clear;
+
+    /**
+     * Stream elements are known to have an encounter order.
+     * <p>Certain collections have an expected order when encoutering elements in the collection while traversing,
+     * such as an array or {@link java.util.List}. That order is referred to as encounter order.
+     * Other collections may have no such order, such as a {@link java.util.HashSet},
+     * or {@link java.util.HashMap} when traversing the keys.</p>
+     * <p>Encounter order is important when the order at the input to a pipeline should be preserved at the output,
+     * for example when a list of elements is mapped to another list of elements the encouter order of the output
+     * list should correlate with the encouter order of the input list.</p>
+     * <p>Encounter order is also relevant when choosing an algorithm to process elements in parallel.
+     * If encounter order is to be preserved the parallel algorithm will need to apply associative only functions
+     * i.e. a function can be applied to any grouping of elements but the order of elements cannot change.</p>
+     * <p>Stream elements sourced from an array have an encounter order that is also a spatial order.</p>
+     * <p>An infinite stream of elements may have an encounter order.</p>
+     */
+    public static final int IS_ORDERED = ORDERED.set;
+
+    /**
+     * Stream elements are not known to be ordered.
+     */
+    public static final int NOT_ORDERED = ORDERED.clear;
+
+    /**
+     * The size of the stream is known to be calculated in less than {@code O(n)} time and that
+     * size is known to be equal to the size of the stream source.
+     * <p>Mutually exclusive to {@link #IS_INFINITELY_SIZED}.</p>
+     */
+    public static final int IS_SIZED = SIZED.set;
+
+    /**
+     * The size of the stream is not known that it is not known to be equal to the size of the stream source.
+     */
+    public static final int NOT_SIZED = SIZED.clear;
+
+    /**
+     * The size of stream is known to be infinitely sized.
+     * <p>Mutually exclusive to {@link #IS_SIZED}.</p>
+     */
+    public static final int IS_INFINITELY_SIZED = INFINITELY_SIZED.set;
+
+    /**
+     * The size of the stream not known to the inifinitely sized.
+     */
+    public static final int NOT_INFINITELY_SIZED = INFINITELY_SIZED.clear;
+
+    /**
+     * The stream is known to be short circuited. Evaluation of the pipeline is constrained to be
+     * pull-oriented.  This is true for operations that may truncate or otherwise
+     * manipulate the stream contents.
+     */
+    public static final int IS_SHORT_CIRCUIT = SHORT_CIRCUIT.set;
+
+    private static int getMask(int flags) {
+        return (flags == 0)
+               ? FLAG_MASK
+               : ~(flags | ((FLAG_MASK_IS & flags) << 1) | ((FLAG_MASK_NOT & flags) >> 1));
+    }
+
+    /**
+     * Combine operation flags.
+     *
+     * <p>A flag value of 0b01 means the property is known on the output stream.</p>
+     * <p>A flag value of 0b10 means the property is not known on the output stream.</p>
+     * <p>A flag value of 0b11 means the property is preserved on the output stream.</p>
+     *
+     * @param opFlags the operation flags.
+     * @param opsFlags previously combined operation flags.
+     *                 The value {#link INITIAL_OPS_VALUE} must be used as the seed value.
+     * @return the result of combination.
+     */
+    public static int combineOpFlags(int opFlags, int opsFlags) {
+        // 0x01 or 0x10 nibbles are transformed to 0x11
+        // 0x00 nibbles remain unchanged
+        // Then all the bits are flipped
+        // Then the result is logically or'ed with the operation flags.
+        return (opsFlags & StreamOpFlags.getMask(opFlags)) | opFlags;
+    }
+
+    /**
+     * Combine stream flags with combined operation flags.
+     *
+     * <p>A flag value of 0b01 means the property is known on the output stream.</p>
+     *
+     * @param streamFlags the stream flags.
+     * @param opsFlags the combined operation flags.
+     * @return the result of combination.
+     */
+    public static int combineStreamFlags(int streamFlags, int opsFlags) {
+        // 0x01 nibbles are transformed to 0x11
+        // Then all the bits are flipped
+        // Then the result is logically and'ed with the combined operation flags
+        // 0x01 nibbles correspond to set flags
+        return (FLAG_MASK ^ ((FLAG_MASK_IS & streamFlags) << 1)) & opsFlags;
+    }
+}
--- a/src/share/classes/java/util/streams/Streams.java	Mon Oct 15 15:31:14 2012 -0700
+++ b/src/share/classes/java/util/streams/Streams.java	Mon Oct 15 15:35:20 2012 -0700
@@ -42,11 +42,11 @@
     // MapStream
 
     public static<K,V> MapStream<K,V> stream(Map<K,V> source) {
-        return new MapPipeline<>(new MapTraversableMapStreamAccessor<>(source, source.size(), Stream.FLAG_DISTINCT));
+        return new MapPipeline<>(new MapTraversableMapStreamAccessor<>(source, source.size(), StreamOpFlags.IS_DISTINCT));
     }
 
     public static<K,V> MapStream<K,V> stream(Map<K,V> source, int flags) {
-        return new MapPipeline<>(new MapTraversableMapStreamAccessor<>(source, source.size(), Stream.FLAG_DISTINCT | flags));
+        return new MapPipeline<>(new MapTraversableMapStreamAccessor<>(source, source.size(), StreamOpFlags.IS_DISTINCT | flags));
     }
 
     public static<K,V> MapStream<K,V> stream(MapTraversable<K,V> source) {
@@ -215,7 +215,7 @@
                 }
             };
 
-            return new ValuePipeline<>(new IteratorStreamAccessor<>(repeat, -1, Stream.FLAG_ORDERED));
+            return new ValuePipeline<>(new IteratorStreamAccessor<>(repeat, -1, StreamOpFlags.IS_ORDERED));
         }
     }
 
@@ -251,7 +251,7 @@
                 }
             };
 
-            return new ValuePipeline<>(new IteratorStreamAccessor<>(repeatedly,  -1, Stream.FLAG_ORDERED));
+            return new ValuePipeline<>(new IteratorStreamAccessor<>(repeatedly,  -1, StreamOpFlags.IS_ORDERED));
         }
     }
 
@@ -336,8 +336,8 @@
         public IteratorStreamAccessor(Iterator<T> it, int sizeOrUnknown, int flags) {
             this.it = it;
             this.sizeOrUnknown = sizeOrUnknown;
-            this.flags = (sizeOrUnknown >= 0 ? Stream.FLAG_SIZED : 0) |
-                   (flags & (Stream.FLAG_DISTINCT | Stream.FLAG_SORTED | Stream.FLAG_ORDERED));
+            this.flags = (sizeOrUnknown >= 0 ? StreamOpFlags.IS_SIZED : 0) |
+                   (flags & (StreamOpFlags.IS_DISTINCT | StreamOpFlags.IS_SORTED | StreamOpFlags.IS_ORDERED));
         }
 
         @Override
@@ -412,7 +412,7 @@
         @Override
         public int getStreamFlags() {
             // @@@ Should encounter order be set by default?
-            return Stream.FLAG_INFINITE | Stream.FLAG_ORDERED;
+            return StreamOpFlags.IS_INFINITELY_SIZED | StreamOpFlags.IS_ORDERED;
         }
 
         @Override
@@ -437,8 +437,8 @@
         public SpliteratorStreamAccessor(Spliterator<T> spliterator, int sizeOrUnknown, int flags) {
             this.spliterator = spliterator;
             this.sizeOrUnknown = sizeOrUnknown;
-            this.flags = (sizeOrUnknown >= 0 ? Stream.FLAG_SIZED : 0) |
-                         (flags & (Stream.FLAG_DISTINCT | Stream.FLAG_SORTED | Stream.FLAG_ORDERED));
+            this.flags = (sizeOrUnknown >= 0 ? StreamOpFlags.IS_SIZED : 0) |
+                         (flags & (StreamOpFlags.IS_DISTINCT | StreamOpFlags.IS_SORTED | StreamOpFlags.IS_ORDERED));
         }
 
         @Override
@@ -494,8 +494,8 @@
 
         TraversableStreamAccessor(Traversable<T> traversable, int sizeOrUnknown, int flags) {
             this.traversable = traversable;
-            this.flags = (sizeOrUnknown >= 0 ? Stream.FLAG_SIZED : 0) |
-                         (flags & (Stream.FLAG_DISTINCT | Stream.FLAG_SORTED | Stream.FLAG_ORDERED));
+            this.flags = (sizeOrUnknown >= 0 ? StreamOpFlags.IS_SIZED : 0) |
+                         (flags & (StreamOpFlags.IS_DISTINCT | StreamOpFlags.IS_SORTED | StreamOpFlags.IS_ORDERED));
             this.sizeOrUnknown = sizeOrUnknown;
         }
 
@@ -557,8 +557,8 @@
 
         MapTraversableMapStreamAccessor(MapTraversable<K,V> traversable, int sizeOrUnknown, int flags) {
             this.traversable = traversable;
-            this.flags = (sizeOrUnknown >= 0 ? Stream.FLAG_SIZED : 0) |
-                         (flags & (Stream.FLAG_DISTINCT | Stream.FLAG_SORTED | Stream.FLAG_ORDERED));
+            this.flags = (sizeOrUnknown >= 0 ? StreamOpFlags.IS_SIZED : 0) |
+                         (flags & (StreamOpFlags.IS_DISTINCT | StreamOpFlags.IS_SORTED | StreamOpFlags.IS_ORDERED));
             this.sizeOrUnknown = sizeOrUnknown;
         }
 
@@ -840,7 +840,7 @@
 
         @Override
         public int getStreamFlags() {
-            return Stream.FLAG_SIZED | Stream.FLAG_ORDERED;
+            return StreamOpFlags.IS_SIZED | StreamOpFlags.IS_ORDERED;
         }
 
         @Override
@@ -883,7 +883,7 @@
 
         @Override
         public int getStreamFlags() {
-            return Stream.FLAG_SIZED | Stream.FLAG_ORDERED;
+            return StreamOpFlags.IS_SIZED | StreamOpFlags.IS_ORDERED;
         }
 
         @Override
@@ -926,7 +926,7 @@
 
         @Override
         public int getStreamFlags() {
-            return Stream.FLAG_SIZED | Stream.FLAG_ORDERED;
+            return StreamOpFlags.IS_SIZED | StreamOpFlags.IS_ORDERED;
         }
 
         @Override
@@ -958,7 +958,7 @@
 
         @Override
         public int getStreamFlags() {
-            return Stream.FLAG_SIZED | Stream.FLAG_ORDERED;
+            return StreamOpFlags.IS_SIZED | StreamOpFlags.IS_ORDERED;
         }
 
         @Override
--- a/src/share/classes/java/util/streams/ops/BiFilterOp.java	Mon Oct 15 15:31:14 2012 -0700
+++ b/src/share/classes/java/util/streams/ops/BiFilterOp.java	Mon Oct 15 15:35:20 2012 -0700
@@ -27,7 +27,7 @@
 import java.util.*;
 import java.util.functions.BiPredicate;
 import java.util.streams.Sink;
-import java.util.streams.Stream;
+import java.util.streams.StreamOpFlags;
 import java.util.streams.StreamShape;
 
 /**
@@ -42,8 +42,8 @@
     }
 
     @Override
-    public int getStreamFlags(int upstreamFlags) {
-        return upstreamFlags & ~(Stream.FLAG_SIZED | Stream.FLAG_UNKNOWN_MASK_V1);
+    public int getOpFlags() {
+        return StreamOpFlags.NOT_SIZED;
     }
 
     @Override
--- a/src/share/classes/java/util/streams/ops/BiMapOp.java	Mon Oct 15 15:31:14 2012 -0700
+++ b/src/share/classes/java/util/streams/ops/BiMapOp.java	Mon Oct 15 15:35:20 2012 -0700
@@ -31,7 +31,7 @@
 import java.util.Objects;
 import java.util.functions.BiMapper;
 import java.util.streams.Sink;
-import java.util.streams.Stream;
+import java.util.streams.StreamOpFlags;
 import java.util.streams.StreamShape;
 
 /**
@@ -53,8 +53,8 @@
     }
 
     @Override
-    public int getStreamFlags(int upstreamFlags) {
-        return upstreamFlags & ~(Stream.FLAG_SORTED | Stream.FLAG_DISTINCT | Stream.FLAG_UNKNOWN_MASK_V1);
+    public int getOpFlags() {
+        return StreamOpFlags.NOT_SORTED | StreamOpFlags.NOT_DISTINCT;
     }
 
     @Override
--- a/src/share/classes/java/util/streams/ops/BiTeeOp.java	Mon Oct 15 15:31:14 2012 -0700
+++ b/src/share/classes/java/util/streams/ops/BiTeeOp.java	Mon Oct 15 15:35:20 2012 -0700
@@ -52,11 +52,6 @@
     }
 
     @Override
-    public int getStreamFlags(int upstreamFlags) {
-        return upstreamFlags & ~(Stream.FLAG_UNKNOWN_MASK_V1);
-    }
-
-    @Override
     public MapIterator<K, V> wrapIterator(final Iterator<Mapping<K, V>> source) {
         return iterator(MapIterator.IteratorAdapter.adapt(source), tee);
     }
--- a/src/share/classes/java/util/streams/ops/ConcatOp.java	Mon Oct 15 15:31:14 2012 -0700
+++ b/src/share/classes/java/util/streams/ops/ConcatOp.java	Mon Oct 15 15:35:20 2012 -0700
@@ -36,8 +36,8 @@
     }
 
     @Override
-    public int getStreamFlags(int upstreamFlags) {
-        return upstreamFlags & ~(Stream.FLAG_SIZED | Stream.FLAG_UNKNOWN_MASK_V1);
+    public int getOpFlags() {
+        return StreamOpFlags.NOT_SORTED | StreamOpFlags.NOT_DISTINCT | StreamOpFlags.NOT_SIZED;
     }
 
     @Override
--- a/src/share/classes/java/util/streams/ops/CumulateOp.java	Mon Oct 15 15:31:14 2012 -0700
+++ b/src/share/classes/java/util/streams/ops/CumulateOp.java	Mon Oct 15 15:35:20 2012 -0700
@@ -46,8 +46,8 @@
     }
 
     @Override
-    public int getStreamFlags(int upstreamFlags) {
-        return upstreamFlags & ~(Stream.FLAG_SORTED | Stream.FLAG_DISTINCT | Stream.FLAG_UNKNOWN_MASK_V1);
+    public int getOpFlags() {
+        return StreamOpFlags.NOT_SORTED | StreamOpFlags.NOT_DISTINCT;
     }
 
     @Override
--- a/src/share/classes/java/util/streams/ops/FilterOp.java	Mon Oct 15 15:31:14 2012 -0700
+++ b/src/share/classes/java/util/streams/ops/FilterOp.java	Mon Oct 15 15:35:20 2012 -0700
@@ -29,7 +29,7 @@
 import java.util.Objects;
 import java.util.functions.Predicate;
 import java.util.streams.Sink;
-import java.util.streams.Stream;
+import java.util.streams.StreamOpFlags;
 
 /**
  * FilterOp
@@ -44,8 +44,8 @@
     }
 
     @Override
-    public int getStreamFlags(int upstreamFlags) {
-        return upstreamFlags & ~(Stream.FLAG_SIZED | Stream.FLAG_UNKNOWN_MASK_V1);
+    public int getOpFlags() {
+        return StreamOpFlags.NOT_SIZED;
     }
 
     @Override
--- a/src/share/classes/java/util/streams/ops/FlatMapOp.java	Mon Oct 15 15:31:14 2012 -0700
+++ b/src/share/classes/java/util/streams/ops/FlatMapOp.java	Mon Oct 15 15:35:20 2012 -0700
@@ -28,10 +28,7 @@
 import java.util.NoSuchElementException;
 import java.util.Objects;
 import java.util.functions.FlatMapper;
-import java.util.streams.Sink;
-import java.util.streams.Stream;
-import java.util.streams.StreamBuilder;
-import java.util.streams.StreamBuilders;
+import java.util.streams.*;
 
 /**
  * FlatMapOp
@@ -47,8 +44,8 @@
     }
 
     @Override
-    public int getStreamFlags(int upstreamFlags) {
-        return upstreamFlags & ~(Stream.FLAG_SORTED | Stream.FLAG_DISTINCT | Stream.FLAG_ORDERED | Stream.FLAG_SIZED | Stream.FLAG_UNKNOWN_MASK_V1);
+    public int getOpFlags() {
+        return StreamOpFlags.NOT_SORTED | StreamOpFlags.NOT_DISTINCT | StreamOpFlags.NOT_ORDERED | StreamOpFlags.NOT_SIZED;
     }
 
     @Override
--- a/src/share/classes/java/util/streams/ops/GroupByOp.java	Mon Oct 15 15:31:14 2012 -0700
+++ b/src/share/classes/java/util/streams/ops/GroupByOp.java	Mon Oct 15 15:35:20 2012 -0700
@@ -91,7 +91,7 @@
     public <S> Map<K, Collection<T>> evaluateParallel(ParallelPipelineHelper<S, T> helper) {
         // @@@ If encounter order is required then a different algorithm will need to be used that preserves
         //     the order of the grouped elements, otherwise the order does not need to be preserved
-        if ((helper.getFlags() & Stream.FLAG_ORDERED) != 0) {
+        if (StreamOpFlags.ORDERED.isKnown(helper.getFlags())) {
             Logger.getLogger(getClass().getName()).log(Level.WARNING, "GroupByOp.evaluateParallel does not preserve encounter order");
         }
 
--- a/src/share/classes/java/util/streams/ops/IntermediateOp.java	Mon Oct 15 15:31:14 2012 -0700
+++ b/src/share/classes/java/util/streams/ops/IntermediateOp.java	Mon Oct 15 15:35:20 2012 -0700
@@ -29,26 +29,26 @@
 import java.util.streams.StreamShape;
 
 /**
- * An operation performed upon elements.
+ * An operation performed upon elements from an input stream to produce elements to
+ * an output stream.
  * <p>By default the operation is stateless and not short-circuiting.</p>
  *
- * @param <E_IN> Type of input elements to the operation.
+ * @param <E_IN>  Type of input elements to the operation.
  * @param <E_OUT> Type of output elements to the operation.
- *
  * @author Brian Goetz
  */
 public interface IntermediateOp<E_IN, E_OUT> {
-    public final static IntermediateOp<?,?>[] EMPTY_ARRAY = new IntermediateOp<?,?>[0];
 
     /**
-     * Return the resultant state of a stream utilizing this operation
-     * considering the state of the provided stream.
+     * Get the properties of the operation.
+     * <p>The properties correspond to the properties the output stream is
+     * known to have or is not known to have when this operation is applied, in
+     * encounter order, to elements of an input stream.</p>
      *
-     * @param upstreamFlags stream state of the upstream stream.
-     * @return the resultant state of a stream utilizing this operation
-     * considering the state of the provided stream.
+     * @return the properties of the operation.
+     * @see {@link java.util.streams.StreamOpFlags}
      */
-    int getStreamFlags(int upstreamFlags);
+    int getOpFlags() default { return 0; }
 
     /**
      * If {@code true} then operation is stateful and accumulates state.
@@ -58,13 +58,6 @@
     boolean isStateful() default { return false; }
 
     /**
-     * If {@code true}, then evaluation of the pipeline is constrained to be
-     * pull-oriented.  This is true for operations that may truncate or otherwise
-     * manipulate the stream contents.
-     */
-    boolean isShortCircuit() default { return false; }
-
-    /**
      * Return an iterator of the elements of the stream. The operation will be
      * performed upon each element as it is returned by {@code Iterator.next()}.
      *
@@ -77,10 +70,9 @@
      * Return a sink which will accept elements, perform the operation upon
      * each element and send it to the provided sink.
      *
-     *
      * @param sink elements will be sent to this sink after the processing.
      * @return a sink which will accept elements and perform the operation upon
-     * each element.
+     *         each element.
      */
     Sink<E_IN, ?, ?> wrapSink(Sink sink);
 
--- a/src/share/classes/java/util/streams/ops/LimitOp.java	Mon Oct 15 15:31:14 2012 -0700
+++ b/src/share/classes/java/util/streams/ops/LimitOp.java	Mon Oct 15 15:35:20 2012 -0700
@@ -43,13 +43,8 @@
     }
 
     @Override
-    public int getStreamFlags(int upstreamFlags) {
-        return upstreamFlags & ~(Stream.FLAG_SIZED | Stream.FLAG_INFINITE | Stream.FLAG_UNKNOWN_MASK_V1);
-    }
-
-    @Override
-    public boolean isShortCircuit() {
-        return true;
+    public int getOpFlags() {
+        return StreamOpFlags.NOT_SIZED | StreamOpFlags.NOT_INFINITELY_SIZED | StreamOpFlags.IS_SHORT_CIRCUIT;
     }
 
     @Override
--- a/src/share/classes/java/util/streams/ops/MapExtractKeysOp.java	Mon Oct 15 15:31:14 2012 -0700
+++ b/src/share/classes/java/util/streams/ops/MapExtractKeysOp.java	Mon Oct 15 15:35:20 2012 -0700
@@ -38,10 +38,6 @@
  * @author Brian Goetz
  */
 public class MapExtractKeysOp<K, V> implements IntermediateOp<Mapping<K, V>, K> {
-    @Override
-    public int getStreamFlags(int upstreamFlags) {
-        return upstreamFlags & ~Stream.FLAG_UNKNOWN_MASK_V1;
-    }
 
     @Override
     public StreamShape inputShape() {
--- a/src/share/classes/java/util/streams/ops/MapExtractValuesOp.java	Mon Oct 15 15:31:14 2012 -0700
+++ b/src/share/classes/java/util/streams/ops/MapExtractValuesOp.java	Mon Oct 15 15:35:20 2012 -0700
@@ -29,7 +29,7 @@
 import java.util.Mapping;
 import java.util.Objects;
 import java.util.streams.Sink;
-import java.util.streams.Stream;
+import java.util.streams.StreamOpFlags;
 import java.util.streams.StreamShape;
 
 /**
@@ -38,9 +38,10 @@
  * @author Brian Goetz
  */
 public class MapExtractValuesOp<K, V> implements IntermediateOp<Mapping<K, V>, V> {
+
     @Override
-    public int getStreamFlags(int upstreamFlags) {
-        return upstreamFlags & ~Stream.FLAG_UNKNOWN_MASK_V1;
+    public int getOpFlags() {
+        return StreamOpFlags.NOT_SORTED | StreamOpFlags.NOT_DISTINCT;
     }
 
     @Override
--- a/src/share/classes/java/util/streams/ops/MapFilterKeysOp.java	Mon Oct 15 15:31:14 2012 -0700
+++ b/src/share/classes/java/util/streams/ops/MapFilterKeysOp.java	Mon Oct 15 15:35:20 2012 -0700
@@ -27,11 +27,10 @@
 import java.util.Iterator;
 import java.util.MapIterator;
 import java.util.Mapping;
-import java.util.NoSuchElementException;
 import java.util.Objects;
 import java.util.functions.Predicate;
 import java.util.streams.Sink;
-import java.util.streams.Stream;
+import java.util.streams.StreamOpFlags;
 import java.util.streams.StreamShape;
 
 /**
@@ -47,8 +46,8 @@
     }
 
     @Override
-    public int getStreamFlags(int upstreamFlags) {
-        return upstreamFlags & ~(Stream.FLAG_SIZED | Stream.FLAG_UNKNOWN_MASK_V1);
+    public int getOpFlags() {
+        return StreamOpFlags.NOT_SIZED;
     }
 
     @Override
--- a/src/share/classes/java/util/streams/ops/MapFilterValuesOp.java	Mon Oct 15 15:31:14 2012 -0700
+++ b/src/share/classes/java/util/streams/ops/MapFilterValuesOp.java	Mon Oct 15 15:35:20 2012 -0700
@@ -27,11 +27,10 @@
 import java.util.Iterator;
 import java.util.MapIterator;
 import java.util.Mapping;
-import java.util.NoSuchElementException;
 import java.util.Objects;
 import java.util.functions.Predicate;
 import java.util.streams.Sink;
-import java.util.streams.Stream;
+import java.util.streams.StreamOpFlags;
 import java.util.streams.StreamShape;
 
 /**
@@ -47,8 +46,8 @@
     }
 
     @Override
-    public int getStreamFlags(int upstreamFlags) {
-        return upstreamFlags & ~(Stream.FLAG_SIZED | Stream.FLAG_UNKNOWN_MASK_V1);
+    public int getOpFlags() {
+        return StreamOpFlags.NOT_SIZED;
     }
 
     @Override
--- a/src/share/classes/java/util/streams/ops/MapLimitOp.java	Mon Oct 15 15:31:14 2012 -0700
+++ b/src/share/classes/java/util/streams/ops/MapLimitOp.java	Mon Oct 15 15:35:20 2012 -0700
@@ -39,13 +39,8 @@
     }
 
     @Override
-    public int getStreamFlags(int upstreamFlags) {
-        return upstreamFlags & ~(Stream.FLAG_SIZED | Stream.FLAG_INFINITE | Stream.FLAG_UNKNOWN_MASK_V1);
-    }
-
-    @Override
-    public boolean isShortCircuit() {
-        return true;
+    public int getOpFlags() {
+        return StreamOpFlags.NOT_SIZED | StreamOpFlags.NOT_INFINITELY_SIZED | StreamOpFlags.IS_SHORT_CIRCUIT;
     }
 
     @Override
--- a/src/share/classes/java/util/streams/ops/MapMapValuesOp.java	Mon Oct 15 15:31:14 2012 -0700
+++ b/src/share/classes/java/util/streams/ops/MapMapValuesOp.java	Mon Oct 15 15:35:20 2012 -0700
@@ -51,11 +51,6 @@
     }
 
     @Override
-    public int getStreamFlags(int upstreamFlags) {
-        return upstreamFlags & ~(Stream.FLAG_UNKNOWN_MASK_V1);
-    }
-
-    @Override
     public StreamShape inputShape() {
         return StreamShape.KEY_VALUE;
     }
--- a/src/share/classes/java/util/streams/ops/MapOp.java	Mon Oct 15 15:31:14 2012 -0700
+++ b/src/share/classes/java/util/streams/ops/MapOp.java	Mon Oct 15 15:35:20 2012 -0700
@@ -28,7 +28,7 @@
 import java.util.Objects;
 import java.util.functions.Mapper;
 import java.util.streams.Sink;
-import java.util.streams.Stream;
+import java.util.streams.StreamOpFlags;
 
 /**
  * MapOp
@@ -43,8 +43,8 @@
     }
 
     @Override
-    public int getStreamFlags(int upstreamFlags) {
-        return upstreamFlags & ~(Stream.FLAG_SORTED | Stream.FLAG_DISTINCT | Stream.FLAG_UNKNOWN_MASK_V1);
+    public int getOpFlags() {
+        return StreamOpFlags.NOT_SORTED | StreamOpFlags.NOT_DISTINCT;
     }
 
     @Override
--- a/src/share/classes/java/util/streams/ops/MapSkipOp.java	Mon Oct 15 15:31:14 2012 -0700
+++ b/src/share/classes/java/util/streams/ops/MapSkipOp.java	Mon Oct 15 15:35:20 2012 -0700
@@ -29,7 +29,7 @@
 import java.util.Mapping;
 import java.util.Objects;
 import java.util.streams.Sink;
-import java.util.streams.Stream;
+import java.util.streams.StreamOpFlags;
 import java.util.streams.StreamShape;
 
 public class MapSkipOp<K, V> implements StatefulOp<Mapping<K, V>, Mapping<K, V>> {
@@ -44,8 +44,8 @@
     }
 
     @Override
-    public int getStreamFlags(int upstreamFlags) {
-        return upstreamFlags & ~(Stream.FLAG_SIZED | Stream.FLAG_UNKNOWN_MASK_V1);
+    public int getOpFlags() {
+        return StreamOpFlags.NOT_SIZED;
     }
 
     @Override
--- a/src/share/classes/java/util/streams/ops/MapSwapOp.java	Mon Oct 15 15:31:14 2012 -0700
+++ b/src/share/classes/java/util/streams/ops/MapSwapOp.java	Mon Oct 15 15:35:20 2012 -0700
@@ -28,7 +28,7 @@
 import java.util.MapIterator;
 import java.util.Mapping;
 import java.util.streams.Sink;
-import java.util.streams.Stream;
+import java.util.streams.StreamOpFlags;
 import java.util.streams.StreamShape;
 
 /**
@@ -48,8 +48,8 @@
     }
 
     @Override
-    public int getStreamFlags(int upstreamFlags) {
-        return upstreamFlags & ~(Stream.FLAG_DISTINCT | Stream.FLAG_SORTED | Stream.FLAG_UNKNOWN_MASK_V1);
+    public int getOpFlags() {
+        return StreamOpFlags.NOT_SORTED | StreamOpFlags.NOT_DISTINCT;
     }
 
     @Override
--- a/src/share/classes/java/util/streams/ops/MappedOp.java	Mon Oct 15 15:31:14 2012 -0700
+++ b/src/share/classes/java/util/streams/ops/MappedOp.java	Mon Oct 15 15:35:20 2012 -0700
@@ -43,11 +43,6 @@
     }
 
     @Override
-    public int getStreamFlags(int upstreamFlags) {
-        return upstreamFlags & ~Stream.FLAG_UNKNOWN_MASK_V1;
-    }
-
-    @Override
     public MapIterator<T, R> wrapIterator(final Iterator<T> in) {
         return new MapIterator<T, R>() {
             boolean hasCurrent;
--- a/src/share/classes/java/util/streams/ops/SkipOp.java	Mon Oct 15 15:31:14 2012 -0700
+++ b/src/share/classes/java/util/streams/ops/SkipOp.java	Mon Oct 15 15:35:20 2012 -0700
@@ -27,7 +27,7 @@
 import java.util.Iterator;
 import java.util.Objects;
 import java.util.streams.Sink;
-import java.util.streams.Stream;
+import java.util.streams.StreamOpFlags;
 
 public class SkipOp<T> implements StatefulOp<T, T> {
 
@@ -41,8 +41,8 @@
     }
 
     @Override
-    public int getStreamFlags(int upstreamFlags) {
-        return upstreamFlags & ~(Stream.FLAG_SIZED | Stream.FLAG_UNKNOWN_MASK_V1);
+    public int getOpFlags() {
+        return StreamOpFlags.NOT_SIZED;
     }
 
     @Override
--- a/src/share/classes/java/util/streams/ops/SortedOp.java	Mon Oct 15 15:31:14 2012 -0700
+++ b/src/share/classes/java/util/streams/ops/SortedOp.java	Mon Oct 15 15:35:20 2012 -0700
@@ -26,7 +26,7 @@
 
 import java.util.*;
 import java.util.streams.Sink;
-import java.util.streams.Stream;
+import java.util.streams.StreamOpFlags;
 
 
 /**
@@ -53,6 +53,11 @@
         this((Comparator<? super T>) Comparators.naturalOrder());
     }
 
+    @Override
+    public int getOpFlags() {
+        return StreamOpFlags.IS_SORTED | StreamOpFlags.IS_ORDERED;
+    }
+
     /**
      * Sort using the provided comparator.
      *
@@ -111,9 +116,4 @@
             }
         };
     }
-
-    @Override
-    public int getStreamFlags(int upstreamFlags) {
-        return upstreamFlags | Stream.FLAG_SORTED | Stream.FLAG_SIZED | Stream.FLAG_ORDERED;
-    }
 }
--- a/src/share/classes/java/util/streams/ops/TeeOp.java	Mon Oct 15 15:31:14 2012 -0700
+++ b/src/share/classes/java/util/streams/ops/TeeOp.java	Mon Oct 15 15:35:20 2012 -0700
@@ -41,11 +41,6 @@
     }
 
     @Override
-    public int getStreamFlags(int upstreamFlags) {
-        return upstreamFlags & ~Stream.FLAG_UNKNOWN_MASK_V1;
-    }
-
-    @Override
     public Iterator<T> wrapIterator(final Iterator<T> source) {
         return iterator(source, tee);
     }
--- a/src/share/classes/java/util/streams/ops/ToArrayOp.java	Mon Oct 15 15:31:14 2012 -0700
+++ b/src/share/classes/java/util/streams/ops/ToArrayOp.java	Mon Oct 15 15:35:20 2012 -0700
@@ -96,7 +96,7 @@
         //     Require Spliterator.toArray with default method
 
         // Ensure tree is flattened
-        TreeUtils.Node<T> node = TreeUtils.collect(helper, false);
+        TreeUtils.Node<T> node = TreeUtils.collect(helper, true);
         @SuppressWarnings("unchecked")
         T[] array = (T[]) new Object[node.size()];
 
--- a/src/share/classes/java/util/streams/ops/TreeUtils.java	Mon Oct 15 15:31:14 2012 -0700
+++ b/src/share/classes/java/util/streams/ops/TreeUtils.java	Mon Oct 15 15:35:20 2012 -0700
@@ -45,7 +45,7 @@
         int size = spliterator.getSizeIfKnown();
         boolean noSplit = ((size <= helper.suggestTargetSize()) && (size >= 0))
                           || (spliterator.getNaturalSplits() == 0);
-        boolean splitSizesKnown = (helper.getFlags() & Stream.FLAG_SIZED) != 0;
+        boolean splitSizesKnown = StreamOpFlags.SIZED.isKnown(helper.getFlags());
         if (noSplit) {
             StreamBuilder<P_OUT> builder;
             if (size >= 0 && splitSizesKnown) {
@@ -206,17 +206,25 @@
             this.offset = offset;
         }
 
+        private ToArrayTask(ToArrayTask<T> parent, Node<T> node, int offset) {
+            super(parent);
+            this.array = parent.array;
+            this.node = node;
+            this.offset = offset;
+        }
+
         @Override
         public void compute() {
             if (node instanceof InternalNode) {
                 Node<T>[] nodes = ((InternalNode<T>) node).nodes();
                 setPendingCount(nodes.length - 1);
-                ToArrayTask<T> firstTask = new ToArrayTask<>(nodes[0], array, offset);
+                ToArrayTask<T> firstTask = new ToArrayTask<>(this, nodes[0], offset);
                 int size = nodes[0].size();
-                for (int i=1; i<nodes.length; i++) {
-                    ToArrayTask<T> task = new ToArrayTask<>(nodes[i], array, offset + size);
+                for (int i = 1; i < nodes.length; i++) {
+                    ToArrayTask<T> task = new ToArrayTask<>(this, nodes[i], offset + size);
+                    task.fork();
+
                     size += nodes[i].size();
-                    task.fork();
                 }
                 firstTask.compute();
             }
@@ -300,7 +308,7 @@
 
             @Override
             public Stream<T> stream() {
-                return Streams.stream(data.iterator(), data.size(), Stream.FLAG_ORDERED);
+                return Streams.stream(data.iterator(), data.size(), StreamOpFlags.IS_ORDERED);
             }
 
             @Override
@@ -367,12 +375,12 @@
 
         @Override
         public Stream<T> stream() {
-            return Streams.stream(iterator(), size(), Stream.FLAG_ORDERED);
+            return Streams.stream(iterator(), size(), StreamOpFlags.IS_ORDERED);
         }
 
         @Override
         public Stream<T> parallel() {
-            return Streams.parallel(spliterator(), size(), Stream.FLAG_ORDERED);
+            return Streams.parallel(spliterator(), size(), StreamOpFlags.IS_ORDERED);
         }
 
         @Override
--- a/src/share/classes/java/util/streams/ops/UniqOp.java	Mon Oct 15 15:31:14 2012 -0700
+++ b/src/share/classes/java/util/streams/ops/UniqOp.java	Mon Oct 15 15:35:20 2012 -0700
@@ -26,7 +26,8 @@
 
 import java.util.*;
 import java.util.concurrent.ConcurrentHashMap;
-import java.util.concurrent.CountedCompleter;
+import java.util.logging.Level;
+import java.util.logging.Logger;
 import java.util.streams.*;
 
 import static java.util.streams.ops.TreeUtils.node;
@@ -49,10 +50,10 @@
     }
 
     @Override
-    public int getStreamFlags(int upstreamFlags) {
+    public int getOpFlags() {
         // If the upstream is sorted, we need only cache last element
         // If the upstream is unique, this is a no-op
-        return upstreamFlags & ~(Stream.FLAG_SIZED | Stream.FLAG_UNKNOWN_MASK_V1) | Stream.FLAG_DISTINCT;
+        return StreamOpFlags.IS_DISTINCT | StreamOpFlags.NOT_SIZED;
     }
 
     @Override
@@ -122,6 +123,10 @@
 
     @Override
     public <S> TreeUtils.Node<T> evaluateParallel(ParallelPipelineHelper<S, T> helper) {
+        if (StreamOpFlags.ORDERED.isKnown(helper.getFlags())) {
+            Logger.getLogger(getClass().getName()).log(Level.WARNING, "UniqOp.evaluateParallel does not preserve encounter order");
+        }
+
         final ConcurrentHashMap<T, Boolean> map = new ConcurrentHashMap();
 
         // Cache the sink chain, so it can be reused by all F/J leaf tasks
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test-ng/tests/org/openjdk/tests/java/util/streams/StreamOpFlagsTest.java	Mon Oct 15 15:35:20 2012 -0700
@@ -0,0 +1,63 @@
+/*
+ * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.openjdk.tests.java.util.streams;
+
+import org.testng.annotations.Test;
+
+import java.util.Arrays;
+import java.util.List;
+import java.util.streams.StreamOpFlags;
+
+import static org.testng.Assert.assertFalse;
+import static org.testng.Assert.assertTrue;
+
+@Test
+public class StreamOpFlagsTest {
+
+    public void test() {
+        int sourceFlags = StreamOpFlags.IS_SIZED | StreamOpFlags.IS_DISTINCT;
+
+        List<Integer> ops = Arrays.asList(StreamOpFlags.NOT_SIZED, StreamOpFlags.IS_ORDERED | StreamOpFlags.IS_SORTED);
+
+        int opsFlags = StreamOpFlags.INITIAL_OPS_VALUE;
+        for (int opFlags : ops) {
+            opsFlags = StreamOpFlags.combineOpFlags(opFlags, opsFlags);
+        }
+        int flags = StreamOpFlags.combineStreamFlags(sourceFlags, opsFlags);
+
+        assertFalse(StreamOpFlags.SIZED.isKnown(flags));
+        assertTrue(StreamOpFlags.DISTINCT.isKnown(flags));
+        assertTrue(StreamOpFlags.SORTED.isKnown(flags));
+        assertTrue(StreamOpFlags.ORDERED.isKnown(flags));
+        assertFalse(StreamOpFlags.INFINITELY_SIZED.isKnown(flags));
+
+        assertFalse(StreamOpFlags.SIZED.isKnownOnOpFlags(flags));
+        assertTrue(StreamOpFlags.DISTINCT.isKnownOnOpFlags(flags));
+        assertTrue(StreamOpFlags.SORTED.isKnownOnOpFlags(flags));
+        assertTrue(StreamOpFlags.ORDERED.isKnownOnOpFlags(flags));
+        assertTrue(StreamOpFlags.INFINITELY_SIZED.isKnownOnOpFlags(flags));
+    }
+
+}
--- a/test-ng/tests/org/openjdk/tests/java/util/streams/ops/StreamOpTestCase.java	Mon Oct 15 15:31:14 2012 -0700
+++ b/test-ng/tests/org/openjdk/tests/java/util/streams/ops/StreamOpTestCase.java	Mon Oct 15 15:35:20 2012 -0700
@@ -47,6 +47,7 @@
  */
 @Test
 public abstract class StreamOpTestCase extends Assert {
+    public final static IntermediateOp<?,?>[] EMPTY_OP_ARRAY = new IntermediateOp<?,?>[0];
 
     @SuppressWarnings("unchecked")
     protected static <T, U> StreamResult<U> exerciseOps(TestData<T> data, IntermediateOp... ops) {
@@ -278,7 +279,7 @@
     @SuppressWarnings("rawtypes")
     private static boolean isShortCircuit(IntermediateOp... ops) {
         for (IntermediateOp op : ops) {
-            if (op.isShortCircuit()) {
+            if (StreamOpFlags.SHORT_CIRCUIT.isKnownOnOpFlags(op.getOpFlags())) {
                 return true;
             }
         }
--- a/test-ng/tests/org/openjdk/tests/java/util/streams/ops/ToArrayOpTest.java	Mon Oct 15 15:31:14 2012 -0700
+++ b/test-ng/tests/org/openjdk/tests/java/util/streams/ops/ToArrayOpTest.java	Mon Oct 15 15:35:20 2012 -0700
@@ -55,7 +55,7 @@
 
     @Test(dataProvider = "opArrays", dataProviderClass = StreamTestDataProvider.class)
     public void testOps(String name, TestData<Integer> data) {
-        exerciseOps(data, Arrays::equals, ToArrayOp.<Integer>singleton(), IntermediateOp.EMPTY_ARRAY);
+        exerciseOps(data, Arrays::equals, ToArrayOp.<Integer>singleton(), EMPTY_OP_ARRAY);
     }
 
     @Test(dataProvider = "opArrays", dataProviderClass = StreamTestDataProvider.class)