You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@tapestry.apache.org by hl...@apache.org on 2010/05/31 19:34:49 UTC

svn commit: r949812 - in /tapestry/tapestry5/trunk/tapestry-ioc/src: main/java/org/apache/tapestry5/func/ test/java/org/apache/tapestry5/func/

Author: hlship
Date: Mon May 31 17:34:48 2010
New Revision: 949812

URL: http://svn.apache.org/viewvc?rev=949812&view=rev
Log:
Initial work on making most Flow operations lazy.

Added:
    tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/func/AbstractFlow.java   (with props)
    tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/func/ConcatFlow.java   (with props)
    tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/func/EmptyFlow.java   (with props)
    tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/func/FilteredFlow.java   (with props)
    tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/func/MappedFlow.java   (with props)
Modified:
    tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/func/ArrayFlow.java
    tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/func/F.java
    tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/func/Flow.java
    tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/func/Mapper.java
    tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/func/Predicate.java
    tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/func/Worker.java
    tapestry/tapestry5/trunk/tapestry-ioc/src/test/java/org/apache/tapestry5/func/FuncTest.java

Added: tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/func/AbstractFlow.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/func/AbstractFlow.java?rev=949812&view=auto
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/func/AbstractFlow.java (added)
+++ tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/func/AbstractFlow.java Mon May 31 17:34:48 2010
@@ -0,0 +1,175 @@
+// Copyright 2010 The Apache Software Foundation
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package org.apache.tapestry5.func;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.Iterator;
+import java.util.List;
+
+import org.apache.tapestry5.ioc.internal.util.Defense;
+
+/**
+ * Abstract base class for implementations of {@link Flow}. Subclasses typically override some methods
+ * for either efficiency, or for the concern they embrace.
+ * 
+ * @since 5.2.0
+ */
+abstract class AbstractFlow<T> implements Flow<T>
+{
+    private <X> X nyi()
+    {
+        throw new RuntimeException("Not yet implemented.");
+    }
+
+    /**
+     * Method limited to just AbstractFlow and its subclasses. Forces a resolve of the entire Flow,
+     * and results in a mutable list of the values in the flow.
+     */
+    List<T> toMutableList()
+    {
+        ArrayList<T> result = new ArrayList<T>();
+
+        Flow<T> cursor = this;
+
+        while (!cursor.isEmpty())
+        {
+            result.add(cursor.first());
+            cursor = cursor.rest();
+        }
+
+        return result;
+    }
+
+    public Iterator<T> iterator()
+    {
+        return new Iterator<T>()
+        {
+            private Flow<T> current = AbstractFlow.this;
+
+            public boolean hasNext()
+            {
+                return !current.isEmpty();
+            }
+
+            public T next()
+            {
+                T next = current.first();
+
+                current = current.rest();
+
+                return next;
+            }
+
+            public void remove()
+            {
+                throw new UnsupportedOperationException("Flows are immutable.");
+            }
+
+        };
+    }
+
+    public Flow<T> concat(List<? extends T> list)
+    {
+        return concat(F.flow(list));
+    }
+
+    public <V extends T> Flow<T> append(V... values)
+    {
+        return concat(F.flow(values));
+    }
+
+    public Flow<T> concat(Flow<? extends T> other)
+    {
+        // Possible optimization is to check for EmptyFlow here (but not isEmpty(),
+        // so as not to prematurely realize values in the Flow).
+        return new ConcatFlow<T>(this, other);
+    }
+
+    /** Subclasses may override this for efficiency. */
+    public Flow<T> each(Worker<? super T> worker)
+    {
+        Flow<T> cursor = this;
+        while (!cursor.isEmpty())
+        {
+            worker.work(cursor.first());
+            cursor = cursor.rest();
+        }
+
+        return this;
+    }
+
+    public Flow<T> filter(Predicate<? super T> predicate)
+    {
+        Defense.notNull(predicate, "predicate");
+
+        return new FilteredFlow<T>(predicate, this);
+    }
+
+    public <X> Flow<X> map(Mapper<T, X> mapper)
+    {
+        Defense.notNull(mapper, "mapper");
+
+        return new MappedFlow<T, X>(mapper, this);
+    }
+
+    public <A> A reduce(Reducer<A, T> reducer, A initial)
+    {
+        Defense.notNull(reducer, "reducer");
+
+        A accumulator = initial;
+
+        Flow<T> cursor = this;
+
+        while (!cursor.isEmpty())
+        {
+            accumulator = reducer.reduce(accumulator, cursor.first());
+            cursor = cursor.rest();
+        }
+
+        return accumulator;
+    }
+
+    public Flow<T> remove(Predicate<? super T> predicate)
+    {
+        Defense.notNull(predicate, "predicate");
+
+        return filter(predicate.invert());
+    }
+
+    public Flow<T> reverse()
+    {
+        return nyi();
+    }
+
+    public Flow<T> sort()
+    {
+        return nyi();
+    }
+
+    public Flow<T> sort(Comparator<? super T> comparator)
+    {
+        return nyi();
+    }
+
+    public List<T> toList()
+    {
+        if (isEmpty())
+            return Collections.emptyList();
+
+        return Collections.unmodifiableList(toMutableList());
+    }
+}

