diff --git a/doc/images/opensensors.png b/doc/images/opensensors.png index 94bf228a..9f65dff4 100644 Binary files a/doc/images/opensensors.png and b/doc/images/opensensors.png differ diff --git a/modules/reitit-core/java-src/reitit/Trie.java b/modules/reitit-core/java-src/reitit/Trie.java index 54ae9c62..78272b4a 100644 --- a/modules/reitit-core/java-src/reitit/Trie.java +++ b/modules/reitit-core/java-src/reitit/Trie.java @@ -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 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( diff --git a/perf-test/clj/reitit/go_perf_test.clj b/perf-test/clj/reitit/go_perf_test.clj index 1a6342ce..36678094 100644 --- a/perf-test/clj/reitit/go_perf_test.clj +++ b/perf-test/clj/reitit/go_perf_test.clj @@ -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 diff --git a/perf-test/clj/reitit/nodejs_perf_test.clj b/perf-test/clj/reitit/nodejs_perf_test.clj index 27d664ba..7b30f118 100644 --- a/perf-test/clj/reitit/nodejs_perf_test.clj +++ b/perf-test/clj/reitit/nodejs_perf_test.clj @@ -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 diff --git a/perf-test/clj/reitit/opensensors_perf_test.clj b/perf-test/clj/reitit/opensensors_perf_test.clj index 50ecdc47..36e02fe0 100644 --- a/perf-test/clj/reitit/opensensors_perf_test.clj +++ b/perf-test/clj/reitit/opensensors_perf_test.clj @@ -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)