Author: hlship
Date: Thu Jun 3 23:10:46 2010
New Revision: 951199
URL: http://svn.apache.org/viewvc?rev=951199&view=rev
Log:
Be more careful about deferring computation (of the first value in a lazy flow)
to ensure that Mappers are not invoked unless truly needed
Added:
tapestry/tapestry5/trunk/tapestry-func/src/main/java/org/apache/tapestry5/func/LazyMappedValue.java
- copied, changed from r951076,
tapestry/tapestry5/trunk/tapestry-func/src/main/java/org/apache/tapestry5/func/LazyMapper.java
tapestry/tapestry5/trunk/tapestry-func/src/main/java/org/apache/tapestry5/func/LazyValue.java
- copied, changed from r951076,
tapestry/tapestry5/trunk/tapestry-func/src/main/java/org/apache/tapestry5/func/LazyMapper.java
tapestry/tapestry5/trunk/tapestry-func/src/main/java/org/apache/tapestry5/func/StaticValue.java
- copied, changed from r951076,
tapestry/tapestry5/trunk/tapestry-func/src/main/java/org/apache/tapestry5/func/LazyMapper.java
tapestry/tapestry5/trunk/tapestry-func/src/test/java/org/apache/tapestry5/func/MapperTest.java
(with props)
Modified:
tapestry/tapestry5/trunk/tapestry-func/src/main/java/org/apache/tapestry5/func/LazyContinuation.java
tapestry/tapestry5/trunk/tapestry-func/src/main/java/org/apache/tapestry5/func/LazyFlow.java
tapestry/tapestry5/trunk/tapestry-func/src/main/java/org/apache/tapestry5/func/LazyMapper.java
tapestry/tapestry5/trunk/tapestry-func/src/test/java/org/apache/tapestry5/func/FuncTest.java
Modified:
tapestry/tapestry5/trunk/tapestry-func/src/main/java/org/apache/tapestry5/func/LazyContinuation.java
URL:
http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-func/src/main/java/org/apache/tapestry5/func/LazyContinuation.java?rev=951199&r1=951198&r2=951199&view=diff
==============================================================================
---
tapestry/tapestry5/trunk/tapestry-func/src/main/java/org/apache/tapestry5/func/LazyContinuation.java
(original)
+++
tapestry/tapestry5/trunk/tapestry-func/src/main/java/org/apache/tapestry5/func/LazyContinuation.java
Thu Jun 3 23:10:46 2010
@@ -21,18 +21,29 @@ package org.apache.tapestry5.func;
*/
public class LazyContinuation<T>
{
- private final T nextValue;
+ private final LazyValue<T> nextValue;
private final LazyFunction<T> nextFunction;
- public LazyContinuation(T next, LazyFunction<T> nextFunction)
+ public LazyContinuation(T nextValue, LazyFunction<T> nextFunction)
{
- this.nextValue = next;
+ this(new StaticValue<T>(nextValue), nextFunction);
+ }
+
+ public LazyContinuation(LazyValue<T> nextValue, LazyFunction<T>
nextFunction)
+ {
+ assert nextValue != null;
+ assert nextFunction != null;
+
+ this.nextValue = nextValue;
this.nextFunction = nextFunction;
}
- /** Returns the next value computed by the lazy function. */
- public T nextValue()
+ /**
+ * Returns, indirectly, the next value computed by the lazy function. The
LazyValue represents
+ * a deferred computation.
+ */
+ public LazyValue<T> nextValue()
{
return nextValue;
}
Modified:
tapestry/tapestry5/trunk/tapestry-func/src/main/java/org/apache/tapestry5/func/LazyFlow.java
URL:
http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-func/src/main/java/org/apache/tapestry5/func/LazyFlow.java?rev=951199&r1=951198&r2=951199&view=diff
==============================================================================
---
tapestry/tapestry5/trunk/tapestry-func/src/main/java/org/apache/tapestry5/func/LazyFlow.java
(original)
+++
tapestry/tapestry5/trunk/tapestry-func/src/main/java/org/apache/tapestry5/func/LazyFlow.java
Thu Jun 3 23:10:46 2010
@@ -18,15 +18,21 @@ class LazyFlow<T> extends AbstractFlow<T
{
// All instance variables guarded by this
- private boolean resolved;
+ // Retained up until resolve() is called
+
+ private LazyFunction<T> lazyFunction;
+ // Set inside resolve()
private boolean empty;
- private T first;
+ // Set inside resolve(), used and discarded inside first()
+ private LazyValue<T> lazyFirst;
+ // Set inside resolve()
private Flow<T> rest;
- private LazyFunction<T> lazyFunction;
+ // Set inside first()
+ private T first;
public LazyFlow(LazyFunction<T> lazyFunction)
{
@@ -37,6 +43,16 @@ class LazyFlow<T> extends AbstractFlow<T
{
resolve();
+ // Immediately after resolving, all we have is the function to call to
get
+ // the first object. And once we get that object, we don't need (or
want) the
+ // function.
+
+ if (lazyFirst != null)
+ {
+ first = lazyFirst.get();
+ lazyFirst = null;
+ }
+
return first;
}
@@ -56,7 +72,7 @@ class LazyFlow<T> extends AbstractFlow<T
private synchronized void resolve()
{
- if (resolved)
+ if (lazyFunction == null)
return;
LazyContinuation<T> continuation = lazyFunction.next();
@@ -68,13 +84,11 @@ class LazyFlow<T> extends AbstractFlow<T
}
else
{
- first = continuation.nextValue();
+ lazyFirst = continuation.nextValue();
rest = new LazyFlow<T>(continuation.nextFunction());
}
- resolved = true;
-
lazyFunction = null;
}
}
Copied:
tapestry/tapestry5/trunk/tapestry-func/src/main/java/org/apache/tapestry5/func/LazyMappedValue.java
(from r951076,
tapestry/tapestry5/trunk/tapestry-func/src/main/java/org/apache/tapestry5/func/LazyMapper.java)
URL:
http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-func/src/main/java/org/apache/tapestry5/func/LazyMappedValue.java?p2=tapestry/tapestry5/trunk/tapestry-func/src/main/java/org/apache/tapestry5/func/LazyMappedValue.java&p1=tapestry/tapestry5/trunk/tapestry-func/src/main/java/org/apache/tapestry5/func/LazyMapper.java&r1=951076&r2=951199&rev=951199&view=diff
==============================================================================
---
tapestry/tapestry5/trunk/tapestry-func/src/main/java/org/apache/tapestry5/func/LazyMapper.java
(original)
+++
tapestry/tapestry5/trunk/tapestry-func/src/main/java/org/apache/tapestry5/func/LazyMappedValue.java
Thu Jun 3 23:10:46 2010
@@ -14,26 +14,20 @@
package org.apache.tapestry5.func;
-class LazyMapper<T, X> implements LazyFunction<X>
+class LazyMappedValue<T, X> implements LazyValue<X>
{
- private final Mapper<T, X> mapper;
+ private final T input;
- private final Flow<T> flow;
+ private final Mapper<T, X> mapper;
- public LazyMapper(Mapper<T, X> mapper, Flow<T> flow)
+ public LazyMappedValue(T input, Mapper<T, X> mapper)
{
+ this.input = input;
this.mapper = mapper;
- this.flow = flow;
}
- public LazyContinuation<X> next()
+ public X get()
{
- if (flow.isEmpty())
- return null;
-
- X mapped = mapper.map(flow.first());
-
- return new LazyContinuation<X>(mapped, new LazyMapper<T, X>(mapper,
flow.rest()));
+ return mapper.map(input);
}
-
}
Modified:
tapestry/tapestry5/trunk/tapestry-func/src/main/java/org/apache/tapestry5/func/LazyMapper.java
URL:
http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-func/src/main/java/org/apache/tapestry5/func/LazyMapper.java?rev=951199&r1=951198&r2=951199&view=diff
==============================================================================
---
tapestry/tapestry5/trunk/tapestry-func/src/main/java/org/apache/tapestry5/func/LazyMapper.java
(original)
+++
tapestry/tapestry5/trunk/tapestry-func/src/main/java/org/apache/tapestry5/func/LazyMapper.java
Thu Jun 3 23:10:46 2010
@@ -31,9 +31,8 @@ class LazyMapper<T, X> implements LazyFu
if (flow.isEmpty())
return null;
- X mapped = mapper.map(flow.first());
-
- return new LazyContinuation<X>(mapped, new LazyMapper<T, X>(mapper,
flow.rest()));
+ return new LazyContinuation<X>(new LazyMappedValue<T, X>(flow.first(),
mapper), new LazyMapper<T, X>(mapper,
+ flow.rest()));
}
}
Copied:
tapestry/tapestry5/trunk/tapestry-func/src/main/java/org/apache/tapestry5/func/LazyValue.java
(from r951076,
tapestry/tapestry5/trunk/tapestry-func/src/main/java/org/apache/tapestry5/func/LazyMapper.java)
URL:
http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-func/src/main/java/org/apache/tapestry5/func/LazyValue.java?p2=tapestry/tapestry5/trunk/tapestry-func/src/main/java/org/apache/tapestry5/func/LazyValue.java&p1=tapestry/tapestry5/trunk/tapestry-func/src/main/java/org/apache/tapestry5/func/LazyMapper.java&r1=951076&r2=951199&rev=951199&view=diff
==============================================================================
---
tapestry/tapestry5/trunk/tapestry-func/src/main/java/org/apache/tapestry5/func/LazyMapper.java
(original)
+++
tapestry/tapestry5/trunk/tapestry-func/src/main/java/org/apache/tapestry5/func/LazyValue.java
Thu Jun 3 23:10:46 2010
@@ -14,26 +14,11 @@
package org.apache.tapestry5.func;
-class LazyMapper<T, X> implements LazyFunction<X>
+/**
+ * A function that returns a value, allowing the computation of that value to
be deferred as late as possible.
+ */
+public interface LazyValue<T>
{
- private final Mapper<T, X> mapper;
-
- private final Flow<T> flow;
-
- public LazyMapper(Mapper<T, X> mapper, Flow<T> flow)
- {
- this.mapper = mapper;
- this.flow = flow;
- }
-
- public LazyContinuation<X> next()
- {
- if (flow.isEmpty())
- return null;
-
- X mapped = mapper.map(flow.first());
-
- return new LazyContinuation<X>(mapped, new LazyMapper<T, X>(mapper,
flow.rest()));
- }
-
+ /** Compute and return the value. */
+ T get();
}
Copied:
tapestry/tapestry5/trunk/tapestry-func/src/main/java/org/apache/tapestry5/func/StaticValue.java
(from r951076,
tapestry/tapestry5/trunk/tapestry-func/src/main/java/org/apache/tapestry5/func/LazyMapper.java)
URL:
http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-func/src/main/java/org/apache/tapestry5/func/StaticValue.java?p2=tapestry/tapestry5/trunk/tapestry-func/src/main/java/org/apache/tapestry5/func/StaticValue.java&p1=tapestry/tapestry5/trunk/tapestry-func/src/main/java/org/apache/tapestry5/func/LazyMapper.java&r1=951076&r2=951199&rev=951199&view=diff
==============================================================================
---
tapestry/tapestry5/trunk/tapestry-func/src/main/java/org/apache/tapestry5/func/LazyMapper.java
(original)
+++
tapestry/tapestry5/trunk/tapestry-func/src/main/java/org/apache/tapestry5/func/StaticValue.java
Thu Jun 3 23:10:46 2010
@@ -4,7 +4,7 @@
// 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
+// 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,
@@ -14,26 +14,17 @@
package org.apache.tapestry5.func;
-class LazyMapper<T, X> implements LazyFunction<X>
+class StaticValue<T> implements LazyValue<T>
{
- private final Mapper<T, X> mapper;
+ private final T nextValue;
- private final Flow<T> flow;
-
- public LazyMapper(Mapper<T, X> mapper, Flow<T> flow)
+ StaticValue(T nextValue)
{
- this.mapper = mapper;
- this.flow = flow;
+ this.nextValue = nextValue;
}
- public LazyContinuation<X> next()
+ public T get()
{
- if (flow.isEmpty())
- return null;
-
- X mapped = mapper.map(flow.first());
-
- return new LazyContinuation<X>(mapped, new LazyMapper<T, X>(mapper,
flow.rest()));
+ return nextValue;
}
-
-}
+}
\ No newline at end of file
Modified:
tapestry/tapestry5/trunk/tapestry-func/src/test/java/org/apache/tapestry5/func/FuncTest.java
URL:
http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-func/src/test/java/org/apache/tapestry5/func/FuncTest.java?rev=951199&r1=951198&r2=951199&view=diff
==============================================================================
---
tapestry/tapestry5/trunk/tapestry-func/src/test/java/org/apache/tapestry5/func/FuncTest.java
(original)
+++
tapestry/tapestry5/trunk/tapestry-func/src/test/java/org/apache/tapestry5/func/FuncTest.java
Thu Jun 3 23:10:46 2010
@@ -25,35 +25,7 @@ import org.testng.annotations.Test;
public class FuncTest extends BaseFuncTest
{
- protected Mapper<Integer, Flow<Integer>> sequencer = new Mapper<Integer,
Flow<Integer>>()
- {
-
- public Flow<Integer> map(Integer value)
- {
- Flow<Integer> flow = F.flow();
-
- for (int i = 0; i < value; i++)
- flow = flow.append(value);
-
- return flow;
- }
- };
-
- @Test
- public void map()
- {
- List<String> source = Arrays.asList("Mary", "had", "a", "little",
"lamb");
-
- List<Integer> lengths = F.flow(source).map(stringToLength).toList();
-
- assertListsEquals(lengths, 4, 3, 1, 6, 4);
- }
-
- @Test
- public void flow_map()
- {
- assertFlowValues(F.flow("Mary", "had", "a", "little",
"lamb").map(stringToLength), 4, 3, 1, 6, 4);
- }
+
@Test
public void flow_reverse()
@@ -518,20 +490,7 @@ public class FuncTest extends BaseFuncTe
assertListsEquals(result, "a", "had", "Mary", "lamb");
}
- @Test
- public void map_of_filtered_empty_is_empty()
- {
- assertTrue(filteredEmpty.map(new Mapper<Integer, Integer>()
- {
- public Integer map(Integer value)
- {
- unreachable();
-
- return value;
- }
- }).isEmpty());
- }
-
+
@Test
public void each_on_empty_flow()
{
@@ -571,23 +530,6 @@ public class FuncTest extends BaseFuncTe
}, initial), initial);
}
- @Test
- public void mapcat_on_empty_flow_is_empty()
- {
- Flow<Integer> flow = F.flow();
-
- assertSame(flow.mapcat(sequencer), flow);
-
- assertTrue(filteredEmpty.mapcat(sequencer).isEmpty());
- }
-
- @Test
- public void mapcat()
- {
- Flow<Integer> flow = F.flow(3, 1, 2);
-
- assertFlowValues(flow.mapcat(sequencer), 3, 3, 3, 1, 2, 2);
- }
@Test
public void count_of_the_empty_flow_is_zero()
@@ -610,23 +552,7 @@ public class FuncTest extends BaseFuncTe
assertEquals(flow.filter(F.notNull()).count(), 5);
}
- @Test
- public void count_of_a_mapped_filtered_empty_flow()
- {
- Flow<Integer> flow = F.flow("Mary", "had",
"etc.").filter(F.isNull()).map(stringToLength);
-
- assertTrue(flow.isEmpty());
- assertEquals(flow.count(), 0);
- }
-
- @Test
- public void toString_mapper()
- {
- Flow<Integer> flow = F.flow(1, 2, 3);
-
- assertFlowValues(flow.map(F.<Integer> stringValueOf()), "1", "2", "3");
- }
-
+
@Test
public void concat_empty_list()
{
Added:
tapestry/tapestry5/trunk/tapestry-func/src/test/java/org/apache/tapestry5/func/MapperTest.java
URL:
http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-func/src/test/java/org/apache/tapestry5/func/MapperTest.java?rev=951199&view=auto
==============================================================================
---
tapestry/tapestry5/trunk/tapestry-func/src/test/java/org/apache/tapestry5/func/MapperTest.java
(added)
+++
tapestry/tapestry5/trunk/tapestry-func/src/test/java/org/apache/tapestry5/func/MapperTest.java
Thu Jun 3 23:10:46 2010
@@ -0,0 +1,132 @@
+// 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.Arrays;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.atomic.AtomicInteger;
+
+import org.testng.annotations.Test;
+
+public class MapperTest extends BaseFuncTest
+{
+ protected Mapper<Integer, Flow<Integer>> sequencer = new Mapper<Integer,
Flow<Integer>>()
+ {
+
+ public Flow<Integer> map(Integer value)
+ {
+ Flow<Integer> flow = F.flow();
+
+ for (int i = 0; i < value; i++)
+ flow = flow.append(value);
+
+ return flow;
+ }
+ };
+
+ @Test
+ public void map()
+ {
+ List<String> source = Arrays.asList("Mary", "had", "a", "little",
"lamb");
+
+ List<Integer> lengths = F.flow(source).map(stringToLength).toList();
+
+ assertListsEquals(lengths, 4, 3, 1, 6, 4);
+ }
+
+ @Test
+ public void flow_map()
+ {
+ assertFlowValues(F.flow("Mary", "had", "a", "little",
"lamb").map(stringToLength), 4, 3, 1, 6, 4);
+ }
+
+ @Test
+ public void map_of_filtered_empty_is_empty()
+ {
+ assertTrue(filteredEmpty.map(new Mapper<Integer, Integer>()
+ {
+ public Integer map(Integer value)
+ {
+ unreachable();
+
+ return value;
+ }
+ }).isEmpty());
+ }
+
+ @Test
+ public void mapcat_on_empty_flow_is_empty()
+ {
+ Flow<Integer> flow = F.flow();
+
+ assertSame(flow.mapcat(sequencer), flow);
+
+ assertTrue(filteredEmpty.mapcat(sequencer).isEmpty());
+ }
+
+ @Test
+ public void mapcat()
+ {
+ Flow<Integer> flow = F.flow(3, 1, 2);
+
+ assertFlowValues(flow.mapcat(sequencer), 3, 3, 3, 1, 2, 2);
+ }
+
+ @Test
+ public void count_of_a_mapped_filtered_empty_flow()
+ {
+ Flow<Integer> flow = F.flow("Mary", "had",
"etc.").filter(F.isNull()).map(stringToLength);
+
+ assertTrue(flow.isEmpty());
+ assertEquals(flow.count(), 0);
+ }
+
+ @Test
+ public void toString_mapper()
+ {
+ Flow<Integer> flow = F.flow(1, 2, 3);
+
+ assertFlowValues(flow.map(F.<Integer> stringValueOf()), "1", "2", "3");
+ }
+
+ @Test
+ public void no_excess_mapping()
+ {
+ final AtomicInteger count = new AtomicInteger();
+
+ Mapper<Integer, Integer> doubler = new Mapper<Integer, Integer>()
+ {
+ public Integer map(Integer value)
+ {
+ count.incrementAndGet();
+
+ return value * 2;
+ }
+ };
+
+ assertFlowValues(F.range(1,
100).filter(F.gt(10)).map(doubler).take(3), 22, 24, 26);
+
+ assertEquals(count.get(), 3);
+
+ count.set(0);
+
+ // Because of laziness, its possible to count all the values in some
mapped lists, without
+ // ever actually running the mapper to determine the final value.
+
+ assertEquals(F.range(1, 100).map(doubler).count(), 99);
+ assertEquals(count.get(), 0);
+ }
+}
Propchange:
tapestry/tapestry5/trunk/tapestry-func/src/test/java/org/apache/tapestry5/func/MapperTest.java
------------------------------------------------------------------------------
svn:eol-style = native