Skip to content

Commit

Permalink
Merge pull request #13967 from mkouba/qute-cleanup-and-optimizations
Browse files Browse the repository at this point in the history
Qute cleanup and minor optimizations
  • Loading branch information
mkouba authored Dec 18, 2020
2 parents b06c505 + 3f140d7 commit fe1e190
Show file tree
Hide file tree
Showing 26 changed files with 301 additions and 136 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,6 @@
import java.util.Objects;
import java.util.Optional;
import java.util.Set;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.CompletionStage;
import java.util.function.Function;
import java.util.function.Predicate;
Expand Down Expand Up @@ -330,7 +329,7 @@ public SectionHelper initialize(SectionInitContext context) {
return new SectionHelper() {
@Override
public CompletionStage<ResultNode> resolve(SectionResolutionContext context) {
return CompletableFuture.completedFuture(ResultNode.NOOP);
return ResultNode.NOOP;
}
};
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ public static EvaluatedParams evaluate(EvalContext context) {
results.add(result);
}
}
return new EvaluatedParams(CompletableFuture.allOf(results.toArray(Futures.EMPTY_RESULTS)), allResults);
return new EvaluatedParams(CompletableFuture.allOf(results.toArray(new CompletableFuture[0])), allResults);
}

public static EvaluatedParams evaluateMessageKey(EvalContext context) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -73,10 +73,10 @@ private CompletionStage<Object> resolveReference(boolean tryParent, Object ref,
EvalContextImpl evalContext = new EvalContextImpl(tryParent, ref, part, resolutionContext);
if (!parts.hasNext()) {
// The last part - no need to compose
return resolve(evalContext, resolvers.iterator(), true);
return resolve(evalContext, null, true);
} else {
// Next part - no need to try the parent context/outer scope
return resolve(evalContext, resolvers.iterator(), true)
return resolve(evalContext, null, true)
.thenCompose(r -> resolveReference(false, r, parts, resolutionContext));
}
}
Expand All @@ -86,46 +86,55 @@ private CompletionStage<Object> resolve(EvalContextImpl evalContext, Iterator<Va

if (tryCachedResolver) {
// Try the cached resolver first
ValueResolver cachedResolver = ((PartImpl) evalContext.part).cachedResolver;
ValueResolver cachedResolver = evalContext.getCachedResolver();
if (cachedResolver != null && cachedResolver.appliesTo(evalContext)) {
return cachedResolver.resolve(evalContext).thenCompose(r -> {
if (Result.NOT_FOUND.equals(r)) {
return resolve(evalContext, resolvers, false);
return resolve(evalContext, null, false);
} else {
return toCompletionStage(r);
}
});
}
}

if (!resolvers.hasNext()) {
if (resolvers == null) {
// Iterate the resolvers lazily
resolvers = this.resolvers.iterator();
}

ValueResolver applicableResolver = null;
while (applicableResolver == null && resolvers.hasNext()) {
ValueResolver next = resolvers.next();
if (next.appliesTo(evalContext)) {
applicableResolver = next;
}
}
if (applicableResolver == null) {
ResolutionContext parent = evalContext.resolutionContext.getParent();
if (evalContext.tryParent && parent != null) {
// Continue with parent context
return resolve(
new EvalContextImpl(true, parent.getData(), evalContext.name, evalContext.params, parent,
new EvalContextImpl(true, parent.getData(), parent,
evalContext.part),
this.resolvers.iterator(), false);
null, false);
}
LOGGER.tracef("Unable to resolve %s", evalContext);
return Results.NOT_FOUND;
}
ValueResolver resolver = resolvers.next();
if (resolver.appliesTo(evalContext)) {
return resolver.resolve(evalContext).thenCompose(r -> {
if (Result.NOT_FOUND.equals(r)) {
// Result not found - try the next resolver
return resolve(evalContext, resolvers, false);
} else {
// Cache the first resolver where a result is found
((PartImpl) evalContext.part).setCachedResolver(resolver);
return toCompletionStage(r);
}
});
} else {
// Try the next resolver
return resolve(evalContext, resolvers, false);
}

final Iterator<ValueResolver> remainingResolvers = resolvers;
final ValueResolver foundResolver = applicableResolver;
return applicableResolver.resolve(evalContext).thenCompose(r -> {
if (Result.NOT_FOUND.equals(r)) {
// Result not found - try the next resolver
return resolve(evalContext, remainingResolvers, false);
} else {
// Cache the first resolver where a result is found
evalContext.setCachedResolver(foundResolver);
return toCompletionStage(r);
}
});
}

@SuppressWarnings("unchecked")
Expand All @@ -144,25 +153,18 @@ static class EvalContextImpl implements EvalContext {

final boolean tryParent;
final Object base;
final String name;
final List<Expression> params;
final ResolutionContext resolutionContext;
final Part part;
final PartImpl part;

EvalContextImpl(boolean tryParent, Object base, Part part, ResolutionContext resolutionContext) {
this(tryParent, base, part.getName(),
part.isVirtualMethod() ? part.asVirtualMethod().getParameters() : Collections.emptyList(),
resolutionContext, part);
this(tryParent, base, resolutionContext, part);
}

EvalContextImpl(boolean tryParent, Object base, String name, List<Expression> params,
ResolutionContext resolutionContext, Part part) {
EvalContextImpl(boolean tryParent, Object base, ResolutionContext resolutionContext, Part part) {
this.tryParent = tryParent;
this.base = base;
this.resolutionContext = resolutionContext;
this.params = params;
this.name = name;
this.part = part;
this.part = (PartImpl) part;
}

@Override
Expand All @@ -172,12 +174,12 @@ public Object getBase() {

@Override
public String getName() {
return name;
return part.getName();
}

@Override
public List<Expression> getParams() {
return params;
return part.isVirtualMethod() ? part.asVirtualMethod().getParameters() : Collections.emptyList();
}

@Override
Expand All @@ -195,11 +197,19 @@ public Object getAttribute(String key) {
return resolutionContext.getAttribute(key);
}

ValueResolver getCachedResolver() {
return part.cachedResolver;
}

void setCachedResolver(ValueResolver valueResolver) {
part.cachedResolver = valueResolver;
}

@Override
public String toString() {
StringBuilder builder = new StringBuilder();
builder.append("EvalContextImpl [tryParent=").append(tryParent).append(", base=").append(base).append(", name=")
.append(name).append(", params=").append(params).append("]");
.append(getBase()).append(", params=").append(getParams()).append("]");
return builder.toString();
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,6 @@

public final class Futures {

@SuppressWarnings("unchecked")
static final CompletableFuture<ResultNode>[] EMPTY_RESULTS = new CompletableFuture[0];

private Futures() {
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ public CompletionStage<ResultNode> resolve(SectionResolutionContext context) {
IfBlock block = blocks.get(0);
return block.condition.evaluate(context).thenCompose(r -> {
if (isFalsy(r)) {
return CompletableFuture.completedFuture(ResultNode.NOOP);
return ResultNode.NOOP;
} else {
return context.execute(block.block, context.resolutionContext());
}
Expand All @@ -66,7 +66,7 @@ private CompletionStage<ResultNode> resolveBlocks(SectionResolutionContext conte
if (blocks.hasNext()) {
return resolveBlocks(context, blocks);
}
return CompletableFuture.completedFuture(ResultNode.NOOP);
return ResultNode.NOOP;
} else {
return context.execute(block.block, context.resolutionContext());
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ public IncludeSectionHelper(Supplier<Template> templateSupplier, Map<String, Sec
public CompletionStage<ResultNode> resolve(SectionResolutionContext context) {
if (parameters.isEmpty()) {
return ((TemplateImpl) templateSupplier.get()).root
.resolve(context.resolutionContext().createChild(null, null, extendingBlocks));
.resolve(context.resolutionContext().createChild(null, extendingBlocks));
} else {
CompletableFuture<ResultNode> result = new CompletableFuture<>();
evaluateParams(parameters, context.resolutionContext()).whenComplete((evaluatedParams, t1) -> {
Expand All @@ -41,7 +41,7 @@ public CompletionStage<ResultNode> resolve(SectionResolutionContext context) {
// Execute the template with the params as the root context object
TemplateImpl tagTemplate = (TemplateImpl) templateSupplier.get();
tagTemplate.root
.resolve(context.resolutionContext().createChild(evaluatedParams, null, extendingBlocks))
.resolve(context.resolutionContext().createChild(evaluatedParams, extendingBlocks))
.whenComplete((resultNode, t2) -> {
if (t2 != null) {
result.completeExceptionally(t2);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@

import static io.quarkus.qute.Parameter.EMPTY;

import io.quarkus.qute.Results.Result;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Iterator;
Expand All @@ -11,7 +10,6 @@
import java.util.Objects;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.CompletionStage;
import java.util.concurrent.atomic.AtomicReference;
import java.util.stream.IntStream;
import java.util.stream.Stream;

Expand Down Expand Up @@ -47,21 +45,24 @@ public CompletionStage<ResultNode> resolve(SectionResolutionContext context) {
results.add(nextElement(iterator.next(), idx++, iterator.hasNext(), context));
}
if (results.isEmpty()) {
return CompletableFuture.completedFuture(ResultNode.NOOP);
return ResultNode.NOOP;
}
if (results.size() == 1) {
return results.get(0);
}
CompletableFuture<ResultNode> result = new CompletableFuture<>();
CompletableFuture<ResultNode>[] all = new CompletableFuture[results.size()];
CompletableFuture<ResultNode>[] allResults = new CompletableFuture[results.size()];
idx = 0;
for (CompletionStage<ResultNode> r : results) {
all[idx++] = r.toCompletableFuture();
allResults[idx++] = r.toCompletableFuture();
}
CompletableFuture
.allOf(all)
.allOf(allResults)
.whenComplete((v, t) -> {
if (t != null) {
result.completeExceptionally(t);
} else {
result.complete(new MultiResultNode(all));
result.complete(new MultiResultNode(allResults));
}
});
return result;
Expand Down Expand Up @@ -90,10 +91,8 @@ private Iterator<?> extractIterator(Object it) {
}

CompletionStage<ResultNode> nextElement(Object element, int index, boolean hasNext, SectionResolutionContext context) {
AtomicReference<ResolutionContext> resolutionContextHolder = new AtomicReference<>();
ResolutionContext child = context.resolutionContext().createChild(new IterationElement(alias, element, index, hasNext),
null, null);
resolutionContextHolder.set(child);
null);
return context.execute(child);
}

Expand Down Expand Up @@ -160,43 +159,47 @@ public Scope initializeBlock(Scope previousScope, BlockInfo block) {

static class IterationElement implements Mapper {

static final CompletableFuture<Object> EVEN = CompletableFuture.completedFuture("even");
static final CompletableFuture<Object> ODD = CompletableFuture.completedFuture("odd");

final String alias;
final Object element;
final CompletableFuture<Object> element;
final int index;
final boolean hasNext;

public IterationElement(String alias, Object element, int index, boolean hasNext) {
this.alias = alias;
this.element = element;
this.element = CompletableFuture.completedFuture(element);
this.index = index;
this.hasNext = hasNext;
}

@Override
public Object get(String key) {
public CompletionStage<Object> getAsync(String key) {
if (alias.equals(key)) {
return element;
}
// Iteration metadata
switch (key) {
case "count":
return index + 1;
return CompletableFuture.completedFuture(index + 1);
case "index":
return index;
return CompletableFuture.completedFuture(index);
case "indexParity":
return index % 2 != 0 ? "even" : "odd";
return index % 2 != 0 ? EVEN : ODD;
case "hasNext":
return hasNext;
return hasNext ? Results.TRUE : Results.FALSE;
case "isOdd":
case "odd":
return index % 2 == 0;
return (index % 2 == 0) ? Results.TRUE : Results.FALSE;
case "isEven":
case "even":
return index % 2 != 0;
return (index % 2 != 0) ? Results.TRUE : Results.FALSE;
default:
return Result.NOT_FOUND;
return Results.NOT_FOUND;
}
}

}

}
Original file line number Diff line number Diff line change
@@ -1,13 +1,22 @@
package io.quarkus.qute;

import java.util.concurrent.CompletableFuture;
import java.util.concurrent.CompletionStage;

/**
* Maps keys to values in a similar way to {@link java.util.Map}. The difference is that it could be stateless, ie. the lookup
* may be performed dynamically.
* Maps keys to values in a similar way to {@link java.util.Map}. The difference is that a mapper could be stateless, i.e. the
* lookup may be performed dynamically.
*
* @see ValueResolvers#mapperResolver()
*/
public interface Mapper {

Object get(String key);
default Object get(String key) {
return null;
}

default CompletionStage<Object> getAsync(String key) {
return CompletableFuture.completedFuture(get(key));
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -12,15 +12,14 @@ public class MultiResultNode implements ResultNode {
private final ResultNode[] results;

public MultiResultNode(CompletableFuture<ResultNode>[] futures) {
ResultNode[] results = new ResultNode[futures.length];
results = new ResultNode[futures.length];
for (int i = 0; i < futures.length; i++) {
try {
results[i] = futures[i].get();
} catch (InterruptedException | ExecutionException e) {
throw new IllegalStateException(e);
}
}
this.results = results;
}

@Override
Expand Down
Loading

0 comments on commit fe1e190

Please sign in to comment.