include matching key in expression

pull/1/head
Mike Barry 2021-06-12 16:40:53 -04:00
rodzic 80827d9135
commit 9915f4e134
2 zmienionych plików z 37 dodań i 13 usunięć

Wyświetl plik

@ -57,7 +57,7 @@ public record MultiExpression<T>(Map<T, Expression> expressions) {
}
}
private static boolean evaluate(Expression expr, Map<String, Object> input) {
private static boolean evaluate(Expression expr, Map<String, Object> input, List<String> matchKeys) {
// optimization: since this is evaluated for every input element, use
// simple for loops instead of enhanced to avoid overhead of generating the
// iterator (~30% speedup)
@ -69,24 +69,27 @@ public record MultiExpression<T>(Map<T, Expression> expressions) {
} else {
String str = value.toString();
if (match.exactMatches().contains(str)) {
matchKeys.add(match.field());
return true;
}
List<String> wildcards = match.wildcards();
for (int i = 0; i < wildcards.size(); i++) {
var target = wildcards.get(i);
if (str.contains(target)) {
matchKeys.add(match.field());
return true;
}
}
return false;
}
} else if (expr instanceof Expression.MatchField match) {
matchKeys.add(match.field());
return input.containsKey(match.field());
} else if (expr instanceof Expression.Or or) {
List<Expression> children = or.children();
for (int i = 0; i < children.size(); i++) {
Expression child = children.get(i);
if (evaluate(child, input)) {
if (evaluate(child, input, matchKeys)) {
return true;
}
}
@ -95,20 +98,22 @@ public record MultiExpression<T>(Map<T, Expression> expressions) {
List<Expression> children = and.children();
for (int i = 0; i < children.size(); i++) {
Expression child = children.get(i);
if (!evaluate(child, input)) {
if (!evaluate(child, input, matchKeys)) {
return false;
}
}
return true;
} else if (expr instanceof Expression.Not not) {
return !evaluate(not.child(), input);
return !evaluate(not.child(), input, new ArrayList<>());
} else {
throw new IllegalArgumentException("Unrecognized expression: " + expr);
}
}
public List<T> getMatches(Map<String, Object> input) {
List<T> result = new ArrayList<>();
public static record MatchWithTriggers<T>(T match, List<String> keys) {}
public List<MatchWithTriggers<T>> getMatchesWithTriggers(Map<String, Object> input) {
List<MatchWithTriggers<T>> result = new ArrayList<>();
BitSet visited = new BitSet(ids.get());
if (input.size() < keyToExpressionsMap.size()) {
for (String inputKey : input.keySet()) {
@ -129,7 +134,12 @@ public record MultiExpression<T>(Map<T, Expression> expressions) {
return result;
}
private void visitExpression(Map<String, Object> input, List<T> result, BitSet visited,
public List<T> getMatches(Map<String, Object> input) {
List<MatchWithTriggers<T>> matches = getMatchesWithTriggers(input);
return matches.stream().map(d -> d.match).toList();
}
private void visitExpression(Map<String, Object> input, List<MatchWithTriggers<T>> result, BitSet visited,
List<ExpressionValue<T>> expressionValues) {
if (expressionValues != null) {
// optimization: since this is evaluated for every element, generating an iterator
@ -138,8 +148,9 @@ public record MultiExpression<T>(Map<T, Expression> expressions) {
var expressionValue = expressionValues.get(i);
if (!visited.get(expressionValue.id)) {
visited.set(expressionValue.id);
if (evaluate(expressionValue.exp(), input)) {
result.add(expressionValue.result);
List<String> matchKeys = new ArrayList<>();
if (evaluate(expressionValue.exp(), input, matchKeys)) {
result.add(new MatchWithTriggers<>(expressionValue.result, matchKeys));
}
}
}

Wyświetl plik

@ -3,6 +3,7 @@ package com.onthegomap.flatmap.openmaptiles;
import static com.onthegomap.flatmap.openmaptiles.Expression.*;
import static org.junit.jupiter.api.Assertions.assertEquals;
import java.util.Comparator;
import java.util.List;
import java.util.Map;
import org.junit.jupiter.api.Test;
@ -158,11 +159,23 @@ public class MultiExpressionTest {
matchAny("key3", "val3")
)
)).index();
// assertSameElements(List.of("a"), index.getMatches(Map.of("key1", "val1")));
// TODO: match {key1=val1} => "key1"
assertSameElements(List.of(new MultiExpression.MultiExpressionIndex.MatchWithTriggers<>(
"a", List.of("key1")
)), index.getMatchesWithTriggers(Map.of("key1", "val1")));
assertSameElements(List.of(new MultiExpression.MultiExpressionIndex.MatchWithTriggers<>(
"a", List.of("key2")
), new MultiExpression.MultiExpressionIndex.MatchWithTriggers<>(
"b", List.of("key2")
)), index.getMatchesWithTriggers(Map.of("key2", "val2")));
assertSameElements(List.of(new MultiExpression.MultiExpressionIndex.MatchWithTriggers<>(
"b", List.of("key3")
)), index.getMatchesWithTriggers(Map.of("key3", "val3")));
}
private static void assertSameElements(List<String> a, List<String> b) {
assertEquals(a.stream().sorted().toList(), b.stream().sorted().toList());
private static <T> void assertSameElements(List<T> a, List<T> b) {
assertEquals(
a.stream().sorted(Comparator.comparing(Object::toString)).toList(),
b.stream().sorted(Comparator.comparing(Object::toString)).toList()
);
}
}