-
-
Notifications
You must be signed in to change notification settings - Fork 57
[Java] Improve cucumber expression creation performance #202
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
Changes from 4 commits
5481450
73a51e1
531d380
a53b0e5
f264cf2
20cc322
fb2e664
7f5c171
b6f51b4
68999a0
99dd95d
7aef82c
6c1f3ec
afc42c8
b2febb7
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change | ||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
@@ -24,7 +24,27 @@ | |||||||||||||
|
||||||||||||||
@API(status = API.Status.STABLE) | ||||||||||||||
public final class CucumberExpression implements Expression { | ||||||||||||||
private static final Pattern ESCAPE_PATTERN = Pattern.compile("[\\\\^\\[({$.|?*+})\\]]"); | ||||||||||||||
/** | ||||||||||||||
* List of characters to be escaped. | ||||||||||||||
* The last char is '}' with index 125, so we need only 126 characters. | ||||||||||||||
*/ | ||||||||||||||
private static final boolean[] CHAR_TO_ESCAPE = new boolean[126]; | ||||||||||||||
static { | ||||||||||||||
CHAR_TO_ESCAPE['^'] = true; | ||||||||||||||
CHAR_TO_ESCAPE['$'] = true; | ||||||||||||||
CHAR_TO_ESCAPE['['] = true; | ||||||||||||||
CHAR_TO_ESCAPE[']'] = true; | ||||||||||||||
CHAR_TO_ESCAPE['('] = true; | ||||||||||||||
CHAR_TO_ESCAPE[')'] = true; | ||||||||||||||
CHAR_TO_ESCAPE['{'] = true; | ||||||||||||||
CHAR_TO_ESCAPE['}'] = true; | ||||||||||||||
CHAR_TO_ESCAPE['.'] = true; | ||||||||||||||
CHAR_TO_ESCAPE['|'] = true; | ||||||||||||||
CHAR_TO_ESCAPE['?'] = true; | ||||||||||||||
CHAR_TO_ESCAPE['*'] = true; | ||||||||||||||
CHAR_TO_ESCAPE['+'] = true; | ||||||||||||||
CHAR_TO_ESCAPE['\\'] = true; | ||||||||||||||
} | ||||||||||||||
private final List<ParameterType<?>> parameterTypes = new ArrayList<>(); | ||||||||||||||
private final String source; | ||||||||||||||
private final TreeRegexp treeRegexp; | ||||||||||||||
|
@@ -61,9 +81,18 @@ private String rewriteToRegex(Node node) { | |||||||||||||
} | ||||||||||||||
|
||||||||||||||
private static String escapeRegex(String text) { | ||||||||||||||
return ESCAPE_PATTERN.matcher(text).replaceAll("\\\\$0"); | ||||||||||||||
int length = text.length(); | ||||||||||||||
StringBuilder sb = new StringBuilder(length * 2); // prevent resizes | ||||||||||||||
int maxChar = CHAR_TO_ESCAPE.length; | ||||||||||||||
for (int i = 0; i < length; i++) { | ||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think that in practice expressions with characters that need to be escaped are rare. Would it make sense to check the entire string for characters that need to be replaced first? It would save an array copy. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. If we rarely escape in practice, the situation is a bit different. We need to benchmark the variants based on the escaping frequency, not only on pure escaping performance. I've implemented two other variants, so to summarize:
I benchmarked these variants with JMH for varying escaping frequencies: The variant
In real conditions, on my project with about ~400 test scenarios runs in about 8.5 seconds. The InteliJ profiler says For completeness, the
|
||||||||||||||
char currentChar = text.charAt(i); | ||||||||||||||
if (currentChar < maxChar && CHAR_TO_ESCAPE[currentChar]) { | ||||||||||||||
sb.append('\\'); | ||||||||||||||
} | ||||||||||||||
sb.append(currentChar); | ||||||||||||||
} | ||||||||||||||
return sb.toString(); | ||||||||||||||
} | ||||||||||||||
|
||||||||||||||
|
||||||||||||||
private String rewriteOptional(Node node) { | ||||||||||||||
assertNoParameters(node, astNode -> createParameterIsNotAllowedInOptional(astNode, source)); | ||||||||||||||
|
Uh oh!
There was an error while loading. Please reload this page.