Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Qute - minor cleanup and micro optimizations #16180

Merged
merged 1 commit into from
Apr 8, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
@Vetoed // Make sure no bean is created from this class
@TemplateExtension
public class MapTemplateExtensions {
@SuppressWarnings({ "rawtypes", "unchecked" })
@SuppressWarnings({ "rawtypes" })
@TemplateExtension(matchName = ANY)
static Object map(Map map, String name) {
switch (name) {
Expand All @@ -29,7 +29,11 @@ static Object map(Map map, String name) {
case "isEmpty":
return map.isEmpty();
default:
return map.getOrDefault(name, Result.NOT_FOUND);
Object val = map.get(name);
if (val == null) {
return map.containsKey(name) ? null : Result.NOT_FOUND;
}
return val;
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,8 +41,9 @@ class EngineImpl implements Engine {
EngineImpl(EngineBuilder builder) {
this.sectionHelperFactories = Collections.unmodifiableMap(new HashMap<>(builder.sectionHelperFactories));
this.valueResolvers = sort(builder.valueResolvers);
this.namespaceResolvers = ImmutableList.copyOf(builder.namespaceResolvers);
this.evaluator = new EvaluatorImpl(this.valueResolvers);
this.namespaceResolvers = ImmutableList.<NamespaceResolver> builder()
.addAll(builder.namespaceResolvers).add(new TemplateImpl.DataNamespaceResolver()).build();
this.evaluator = new EvaluatorImpl(this.valueResolvers, this.namespaceResolvers);
this.templates = new ConcurrentHashMap<>();
this.locators = sort(builder.locators);
this.resultMappers = sort(builder.resultMappers);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,18 +32,29 @@ public static EvaluatedParams evaluate(EvalContext context) {
return new EvaluatedParams(context.evaluate(params.get(0)));
}
CompletableFuture<?>[] allResults = new CompletableFuture<?>[params.size()];
List<CompletableFuture<?>> results = new LinkedList<>();
List<CompletableFuture<?>> results = null;
int i = 0;
Iterator<Expression> it = params.iterator();
while (it.hasNext()) {
Expression expression = it.next();
CompletableFuture<Object> result = context.evaluate(expression).toCompletableFuture();
allResults[i++] = result;
if (!expression.isLiteral()) {
if (results == null) {
results = new LinkedList<>();
}
results.add(result);
}
}
return new EvaluatedParams(CompletableFuture.allOf(results.toArray(new CompletableFuture[0])), allResults);
CompletionStage<?> cs;
if (results == null) {
cs = Futures.COMPLETED;
} else if (results.size() == 1) {
cs = results.get(0);
} else {
cs = CompletableFuture.allOf(results.toArray(new CompletableFuture[0]));
}
return new EvaluatedParams(cs, allResults);
}

public static EvaluatedParams evaluateMessageKey(EvalContext context) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,17 +19,25 @@ class EvaluatorImpl implements Evaluator {
private static final Logger LOGGER = Logger.getLogger(EvaluatorImpl.class);

private final List<ValueResolver> resolvers;
private final List<NamespaceResolver> namespaceResolvers;

EvaluatorImpl(List<ValueResolver> valueResolvers) {
EvaluatorImpl(List<ValueResolver> valueResolvers, List<NamespaceResolver> namespaceResolvers) {
this.resolvers = valueResolvers;
this.namespaceResolvers = namespaceResolvers;
}

@Override
public CompletionStage<Object> evaluate(Expression expression, ResolutionContext resolutionContext) {
Iterator<Part> parts;
if (expression.hasNamespace()) {
parts = expression.getParts().iterator();
NamespaceResolver resolver = findNamespaceResolver(expression.getNamespace(), resolutionContext);
NamespaceResolver resolver = null;
for (NamespaceResolver namespaceResolver : namespaceResolvers) {
if (namespaceResolver.getNamespace().equals(expression.getNamespace())) {
resolver = namespaceResolver;
break;
}
}
if (resolver == null) {
LOGGER.errorf("No namespace resolver found for: %s", expression.getNamespace());
return Futures.failure(new TemplateException("No resolver for namespace: " + expression.getNamespace()));
Expand All @@ -53,20 +61,6 @@ public CompletionStage<Object> evaluate(Expression expression, ResolutionContext
}
}

private NamespaceResolver findNamespaceResolver(String namespace, ResolutionContext resolutionContext) {
if (resolutionContext == null) {
return null;
}
if (resolutionContext.getNamespaceResolvers() != null) {
for (NamespaceResolver resolver : resolutionContext.getNamespaceResolvers()) {
if (resolver.getNamespace().equals(namespace)) {
return resolver;
}
}
}
return findNamespaceResolver(namespace, resolutionContext.getParent());
}

private CompletionStage<Object> resolveReference(boolean tryParent, Object ref, Iterator<Part> parts,
ResolutionContext resolutionContext) {
Part part = parts.next();
Expand Down Expand Up @@ -138,7 +132,7 @@ private CompletionStage<Object> resolve(EvalContextImpl evalContext, Iterator<Va
}

@SuppressWarnings("unchecked")
private CompletionStage<Object> toCompletionStage(Object result) {
private static CompletionStage<Object> toCompletionStage(Object result) {
if (result instanceof CompletionStage) {
// If the result is a completion stage return it as is
return (CompletionStage<Object>) result;
Expand All @@ -155,6 +149,8 @@ static class EvalContextImpl implements EvalContext {
final Object base;
final ResolutionContext resolutionContext;
final PartImpl part;
final List<Expression> params;
final String name;

EvalContextImpl(boolean tryParent, Object base, Part part, ResolutionContext resolutionContext) {
this(tryParent, base, resolutionContext, part);
Expand All @@ -165,6 +161,8 @@ static class EvalContextImpl implements EvalContext {
this.base = base;
this.resolutionContext = resolutionContext;
this.part = (PartImpl) part;
this.name = part.getName();
this.params = part.isVirtualMethod() ? part.asVirtualMethod().getParameters() : Collections.emptyList();
}

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

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

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

@Override
Expand Down Expand Up @@ -209,7 +207,7 @@ void setCachedResolver(ValueResolver valueResolver) {
public String toString() {
StringBuilder builder = new StringBuilder();
builder.append("EvalContextImpl [tryParent=").append(tryParent).append(", base=").append(base).append(", name=")
.append(getBase()).append(", params=").append(getParams()).append("]");
.append(getName()).append(", params=").append(getParams()).append("]");
return builder.toString();
}

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

public final class Futures {

static final CompletableFuture<Void> COMPLETED = CompletableFuture.completedFuture(null);

private Futures() {
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
import java.util.Objects;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.CompletionStage;
import java.util.concurrent.ExecutionException;
import java.util.stream.Collectors;

/**
Expand Down Expand Up @@ -152,15 +153,6 @@ interface Condition {

Operator getOperator();

/**
* Short-circuiting evaluation.
*
* @return null if evaluation should continue
*/
default Boolean evaluate(Object value) {
return getOperator() != null ? getOperator().evaluate(value) : null;
}

default boolean isLogicalComplement() {
return Operator.NOT.equals(getOperator());
}
Expand All @@ -169,16 +161,32 @@ default boolean isEmpty() {
return false;
}

default Object getLiteralValue() {
return null;
}

}

static class OperandCondition implements Condition {

final Operator operator;
final Expression expression;
final Object literalValue;

OperandCondition(Operator operator, Expression expression) {
this.operator = operator;
this.expression = expression;
CompletableFuture<Object> literalVal = expression.getLiteralValue();
if (literalVal != null) {
try {
this.literalValue = literalVal.get();
} catch (InterruptedException | ExecutionException e) {
throw new IllegalStateException(e);
}
} else {
this.literalValue = null;
}

}

@Override
Expand All @@ -191,6 +199,11 @@ public Operator getOperator() {
return operator;
}

@Override
public Object getLiteralValue() {
return literalValue;
}

@Override
public String toString() {
return "OperandCondition [operator=" + operator + ", expression=" + expression.toOriginalString() + "]";
Expand All @@ -213,53 +226,27 @@ public CompletionStage<Object> evaluate(SectionResolutionContext context) {
return evaluateNext(context, null, conditions.iterator());
}

CompletionStage<Object> evaluateNext(SectionResolutionContext context, Object value, Iterator<Condition> iter) {
static CompletionStage<Object> evaluateNext(SectionResolutionContext context, Object value, Iterator<Condition> iter) {
CompletableFuture<Object> result = new CompletableFuture<>();
if (!iter.hasNext()) {
result.complete(value);
Condition next = iter.next();
Boolean shortResult = null;
Operator operator = next.getOperator();
if (operator != null && operator.isShortCircuiting()) {
shortResult = operator.evaluate(value);
}
if (shortResult != null) {
// There is no need to continue with the next operand
result.complete(shortResult);
} else {
Condition next = iter.next();
Boolean shortResult = null;
Operator operator = next.getOperator();
if (operator != null && operator.isShortCircuiting()) {
shortResult = operator.evaluate(value);
}
if (shortResult != null) {
// There is no need to continue with the next operand
result.complete(shortResult);
Object literalVal = next.getLiteralValue();
if (literalVal != null) {
processConditionValue(context, next, operator, value, literalVal, result, iter);
} else {
next.evaluate(context).whenComplete((r, t) -> {
if (t != null) {
result.completeExceptionally(t);
} else {
Object val;
if (next.isLogicalComplement()) {
r = Booleans.isFalsy(r) ? Boolean.TRUE : Boolean.FALSE;
}
if (operator == null || !operator.isBinary()) {
val = r;
} else {
try {
if (Result.NOT_FOUND.equals(r)) {
r = null;
}
Object localValue = value;
if (Result.NOT_FOUND.equals(localValue)) {
localValue = null;
}
val = operator.evaluate(localValue, r);
} catch (Throwable e) {
result.completeExceptionally(e);
throw e;
}
}
evaluateNext(context, val, iter).whenComplete((r2, t2) -> {
if (t2 != null) {
result.completeExceptionally(t2);
} else {
result.complete(r2);
}
});
processConditionValue(context, next, operator, value, r, result, iter);
}
});
}
Expand All @@ -282,6 +269,43 @@ public String toString() {
return "CompositeCondition [conditions=" + conditions.size() + ", operator=" + operator + "]";
}

static void processConditionValue(SectionResolutionContext context, Condition condition, Operator operator,
Object previousValue, Object conditionValue, CompletableFuture<Object> result, Iterator<Condition> iter) {
Object val;
if (condition.isLogicalComplement()) {
conditionValue = Booleans.isFalsy(conditionValue) ? Boolean.TRUE : Boolean.FALSE;
}
if (operator == null || !operator.isBinary()) {
val = conditionValue;
} else {
// Binary operator
try {
if (Result.NOT_FOUND.equals(conditionValue)) {
conditionValue = null;
}
Object localValue = previousValue;
if (Result.NOT_FOUND.equals(localValue)) {
localValue = null;
}
val = operator.evaluate(localValue, conditionValue);
} catch (Throwable e) {
result.completeExceptionally(e);
throw e;
}
}
if (!iter.hasNext()) {
result.complete(val);
} else {
evaluateNext(context, val, iter).whenComplete((r2, t2) -> {
if (t2 != null) {
result.completeExceptionally(t2);
} else {
result.complete(r2);
}
});
}
}

}

enum Operator {
Expand Down Expand Up @@ -544,7 +568,7 @@ static Condition createCondition(Object param, SectionBlock block, Operator oper
nextOperator = null;
}
}
condition = new CompositeCondition(operator, conditions);
condition = new CompositeCondition(operator, ImmutableList.copyOf(conditions));
} else {
throw new TemplateException("Unsupported param type: " + param);
}
Expand Down
Loading