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/28 18:13:42 UTC

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

Author: hlship
Date: Fri May 28 16:13:42 2010
New Revision: 949214

URL: http://svn.apache.org/viewvc?rev=949214&view=rev
Log:
Clean up documentation and add new methods first() and rest() to Flow.

Modified:
    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/FlowImpl.java
    tapestry/tapestry5/trunk/tapestry-ioc/src/test/java/org/apache/tapestry5/func/FuncTest.java

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=949214&r1=949213&r2=949214&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 Fri May 28 16:13:42 2010
@@ -14,14 +14,11 @@
 
 package org.apache.tapestry5.func;
 
-import java.util.Arrays;
 import java.util.Collection;
-import java.util.List;
 
 /**
  * Functional operations on collections with generics support. Tending to use the equivalent names from
- * Clojure. As with Clojure, all these functions return new lists. Unlike Clojure, there's no guarantee
- * that the lists are immutable, and there isn't built-in laziness.
+ * Clojure. As with Clojure, all these functions return new lists.
  * 
  * @since 5.2.0
  */
@@ -174,18 +171,21 @@ public class F
         };
     };
 
+    /**
+     * Extracts the values from the collection to form a {@link Flow}. The Collection
+     * may change after the Flow is created without affecting the Flow.
+     */
     public static <T> Flow<T> flow(Collection<T> values)
     {
         return new FlowImpl<T>(values);
     }
 
-    public static <T> Flow<T> flow(List<T> values)
-    {
-        return new FlowImpl<T>(values);
-    }
-
+    /**
+     * Creates a new Flow from the values. You should not change the values array
+     * after invoking this method (i.e., no defensive copy of the values is made).
+     */
     public static <T> Flow<T> flow(T... values)
     {
-        return flow(Arrays.asList(values));
+        return new FlowImpl<T>(values);
     }
 }

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=949214&r1=949213&r2=949214&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 Fri May 28 16:13:42 2010
@@ -19,7 +19,8 @@ import java.util.List;
 
 /**
  * A fluent interface for manipulating collections using map, reduce, filter and remove. Flows are
- * immutable; operations create new flows to replace the old ones.
+ * <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.
  * <p>
  * A future enhancement may be to make flows lazy.
  * 
@@ -32,7 +33,7 @@ public interface Flow<T> extends Iterabl
 
     /**
      * Filters values, keeping only values where the predicate is true, returning a new Flow with just
-     * the remaining values.
+     * the retained values.
      */
     Flow<T> filter(Predicate<? super T> predicate);
 
@@ -71,12 +72,27 @@ public interface Flow<T> extends Iterabl
     <V extends T> Flow<T> append(V... values);
 
     /**
-     * Sorts this Flow forming a new Flow.
+     * Sorts this Flow, forming a new Flow.
      * 
      * @throws ClassCastException
      *             if type <T> does not extend {@link Comparable}
      */
     Flow<T> sort();
 
+    /**
+     * Sorts this Flow using the comparator, forming a new Flow.
+     */
     Flow<T> sort(Comparator<? super T> comparator);
+
+    /**
+     * Returns the first value in the Flow. Returns null for empty flows, but remember that null is a valid
+     * value within a flow, so use {@link #isEmpty() to determine if a flow is actually empty.
+     */
+    T first();
+
+    /**
+     * Returns a new Flow containing all but the first value in this Flow. If this Flow has only a single item,
+     * or is empty, this will return an empty Flow.
+     */
+    Flow<T> rest();
 }

Modified: tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/func/FlowImpl.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/func/FlowImpl.java?rev=949214&r1=949213&r2=949214&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/func/FlowImpl.java (original)
+++ tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/func/FlowImpl.java Fri May 28 16:13:42 2010
@@ -29,18 +29,33 @@ class FlowImpl<T> implements Flow<T>
 {
     private final T[] values;
 
+    private final int start, count;
+
+    // Guarded by this
+    private Flow<T> rest;
+
     @SuppressWarnings("unchecked")
     FlowImpl(Collection<T> values)
     {
-        this.values = (T[]) values.toArray();
+        this((T[]) values.toArray());
+    }
+
+    FlowImpl(T[] values)
+    {
+        this(values, 0, values.length);
+    }
+
+    FlowImpl(T[] values, int start, int count)
+    {
+        this.values = values;
+        this.start = start;
+        this.count = count;
     }
 
     public Flow<T> each(Worker<? super T> worker)
     {
-        for (T t : values)
-        {
-            worker.work(t);
-        }
+        for (int i = 0; i < count; i++)
+            worker.work(values[start + i]);
 
         return this;
     }
@@ -54,10 +69,12 @@ class FlowImpl<T> implements Flow<T>
 
         List<T> result = new ArrayList<T>(values.length);
 
-        for (T item : values)
+        for (int i = 0; i < count; i++)
         {
-            if (predicate.accept(item))
-                result.add(item);
+            T value = values[start + i];
+
+            if (predicate.accept(value))
+                result.add(value);
         }
 
         return new FlowImpl<T>(result);
@@ -70,6 +87,7 @@ class FlowImpl<T> implements Flow<T>
         return filter(predicate.invert());
     }
 
