mirror of
https://github.com/lightbend/config.git
synced 2025-01-15 23:01:05 +08:00
Avoid PathBuilder for fast-path path parsing
This makes the typical path parse much faster: - avoid Character.isLetter in favor of just ASCII alphanumeric - allow fast path with hyphens and underscores involved - don't use PathBuilder, build a Path directly by traversing the string backward; this avoids some object allocation
This commit is contained in:
parent
c5b2572858
commit
0a7db6a126
@ -1138,26 +1138,51 @@ final class Parser {
|
||||
}
|
||||
}
|
||||
|
||||
// the idea is to see if the string has any chars that might require the
|
||||
// full parser to deal with.
|
||||
private static boolean hasUnsafeChars(String s) {
|
||||
for (int i = 0; i < s.length(); ++i) {
|
||||
// the idea is to see if the string has any chars or features
|
||||
// that might require the full parser to deal with.
|
||||
private static boolean looksUnsafeForFastParser(String s) {
|
||||
boolean lastWasDot = true; // start of path is also a "dot"
|
||||
int len = s.length();
|
||||
if (s.isEmpty())
|
||||
return true;
|
||||
if (s.charAt(0) == '.')
|
||||
return true;
|
||||
if (s.charAt(len - 1) == '.')
|
||||
return true;
|
||||
|
||||
for (int i = 0; i < len; ++i) {
|
||||
char c = s.charAt(i);
|
||||
if (Character.isLetter(c) || c == '.')
|
||||
if ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || c == '_') {
|
||||
lastWasDot = false;
|
||||
continue;
|
||||
else
|
||||
} else if (c == '.') {
|
||||
if (lastWasDot)
|
||||
return true; // ".." means we need to throw an error
|
||||
lastWasDot = true;
|
||||
} else if (c == '-') {
|
||||
if (lastWasDot)
|
||||
return true;
|
||||
continue;
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
if (lastWasDot)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private static void appendPathString(PathBuilder pb, String s) {
|
||||
int splitAt = s.indexOf('.');
|
||||
private static Path fastPathBuild(Path tail, String s, int end) {
|
||||
// lastIndexOf takes last index it should look at, end - 1 not end
|
||||
int splitAt = s.lastIndexOf('.', end - 1);
|
||||
// this works even if splitAt is -1; then we start the substring at 0
|
||||
Path withOneMoreElement = new Path(s.substring(splitAt + 1, end), tail);
|
||||
if (splitAt < 0) {
|
||||
pb.appendKey(s);
|
||||
return withOneMoreElement;
|
||||
} else {
|
||||
pb.appendKey(s.substring(0, splitAt));
|
||||
appendPathString(pb, s.substring(splitAt + 1));
|
||||
return fastPathBuild(withOneMoreElement, s, splitAt);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1165,15 +1190,9 @@ final class Parser {
|
||||
// we just have something like "foo" or "foo.bar"
|
||||
private static Path speculativeFastParsePath(String path) {
|
||||
String s = ConfigImplUtil.unicodeTrim(path);
|
||||
if (s.isEmpty())
|
||||
if (looksUnsafeForFastParser(s))
|
||||
return null;
|
||||
if (hasUnsafeChars(s))
|
||||
return null;
|
||||
if (s.startsWith(".") || s.endsWith(".") || s.contains(".."))
|
||||
return null; // let the full parser throw the error
|
||||
|
||||
PathBuilder pb = new PathBuilder();
|
||||
appendPathString(pb, s);
|
||||
return pb.result();
|
||||
return fastPathBuild(null, s, s.length());
|
||||
}
|
||||
}
|
||||
|
@ -94,6 +94,23 @@ object GetExistingPath extends App {
|
||||
Util.loop(args, task)
|
||||
}
|
||||
|
||||
object GetSeveralExistingPaths extends App {
|
||||
val conf = ConfigFactory.parseString("aaaaa { bbbbb.ccccc.d=42, qqqqq.rrrrr = 43 }, xxxxx.yyyyy.zzzzz = 44 ").resolve()
|
||||
|
||||
def task() {
|
||||
if (conf.getInt("aaaaa.bbbbb.ccccc.d") != 42 ||
|
||||
conf.getInt("aaaaa.qqqqq.rrrrr") != 43 ||
|
||||
conf.getInt("xxxxx.yyyyy.zzzzz") != 44) {
|
||||
throw new Exception("broken get")
|
||||
}
|
||||
}
|
||||
|
||||
val ms = Util.time(task, 5000000)
|
||||
println("GetSeveralExistingPaths: " + ms + "ms")
|
||||
|
||||
Util.loop(args, task)
|
||||
}
|
||||
|
||||
object HasPathOnMissing extends App {
|
||||
val conf = ConfigFactory.parseString("aaaaa.bbbbb.ccccc.d=42,x=10, y=11, z=12").resolve()
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user