Propchange: tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/func/AbstractFlow.java
------------------------------------------------------------------------------
    svn:eol-style = native

Modified: tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/func/ArrayFlow.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/func/ArrayFlow.java?rev=949812&r1=949811&r2=949812&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/func/ArrayFlow.java (original)
+++ tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/func/ArrayFlow.java Mon May 31 17:34:48 2010
@@ -27,8 +27,10 @@ import org.apache.tapestry5.ioc.internal
 
 /**
  * Implementation of {@link Flow} based on an internal array of objects.
+ * 
+ * @since 5.2.0
  */
-class ArrayFlow<T> implements Flow<T>
+class ArrayFlow<T> extends AbstractFlow<T>
 {
     private final T[] values;
 
@@ -53,6 +55,8 @@ class ArrayFlow<T> implements Flow<T>
         this.values = values;
         this.start = start;
         this.count = count;
+
+        assert count > 0;
     }
 
     public Flow<T> each(Worker<? super T> worker)
@@ -63,55 +67,6 @@ class ArrayFlow<T> implements Flow<T>
         return this;
     }
 
-    public Flow<T> filter(Predicate<? super T> predicate)
-    {
-        Defense.notNull(predicate, "predicate");
-
-        if (isEmpty())
-            return this;
-
-        List<T> result = new ArrayList<T>(values.length);
-
-        for (int i = 0; i < count; i++)
-        {
-            T value = values[start + i];
-
-            if (predicate.accept(value))
-                result.add(value);
-        }
-
-        return new ArrayFlow<T>(result);
-    }
-
-    public Flow<T> remove(Predicate<? super T> predicate)
-    {
-        Defense.notNull(predicate, "predicate");
-
-        return filter(predicate.invert());
-    }
-
-    @SuppressWarnings("unchecked")
-    public <X> Flow<X> map(Mapper<T, X> mapper)
-    {
-        Defense.notNull(mapper, "mapper");
-
-        if (isEmpty())
-        {
-            List<X> empty = Collections.emptyList();
-            return new ArrayFlow<X>(empty);
-        }
-
-        X[] newValues = (X[]) new Object[values.length];
-
-        for (int i = 0; i < count; i++)
-        {
-            T value = values[start + i];
-            newValues[i] = mapper.map(value);
-        }
-
-        return new ArrayFlow<X>(newValues);
-    }
-
     public <A> A reduce(Reducer<A, T> reducer, A initial)
     {
         Defense.notNull(reducer, "reducer");
@@ -130,9 +85,6 @@ class ArrayFlow<T> implements Flow<T>
 
     public List<T> toList()
     {
-        if (isEmpty())
-            return Collections.emptyList();
-
         return Arrays.asList(values).subList(start, start + count);
     }
 
@@ -150,23 +102,10 @@ class ArrayFlow<T> implements Flow<T>
 
     public boolean isEmpty()
     {
-        return count == 0;
-    }
-
-    public Flow<T> concat(Flow<? extends T> other)
-    {
-        Defense.notNull(other, "other");
-
-        if (other.isEmpty())
-            return this;
-
-        List<T> newValues = copy();
-        newValues.addAll(other.toList());
-
-        return new ArrayFlow<T>(newValues);
+        return false;
     }
 
-    private List<T> copy()
+    List<T> toMutableList()
     {
         List<T> result = new ArrayList<T>(count);
 
@@ -178,23 +117,13 @@ class ArrayFlow<T> implements Flow<T>
         return result;
     }
 
-    public Flow<T> concat(List<? extends T> list)
-    {
-        return concat(F.flow(list));
-    }
-
-    public <V extends T> Flow<T> append(V... values)
-    {
-        return concat(F.flow(values));
-    }
-
     @SuppressWarnings("unchecked")
     public Flow<T> sort()
     {
         if (values.length < 2)
             return this;
 
-        List<Comparable> newValues = (List<Comparable>) copy();
+        List<Comparable> newValues = (List<Comparable>) toMutableList();
 
         Collections.sort(newValues);
 
@@ -208,7 +137,7 @@ class ArrayFlow<T> implements Flow<T>
         if (values.length < 2)
             return this;
 
-        List<T> newValues = copy();
+        List<T> newValues = toMutableList();
 
         Collections.sort(newValues, comparator);
 
@@ -224,7 +153,7 @@ class ArrayFlow<T> implements Flow<T>
 
     public T first()
     {
-        return isEmpty() ? null : values[start];
+        return values[start];
     }
 
     public synchronized Flow<T> rest()
@@ -237,9 +166,8 @@ class ArrayFlow<T> implements Flow<T>
 
     private Flow<T> buildRest()
     {
-        // TODO: A special implementation of an empty FlowImpl would be cool.
-        if (isEmpty())
-            return this;
+        if (count < 2)
+            return F.emptyFlow();
 
         return new ArrayFlow<T>(values, start + 1, count - 1);
     }

Added: tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/func/ConcatFlow.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/func/ConcatFlow.java?rev=949812&view=auto
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/func/ConcatFlow.java (added)
+++ tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/func/ConcatFlow.java Mon May 31 17:34:48 2010
@@ -0,0 +1,95 @@
+// Copyright 2010 The Apache Software Foundation
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package org.apache.tapestry5.func;
+
+/**
+ * A flow that implements a lazy concatination of two flows. Because of lazy filtering,
+ * we don't know at construction time whether either of the underlying flows are empty.
+ * 
+ * @since 5.2.0
+ */
+class ConcatFlow<T> extends AbstractFlow<T>
+{
+    private Flow<T> firstFlow;
+
+    private Flow<T> secondFlow;
+
+    private boolean resolved;
+
+    private boolean isEmpty;
+
+    private T first;
+
+    private Flow<T> rest;
+
+    @SuppressWarnings("unchecked")
+    public ConcatFlow(Flow<T> firstFlow, Flow<? extends T> secondFlow)
+    {
+        this.firstFlow = firstFlow;
+        this.secondFlow = (Flow<T>) secondFlow;
+    }
+
+    public synchronized T first()
+    {
+        resolve();
+
+        return first;
+    }
+
+    public synchronized boolean isEmpty()
+    {
+        resolve();
+
+        return isEmpty;
+    }
+
+    public synchronized Flow<T> rest()
+    {
+        resolve();
+
+        return rest;
+    }
+
+    @SuppressWarnings("unchecked")
+    private void resolve()
+    {
+        if (resolved)
+            return;
+
+        if (!firstFlow.isEmpty())
+        {
+            first = firstFlow.first();
+
+            Flow<T> restOfFirst = firstFlow.rest();
+
+            if (restOfFirst.isEmpty())
+                rest = secondFlow;
+            else
+                rest = new ConcatFlow(restOfFirst, secondFlow);
+        }
+        else
+        {
+            first = secondFlow.first();
+            rest = secondFlow.rest();
+
+            isEmpty = secondFlow.isEmpty();
+        }
+
+        firstFlow = null;
+        secondFlow = null;
+
+        resolved = true;
+    }
+}

Propchange: tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/func/ConcatFlow.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/func/EmptyFlow.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/func/EmptyFlow.java?rev=949812&view=auto
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/func/EmptyFlow.java (added)
+++ tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/func/EmptyFlow.java Mon May 31 17:34:48 2010
@@ -0,0 +1,105 @@
+// Copyright 2010 The Apache Software Foundation
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package org.apache.tapestry5.func;
+
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.List;
+
+/**
+ * An implementation of {@link Flow} for empty flows. This allows for some easy optimizations.
+ * 
+ * @since 5.2.0
+ */
+class EmptyFlow<T> extends AbstractFlow<T>
+{
+    public T first()
+    {
+        return null;
+    }
+
+    public boolean isEmpty()
+    {
+        return true;
+    }
+
+    public Flow<T> rest()
+    {
+        return this;
+    }
+
+    /** Does nothing; returns this empty list. */
+    public Flow<T> each(Worker<? super T> worker)
+    {
+        return this;
+    }
+
+    /** Does nothing; returns this empty list. */
+    public Flow<T> filter(Predicate<? super T> predicate)
+    {
+        return this;
+    }
+
+    /** Does nothing; returns this empty list. */
+    public Flow<T> remove(Predicate<? super T> predicate)
+    {
+        return this;
+    }
+
+    /** Does nothing; returns this empty list (as a Flow<X>). */
+    @SuppressWarnings("unchecked")
+    public <X> Flow<X> map(Mapper<T, X> mapper)
+    {
+        return (Flow<X>) this;
+    }
+
+    /** Does nothing; returns the initial value. */
+    public <A> A reduce(Reducer<A, T> reducer, A initial)
+    {
+        return initial;
+    }
+
+    /** Does nothing; returns this empty list. */
+    public Flow<T> reverse()
+    {
+        return this;
+    }
+
+    /** Does nothing; returns this empty list. */
+    public Flow<T> sort()
+    {
+        return this;
+    }
+
+    /** Does nothing; returns this empty list. */
+    public Flow<T> sort(Comparator<? super T> comparator)
+    {
+        return this;
+    }
+
+    /** Returns the empty list. */
+    public List<T> toList()
+    {
+        return Collections.emptyList();
+    }
+
+    /** Returns the other list (i.e. empty ++ other == other). */
+    @SuppressWarnings("unchecked")
+    public Flow<T> concat(Flow<? extends T> other)
+    {
+        return (Flow<T>) other;
+    }
+
+}

Propchange: tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/func/EmptyFlow.java
------------------------------------------------------------------------------
    svn:eol-style = native

Modified: tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/func/F.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/func/F.java?rev=949812&r1=949811&r2=949812&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/func/F.java (original)
+++ tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/func/F.java Mon May 31 17:34:48 2010
@@ -24,6 +24,14 @@ import java.util.Collection;
  */
 public class F
 {
+    private final static Flow<?> EMPTY_FLOW = new EmptyFlow();
+
+    @SuppressWarnings("unchecked")
+    static <T> Flow<T> emptyFlow()
+    {
+        return (Flow<T>) EMPTY_FLOW;
+    }
+
     public static Predicate<Number> eq(final long value)
     {
         return new Predicate<Number>()
@@ -177,6 +185,9 @@ public class F
      */
     public static <T> Flow<T> flow(Collection<T> values)
     {
+        if (values.isEmpty())
+            return emptyFlow();
+
         return new ArrayFlow<T>(values);
     }
 
@@ -186,6 +197,9 @@ public class F
      */
     public static <T> Flow<T> flow(T... values)
     {
+        if (values.length == 0)
+            return emptyFlow();
+
         return new ArrayFlow<T>(values);
     }
 }

Added: tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/func/FilteredFlow.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/func/FilteredFlow.java?rev=949812&view=auto
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/func/FilteredFlow.java (added)
+++ tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/func/FilteredFlow.java Mon May 31 17:34:48 2010
@@ -0,0 +1,107 @@
+// Copyright 2010 The Apache Software Foundation
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package org.apache.tapestry5.func;
+
+/**
+ * {@link Flow} implementation that filters (applies a {@link Predicate}) to another Flow.
+ * 
+ * @since 5.2.0
+ */
+class FilteredFlow<T> extends AbstractFlow<T>
+{
+    private final Predicate<? super T> predicate;
+
+    // Reset to null once resolved
+    // Guarded by this
+    private Flow<T> filteredFlow;
+
+    // Has first, rest, empty been resolved?
+    // Guarded by this
+    private boolean resolved;
+
+    // No matches in filteredFlow?
+    // Guarded by this
+    private boolean empty;
+
+    // First match from filteredFlow
+    // Guarded by this
+    private T first;
+
+    // Remaining flow after the first match
+    // Guarded by this
+    private Flow<T> rest;
+
+    FilteredFlow(Predicate<? super T> predicate, Flow<T> filteredFlow)
+    {
+        this.predicate = predicate;
+        this.filteredFlow = filteredFlow;
+    }
+
+    public synchronized T first()
+    {
+        resolve();
+
+        return first;
+    }
+
+    public synchronized Flow<T> rest()
+    {
+        resolve();
+
+        return rest;
+    }
+
+    public synchronized boolean isEmpty()
+    {
+        resolve();
+
+        return empty;
+    }
+
+    private void resolve()
+    {
+        if (resolved)
+            return;
+
+        Flow<T> cursor = filteredFlow;
+
+        while (true)
+        {
+            if (cursor.isEmpty())
+            {
+                empty = true;
+                rest = cursor;
+                break;
+            }
+
+            T potential = cursor.first();
+
+            if (predicate.accept(potential))
+            {
+                first = potential;
+                rest = new FilteredFlow<T>(predicate, cursor.rest());
+                break;
+            }
+
+            cursor = cursor.rest();
+        }
+
+        resolved = true;
+
+        // No longer needed once resolved.
+
+        filteredFlow = null;
+    }
+}

Propchange: tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/func/FilteredFlow.java
------------------------------------------------------------------------------
    svn:eol-style = native

Modified: tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/func/Flow.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/func/Flow.java?rev=949812&r1=949811&r2=949812&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/func/Flow.java (original)
+++ tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/func/Flow.java Mon May 31 17:34:48 2010
@@ -18,11 +18,15 @@ import java.util.Comparator;
 import java.util.List;
 
 /**
- * A fluent interface for manipulating collections using map, reduce, filter and remove. Flows are
- * <strong>immutable</strong>; operations create new Flows rather than change the internal state of
- * an existing Flow. Using Flows allows for a very fluid interface.
+ * A Flow is a a functional interface for working with a ordered collection of values.
+ * A given Flow contains only values of a particular type. Standard operations allow for
+ * filtering the Flow, or appending values to the Flow. Since Flows are immutable, all operations
+ * on Flows return new immutable Flows. Flows are thread safe (to the extent that the {@link Mapper}s, {@link Predicate}
+ * s, {@link Worker}s and {@link Reducer}s are).
+ * Flows are <em>lazy</em>: filtering, mapping, and concatenating Flows will do so with no, or a minimum, of evaluation.
+ * However, converting a Flow into a {@link List} will force a realization of the entire Flow.
  * <p>
- * A future enhancement may be to make flows lazy.
+ * Using Flows allows for a very fluid interface.
  * 
  * @since 5.2.0
  */

Added: tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/func/MappedFlow.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/func/MappedFlow.java?rev=949812&view=auto
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/func/MappedFlow.java (added)
+++ tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/func/MappedFlow.java Mon May 31 17:34:48 2010
@@ -0,0 +1,83 @@
+// Copyright 2010 The Apache Software Foundation
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package org.apache.tapestry5.func;
+
+/**
+ * Flow that wraps around another Flow, transforming it value by value into a new Flow.
+ * 
+ * @since 5.2.0
+ */
+class MappedFlow<T, X> extends AbstractFlow<X>
+{
+    private final Mapper<T, X> mapper;
+
+    // Used to determine first, rest
+    private Flow<T> mappedFlow;
+
+    // Guarded by this
+    private boolean resolved;
+
+    // Guarded by this
+    private X first;
+
+    // Guarded by this
+    private Flow<X> rest;
+
+    public MappedFlow(Mapper<T, X> mapper, Flow<T> mappedFlow)
+    {
+        this.mapper = mapper;
+        this.mappedFlow = mappedFlow;
+    }
+
+    public synchronized X first()
+    {
+        resolve();
+
+        return first;
+    }
+
+    public boolean isEmpty()
+    {
+        return false;
+    }
+
+    public synchronized Flow<X> rest()
+    {
+        resolve();
+
+        return rest;
+    }
+
+    private void resolve()
+    {
+        if (resolved)
+            return;
+
+        // The mappedFlow should never be empty
+
+        first = mapper.map(mappedFlow.first());
+
+        Flow<T> mappedRest = mappedFlow.rest();
+
+        if (mappedRest.isEmpty())
+            rest = F.emptyFlow();
+        else
+            rest = new MappedFlow<T, X>(mapper, mappedRest);
+
+        mappedFlow = null;
+
+        resolved = true;
+    }
+}

Propchange: tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/func/MappedFlow.java
------------------------------------------------------------------------------
    svn:eol-style = native

Modified: tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/func/Mapper.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/func/Mapper.java?rev=949812&r1=949811&r2=949812&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/func/Mapper.java (original)
+++ tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/func/Mapper.java Mon May 31 17:34:48 2010
@@ -15,9 +15,8 @@
 package org.apache.tapestry5.func;
 
 /**
- * Base class used with {@link F#map(Mapper, java.util.Collection)} and {@link Flow#map(Mapper)} to
- * define how objects
- * are mapped from one type
+ * Base class used with {@link Flow#map(Mapper)} to
+ * define how Flow values are mapped from one type
  * to another (or otherwise transformed).
  * 
  * @since 5.2.0

Modified: tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/func/Predicate.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/func/Predicate.java?rev=949812&r1=949811&r2=949812&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/func/Predicate.java (original)
+++ tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/func/Predicate.java Mon May 31 17:34:48 2010
@@ -23,8 +23,8 @@ import org.apache.tapestry5.ioc.internal
  * The {@link F} class includes a number of Predicate factory methods.
  * 
  * @since 5.2.0
- * @see F#filter(Predicate, java.util.List)
- * @see F#remove(Predicate, java.util.List)
+ * @see Flow#filter(Predicate)
+ * @see Flow#remove(Predicate)
  */
 public abstract class Predicate<T>
 {

Modified: tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/func/Worker.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/func/Worker.java?rev=949812&r1=949811&r2=949812&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/func/Worker.java (original)
+++ tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/func/Worker.java Mon May 31 17:34:48 2010
@@ -15,10 +15,10 @@
 package org.apache.tapestry5.func;
 
 /**
- * An operational function used with a collection.
+ * An operational function used with a {@link Flow}.
  * 
  * @since 5.2.0
- * @see F#each(Worker, java.util.Collection)
+ * @see Flow#each(Worker)
  */
 public abstract class Worker<T>
 {
@@ -29,7 +29,7 @@ public abstract class Worker<T>
 
     /**
      * Combines this worker with the other worker, forming a new composite worker. In the composite,
-     * the value passed first to this worker, then to the other worker.
+     * the value from the Flow is passed first to this worker, then to the other worker.
      */
     public Worker<T> combine(final Worker<? super T> other)
     {

Modified: tapestry/tapestry5/trunk/tapestry-ioc/src/test/java/org/apache/tapestry5/func/FuncTest.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-ioc/src/test/java/org/apache/tapestry5/func/FuncTest.java?rev=949812&r1=949811&r2=949812&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-ioc/src/test/java/org/apache/tapestry5/func/FuncTest.java (original)
+++ tapestry/tapestry5/trunk/tapestry-ioc/src/test/java/org/apache/tapestry5/func/FuncTest.java Mon May 31 17:34:48 2010
@@ -214,14 +214,6 @@ public class FuncTest extends TestUtils
     }
 
     @Test
-    public void filter_empty_list_is_same()
-    {
-        Flow<Integer> flow = F.flow();
-
-        assertSame(flow.filter(evenp), flow);
-    }
-
-    @Test
     public void combine_predicate_with_and()
     {
         List<Integer> input = Arrays.asList(1, 2, 3, 4, 5, 6, 7);
@@ -313,12 +305,12 @@ public class FuncTest extends TestUtils
     }
 
     @Test
-    public void concat_empty_list_is_same()
+    public void concat_onto_empty_list()
     {
-        Flow<Integer> first = F.flow(1, 2, 3);
         Flow<Integer> empty = F.flow();
+        Flow<Integer> flow = F.flow(1, 2, 3);
 
-        assertSame(first.concat(empty), first);
+        assertSame(empty.concat(flow), flow);
     }
 
     @Test