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());
+ }
}