+    @SuppressWarnings("unchecked")
     public <X> Flow<X> map(Mapper<T, X> mapper)
     {
         Defense.notNull(mapper, "mapper");
@@ -80,11 +98,12 @@ class FlowImpl<T> implements Flow<T>
             return new FlowImpl<X>(empty);
         }
 
-        List<X> newValues = new ArrayList<X>(values.length);
+        X[] newValues = (X[]) new Object[values.length];
 
-        for (T value : values)
+        for (int i = 0; i < count; i++)
         {
-            newValues.add(mapper.map(value));
+            T value = values[start + i];
+            newValues[i] = mapper.map(value);
         }
 
         return new FlowImpl<X>(newValues);
@@ -96,21 +115,22 @@ class FlowImpl<T> implements Flow<T>
 
         A accumulator = initial;
 
-        for (T value : values)
+        for (int i = 0; i < count; i++)
         {
+            T value = values[start + i];
+
             accumulator = reducer.reduce(accumulator, value);
         }
 
         return accumulator;
     }
 
-    /** Returns the values in the flow as an unmodifiable List. */
     public List<T> toList()
     {
         if (isEmpty())
             return Collections.emptyList();
 
-        return Arrays.asList(values);
+        return Arrays.asList(values).subList(start, start + count);
     }
 
     public Flow<T> reverse()
@@ -127,7 +147,7 @@ class FlowImpl<T> implements Flow<T>
 
     public boolean isEmpty()
     {
-        return values.length == 0;
+        return count == 0;
     }
 
     public Flow<T> concat(Flow<? extends T> other)
@@ -145,7 +165,14 @@ class FlowImpl<T> implements Flow<T>
 
     private List<T> copy()
     {
-        return new ArrayList<T>(Arrays.asList(values));
+        List<T> result = new ArrayList<T>(count);
+
+        for (int i = 0; i < count; i++)
+        {
+            result.add(values[start + i]);
+        }
+
+        return result;
     }
 
     public Flow<T> concat(List<? extends T> list)
@@ -192,4 +219,26 @@ class FlowImpl<T> implements Flow<T>
         return toList().iterator();
     }
 
+    public T first()
+    {
+        return isEmpty() ? null : values[start];
+    }
+
+    public synchronized Flow<T> rest()
+    {
+        if (rest == null)
+            rest = buildRest();
+
+        return rest;
+    }
+
+    private Flow<T> buildRest()
+    {
+        // TODO: A special implementation of an empty FlowImpl would be cool.
+        if (isEmpty())
+            return this;
+
+        return new FlowImpl<T>(values, start + 1, count - 1);
+    }
+
 }

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=949214&r1=949213&r2=949214&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 Fri May 28 16:13:42 2010
@@ -407,4 +407,36 @@ public class FuncTest extends TestUtils
 
         assertEquals(total, 16);
     }
+
+    @Test
+    public void first_of_non_empty_flow()
+    {
+        assertEquals(F.flow("Mary", "had", "a", "little", "lamb").first(), "Mary");
+    }
+
+    @Test
+    public void rest_of_non_empty_flow()
+    {
+        assertListsEquals(F.flow("Mary", "had", "a", "little", "lamb").rest().toList(), "had", "a", "little", "lamb");
+    }
+
+    @Test
+    public void flow_rest_is_cached()
+    {
+        Flow<Integer> flow = F.flow(1, 2, 3);
+
+        assertSame(flow.rest(), flow.rest());
+    }
+
+    @Test
+    public void first_of_empty_is_null()
+    {
+        assertNull(F.flow().first());
+    }
+
+    @Test
+    public void rest_of_empty_is_still_empty_and_not_null()
+    {
+        assertTrue(F.flow().rest().isEmpty());
+    }
 }