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