char-array is faster, re-run tests

This commit is contained in:
Tommi Reiman 2019-02-02 20:13:45 +02:00
parent 86cfacb03c
commit c87bc099b0
5 changed files with 22 additions and 25 deletions

Binary file not shown.

Before

Width:  |  Height:  |  Size: 36 KiB

After

Width:  |  Height:  |  Size: 31 KiB

View file

@ -13,8 +13,8 @@ import java.util.*;
public class Trie {
private static String decode(String ss, int begin, int end, boolean hasPercent, boolean hasPlus) {
final String s = ss.substring(begin, end);
private static String decode(char[] chars, int begin, int end, boolean hasPercent, boolean hasPlus) {
final String s = new String(chars, begin, end - begin);
try {
if (hasPercent) {
return URLDecoder.decode(hasPlus ? s.replace("+", "%2B") : s, "UTF-8");
@ -24,18 +24,18 @@ public class Trie {
return s;
}
private static String decode(String s, int begin, int end) {
private static String decode(char[] chars, int begin, int end) {
boolean hasPercent = false;
boolean hasPlus = false;
for (int j = begin; j < end; j++) {
final char c = s.charAt(j);
final char c = chars[j];
if (c == '%') {
hasPercent = true;
} else if (c == '+') {
hasPlus = true;
}
}
return decode(s, begin, end, hasPercent, hasPlus);
return decode(chars, begin, end, hasPercent, hasPlus);
}
public static class Match {
@ -56,7 +56,7 @@ public class Trie {
}
public interface Matcher {
Match match(int i, int max, String path, Match match);
Match match(int i, int max, char[] path, Match match);
int depth();
}
@ -77,12 +77,12 @@ public class Trie {
}
@Override
public Match match(int i, int max, String path, Match match) {
public Match match(int i, int max, char[] path, Match match) {
if (max < i + size) {
return null;
}
for (int j = 0; j < size; j++) {
if (path.charAt(j + i) != this.path[j]) {
if (path[j + i] != this.path[j]) {
return null;
}
}
@ -112,7 +112,7 @@ public class Trie {
}
@Override
public Match match(int i, int max, String path, Match match) {
public Match match(int i, int max, char[] path, Match match) {
if (i == max) {
match.data = data;
return match;
@ -145,12 +145,12 @@ public class Trie {
}
@Override
public Match match(int i, int max, String path, Match match) {
if (i < max && path.charAt(i) != '/') {
public Match match(int i, int max, char[] path, Match match) {
if (i < max && path[i] != '/') {
boolean hasPercent = false;
boolean hasPlus = false;
for (int j = i; j < max; j++) {
final char c = path.charAt(j);
final char c = path[j];
if (c == '/') {
final Match m = child.match(j, max, path, match);
if (m != null) {
@ -197,7 +197,7 @@ public class Trie {
}
@Override
public Match match(int i, int max, String path, Match match) {
public Match match(int i, int max, char[] path, Match match) {
if (i < max) {
match.params.assoc(parameter, decode(path, i, max));
match.data = data;
@ -233,7 +233,7 @@ public class Trie {
}
@Override
public Match match(int i, int max, String path, Match match) {
public Match match(int i, int max, char[] path, Match match) {
for (int j = 0; j < size; j++) {
final Match m = childs[j].match(i, max, path, match);
if (m != null) {
@ -255,7 +255,7 @@ public class Trie {
}
public static Object lookup(Matcher matcher, String path) {
return matcher.match(0, path.length(), path, new Match());
return matcher.match(0, path.length(), path.toCharArray(), new Match());
}
public static Matcher scanner(List<Matcher> matchers) {
@ -263,13 +263,6 @@ public class Trie {
}
public static void main(String[] args) {
//Matcher matcher = new StaticMatcher("/kikka", new StaticMatcher("/kukka", new DataMatcher(1)));
// Matcher matcher =
// staticMatcher("/kikka/",
// wildMatcher(Keyword.intern("kukka"),
// staticMatcher("/kikka",
// dataMatcher(1))));
Matcher matcher =
linearMatcher(
Arrays.asList(

View file

@ -20,8 +20,7 @@
;;
(defn h [path]
(fn [_]
{:status 200, :body path}))
(constantly {:status 200, :body path}))
(defn add [handler routes route]
(let [method (-> route keys first str/lower-case keyword)
@ -318,6 +317,7 @@
;; 140µs (java-segment-router)
;; 60ns (java-segment-router, no injects)
;; 55ns (trie-router, no injects)
;; 54µs (trie-router, no injects, optimized)
(let [req (map->Req {:request-method :get, :uri "/user/repos"})]
(title "static")
(assert (= {:status 200, :body "/user/repos"} (app req)))
@ -330,6 +330,7 @@
;; 490ns (java-segment-router, no injects)
;; 440ns (java-segment-router, no injects, single-wild-optimization)
;; 305ns (trie-router, no injects)
;; 281µs (trie-router, no injects, optimized)
(let [req (map->Req {:request-method :get, :uri "/repos/julienschmidt/httprouter/stargazers"})]
(title "param")
(assert (= {:status 200, :body "/repos/:owner/:repo/stargazers"} (app req)))
@ -342,6 +343,7 @@
;; 100µs (java-segment-router, no injects)
;; 90µs (java-segment-router, no injects, single-wild-optimization)
;; 66µs (trie-router, no injects)
;; 64µs (trie-router, no injects, optimized)
(let [requests (mapv route->req routes)]
(title "all")
(cc/quick-bench

View file

@ -69,7 +69,7 @@
;; 25310 / 25126
"regex"
;; 112017 / 113811
;; 112719 / 113959
(title "reitit")
;; wrk -d ${DURATION:="30s"} http://127.0.0.1:2048/product/foo
;; wrk -d ${DURATION:="30s"} http://127.0.0.1:2048/twenty/bar

View file

@ -584,12 +584,14 @@
;; 474ns (java-segment-router)
;; 373ns (trie)
;; 323ns (trie, prioritized)
;; 289ns (trie, prioritized, zero-copy)
(b! "reitit-ring" reitit-ring-f)
;; 385ns (java-segment-router, no injects)
;; 271ms (trie)
;; 240ns (trie, prioritized)
(b! "reitit-ring-fast" reitit-ring-fast-f)
;; 240ns (trie, prioritized, zero-copy)
;; 2553ns (linear-router)
;; 630ns (segment-router-backed)