You are viewing a plain text version of this content. The canonical link for it is here.
Posted to notifications@freemarker.apache.org by dd...@apache.org on 2019/05/25 23:02:16 UTC
[freemarker] 02/03: Generalized/simplified the way it's decided if
an expression can produce or consume lazily generated values.
This is an automated email from the ASF dual-hosted git repository.
ddekany pushed a commit to branch 2.3-gae
in repository https://gitbox.apache.org/repos/asf/freemarker.git
commit 1f25c8b538d9c5ecc5fb4e95f3b65cd55b6a60c7
Author: ddekany <dd...@apache.org>
AuthorDate: Sat May 25 14:59:36 2019 +0200
Generalized/simplified the way it's decided if an expression can produce or consume lazily generated values.
---
src/main/java/freemarker/core/BuiltIn.java | 13 +++---
.../freemarker/core/BuiltInsForMultipleTypes.java | 2 +-
.../java/freemarker/core/BuiltInsForSequences.java | 46 +++++++++-------------
src/main/java/freemarker/core/DynamicKeyName.java | 6 +--
src/main/java/freemarker/core/Expression.java | 18 +++++++++
src/main/java/freemarker/core/IteratorBlock.java | 10 +----
.../core/LazilyGeneratedSequenceModel.java | 6 ++-
.../freemarker/core/ParentheticalExpression.java | 7 +++-
.../core/SingleIterationCollectionModel.java | 2 +-
9 files changed, 55 insertions(+), 55 deletions(-)
diff --git a/src/main/java/freemarker/core/BuiltIn.java b/src/main/java/freemarker/core/BuiltIn.java
index 9e3dd3c..57c3313 100644
--- a/src/main/java/freemarker/core/BuiltIn.java
+++ b/src/main/java/freemarker/core/BuiltIn.java
@@ -386,18 +386,15 @@ abstract class BuiltIn extends Expression implements Cloneable {
throw new InternalError();
}
bi.key = key;
- bi.target = target;
- if (bi.isLazilyGeneratedSequenceModelTargetSupported()) {
- Expression cleanedTarget = MiscUtil.peelParentheses(target);
- if (cleanedTarget instanceof BuiltInsForSequences.IntermediateStreamOperationLikeBuiltIn) {
- ((BuiltInsForSequences.IntermediateStreamOperationLikeBuiltIn) cleanedTarget)
- .setLazyResultGenerationAllowed(true);
- }
+ if (bi.isLazilyGeneratedTargetResultSupported()) {
+ target.enableLazilyGeneratedResult();
}
+ bi.target = target;
return bi;
}
- protected boolean isLazilyGeneratedSequenceModelTargetSupported() {
+ /** If the built-in supports a lazily generated value as its left operand (the target). */
+ protected boolean isLazilyGeneratedTargetResultSupported() {
return false;
}
diff --git a/src/main/java/freemarker/core/BuiltInsForMultipleTypes.java b/src/main/java/freemarker/core/BuiltInsForMultipleTypes.java
index b690cf5..c8a0922 100644
--- a/src/main/java/freemarker/core/BuiltInsForMultipleTypes.java
+++ b/src/main/java/freemarker/core/BuiltInsForMultipleTypes.java
@@ -485,7 +485,7 @@ class BuiltInsForMultipleTypes {
static class sizeBI extends BuiltIn {
@Override
- protected boolean isLazilyGeneratedSequenceModelTargetSupported() {
+ protected boolean isLazilyGeneratedTargetResultSupported() {
return true;
}
diff --git a/src/main/java/freemarker/core/BuiltInsForSequences.java b/src/main/java/freemarker/core/BuiltInsForSequences.java
index b4acd16..ba40615 100644
--- a/src/main/java/freemarker/core/BuiltInsForSequences.java
+++ b/src/main/java/freemarker/core/BuiltInsForSequences.java
@@ -144,7 +144,7 @@ class BuiltInsForSequences {
static class firstBI extends BuiltIn {
@Override
- protected boolean isLazilyGeneratedSequenceModelTargetSupported() {
+ protected boolean isLazilyGeneratedTargetResultSupported() {
return true;
}
@@ -185,7 +185,7 @@ class BuiltInsForSequences {
static class joinBI extends BuiltIn {
@Override
- protected boolean isLazilyGeneratedSequenceModelTargetSupported() {
+ protected boolean isLazilyGeneratedTargetResultSupported() {
return true;
}
@@ -302,7 +302,7 @@ class BuiltInsForSequences {
static class seq_containsBI extends BuiltIn {
@Override
- protected boolean isLazilyGeneratedSequenceModelTargetSupported() {
+ protected boolean isLazilyGeneratedTargetResultSupported() {
return true;
}
@@ -374,7 +374,7 @@ class BuiltInsForSequences {
static class seq_index_ofBI extends BuiltIn {
@Override
- protected boolean isLazilyGeneratedSequenceModelTargetSupported() {
+ protected boolean isLazilyGeneratedTargetResultSupported() {
return true;
}
@@ -915,7 +915,7 @@ class BuiltInsForSequences {
}
@Override
- protected boolean isLazilyGeneratedSequenceModelTargetSupported() {
+ protected boolean isLazilyGeneratedTargetResultSupported() {
return true;
}
@@ -989,7 +989,7 @@ class BuiltInsForSequences {
private Expression elementTransformerExp;
private ElementTransformer precreatedElementTransformer;
- private boolean lazyResultGenerationAllowed;
+ private boolean lazilyGeneratedResultEnabled;
@Override
void bindToParameters(List<Expression> parameters, Token openParen, Token closeParen) throws ParseException {
@@ -1007,33 +1007,23 @@ class BuiltInsForSequences {
}
@Override
- protected boolean isLocalLambdaParameterSupported() {
+ protected final boolean isLocalLambdaParameterSupported() {
return true;
}
@Override
- protected boolean isLazilyGeneratedSequenceModelTargetSupported() {
- return true;
+ final void enableLazilyGeneratedResult() {
+ this.lazilyGeneratedResultEnabled = true;
}
- final boolean isLazyResultGenerationAllowed() {
- return lazyResultGenerationAllowed;
+ /** Tells if {@link #enableLazilyGeneratedResult()} was called. */
+ protected final boolean isLazilyGeneratedResultEnabled() {
+ return lazilyGeneratedResultEnabled;
}
- /**
- * Used to allow generating the result collection or sequence elements on an as-needed basis, similarly as
- * Java 8 Stream intermediate operations do it. This is initially {@code false}. The containing expression or
- * directive sets it to {@code true} if it can ensure that:
- * <ul>
- * <li>The returned {@link TemplateCollectionModel} is traversed only once, more specifically,
- * {@link TemplateCollectionModel#iterator()} is called only once.
- * <li>When the methods of the collection or iterator are called, the context provided by
- * the {@link Environment} (such as the local context stack) is similar to the context from where the
- * built-in was called. This is required as lambda expression are {@link LocalLambdaExpression}-s.
- * </ul>
- */
- void setLazyResultGenerationAllowed(boolean lazyResultGenerationAllowed) {
- this.lazyResultGenerationAllowed = lazyResultGenerationAllowed;
+ @Override
+ protected final boolean isLazilyGeneratedTargetResultSupported() {
+ return true;
}
protected List<Expression> getArgumentsAsList() {
@@ -1086,7 +1076,7 @@ class BuiltInsForSequences {
private TemplateModelIterator getTemplateModelIterator(Environment env, TemplateModel model) throws TemplateModelException,
NonSequenceOrCollectionException, InvalidReferenceException {
if (model instanceof TemplateCollectionModel) {
- return isLazyResultGenerationAllowed()
+ return isLazilyGeneratedResultEnabled()
? new LazyCollectionTemplateModelIterator((TemplateCollectionModel) model)
: ((TemplateCollectionModel) model).iterator();
} else if (model instanceof TemplateSequenceModel) {
@@ -1176,7 +1166,7 @@ class BuiltInsForSequences {
final TemplateModelIterator lhoIterator, final TemplateModel lho,
final ElementTransformer elementTransformer,
final Environment env) throws TemplateException {
- if (!isLazyResultGenerationAllowed()) {
+ if (!isLazilyGeneratedResultEnabled()) {
List<TemplateModel> resultList = new ArrayList<TemplateModel>();
while (lhoIterator.hasNext()) {
TemplateModel element = lhoIterator.next();
@@ -1262,7 +1252,7 @@ class BuiltInsForSequences {
protected TemplateModel calculateResult(
final TemplateModelIterator lhoIterator, TemplateModel lho, final ElementTransformer elementTransformer,
final Environment env) throws TemplateException {
- if (!isLazyResultGenerationAllowed()) {
+ if (!isLazilyGeneratedResultEnabled()) {
List<TemplateModel> resultList = new ArrayList<TemplateModel>();
while (lhoIterator.hasNext()) {
resultList.add(fetchAndMapNextElement(lhoIterator, elementTransformer, env));
diff --git a/src/main/java/freemarker/core/DynamicKeyName.java b/src/main/java/freemarker/core/DynamicKeyName.java
index c01d0ef..15ff96b 100644
--- a/src/main/java/freemarker/core/DynamicKeyName.java
+++ b/src/main/java/freemarker/core/DynamicKeyName.java
@@ -51,11 +51,7 @@ final class DynamicKeyName extends Expression {
this.target = target;
this.keyExpression = keyExpression;
- Expression cleanedTarget = MiscUtil.peelParentheses(target);
- if (cleanedTarget instanceof BuiltInsForSequences.IntermediateStreamOperationLikeBuiltIn) {
- ((BuiltInsForSequences.IntermediateStreamOperationLikeBuiltIn) cleanedTarget)
- .setLazyResultGenerationAllowed(true);
- }
+ target.enableLazilyGeneratedResult();
}
@Override
diff --git a/src/main/java/freemarker/core/Expression.java b/src/main/java/freemarker/core/Expression.java
index 0c3575c..5a69095 100644
--- a/src/main/java/freemarker/core/Expression.java
+++ b/src/main/java/freemarker/core/Expression.java
@@ -77,6 +77,24 @@ abstract public class Expression extends TemplateObject {
public final TemplateModel getAsTemplateModel(Environment env) throws TemplateException {
return eval(env);
}
+
+ /**
+ * Allows generating the result collection or sequence elements (or maybe others in future) on an as-needed basis,
+ * similarly as Java 8 Stream intermediate operations do it. The default implementation in {@link Expression}
+ * does nothing, as most expressions can't create such result. The containing expression or directive calls
+ * this if it can ensure that:
+ * <ul>
+ * <li>If the returned value is a {@link TemplateCollectionModel}, then it's traversed at most once, more
+ * specifically, {@link TemplateCollectionModel#iterator()} is called at most once.
+ * <li>When the methods of the collection or iterator are called, the context provided by
+ * the {@link Environment} (such as the local context stack) is similar to the context from where this
+ * expression was called. This is required as lazily generated results are allowed to be based on
+ * {@link LocalLambdaExpression}-s.
+ * </ul>
+ */
+ void enableLazilyGeneratedResult() {
+ // Has no effect by default
+ }
final TemplateModel eval(Environment env) throws TemplateException {
try {
diff --git a/src/main/java/freemarker/core/IteratorBlock.java b/src/main/java/freemarker/core/IteratorBlock.java
index c734cbe..aaaaf64 100644
--- a/src/main/java/freemarker/core/IteratorBlock.java
+++ b/src/main/java/freemarker/core/IteratorBlock.java
@@ -48,7 +48,6 @@ final class IteratorBlock extends TemplateElement {
private final String loopVar2Name;
private final boolean hashListing;
private final boolean forEach;
- private final boolean fetchElementsOutsideLoopVarContext;
/**
* @param listedExp
@@ -83,14 +82,7 @@ final class IteratorBlock extends TemplateElement {
this.hashListing = hashListing;
this.forEach = forEach;
- Expression cleanedListExp = MiscUtil.peelParentheses(listedExp);
- if (cleanedListExp instanceof BuiltInsForSequences.IntermediateStreamOperationLikeBuiltIn) {
- ((BuiltInsForSequences.IntermediateStreamOperationLikeBuiltIn) cleanedListExp)
- .setLazyResultGenerationAllowed(true);
- fetchElementsOutsideLoopVarContext = true;
- } else {
- fetchElementsOutsideLoopVarContext = false;
- }
+ listedExp.enableLazilyGeneratedResult();
}
boolean isHashListing() {
diff --git a/src/main/java/freemarker/core/LazilyGeneratedSequenceModel.java b/src/main/java/freemarker/core/LazilyGeneratedSequenceModel.java
index a0737f1..26e210a 100644
--- a/src/main/java/freemarker/core/LazilyGeneratedSequenceModel.java
+++ b/src/main/java/freemarker/core/LazilyGeneratedSequenceModel.java
@@ -26,10 +26,12 @@ import freemarker.template.TemplateSequenceModel;
/**
* Same as {@link SingleIterationCollectionModel}, but marks the value as something that's in principle a
* {@link TemplateSequenceModel}, but to allow lazy result generation a {@link CollectionModel} is used internally.
- * This is an optimization that we do where we consider it to be transparent enough for the user.
+ * This is an optimization that we do where we consider it to be transparent enough for the user. An operator or
+ * built-in should only ever receive a {@link LazilyGeneratedSequenceModel} if it has explicitly allowed its
+ * input expression to return such value via calling {@link Expression#enableLazilyGeneratedResult()}.
*/
class LazilyGeneratedSequenceModel extends SingleIterationCollectionModel {
- public LazilyGeneratedSequenceModel(TemplateModelIterator iterator) {
+ LazilyGeneratedSequenceModel(TemplateModelIterator iterator) {
super(iterator);
}
}
diff --git a/src/main/java/freemarker/core/ParentheticalExpression.java b/src/main/java/freemarker/core/ParentheticalExpression.java
index f63e0b6..07f5d18 100644
--- a/src/main/java/freemarker/core/ParentheticalExpression.java
+++ b/src/main/java/freemarker/core/ParentheticalExpression.java
@@ -60,6 +60,11 @@ final class ParentheticalExpression extends Expression {
}
@Override
+ void enableLazilyGeneratedResult() {
+ nested.enableLazilyGeneratedResult();
+ }
+
+ @Override
protected Expression deepCloneWithIdentifierReplaced_inner(
String replacedIdentifier, Expression replacement, ReplacemenetState replacementState) {
return new ParentheticalExpression(
@@ -82,5 +87,5 @@ final class ParentheticalExpression extends Expression {
if (idx != 0) throw new IndexOutOfBoundsException();
return ParameterRole.ENCLOSED_OPERAND;
}
-
+
}
diff --git a/src/main/java/freemarker/core/SingleIterationCollectionModel.java b/src/main/java/freemarker/core/SingleIterationCollectionModel.java
index 292bcd3..56efe93 100644
--- a/src/main/java/freemarker/core/SingleIterationCollectionModel.java
+++ b/src/main/java/freemarker/core/SingleIterationCollectionModel.java
@@ -34,7 +34,7 @@ import freemarker.template.utility.NullArgumentException;
class SingleIterationCollectionModel implements TemplateCollectionModel {
private TemplateModelIterator iterator;
- public SingleIterationCollectionModel(TemplateModelIterator iterator) {
+ SingleIterationCollectionModel(TemplateModelIterator iterator) {
NullArgumentException.check(iterator);
this.iterator = iterator;
}