diff --git a/modules/reitit-core/java-src/reitit/Trie.java b/modules/reitit-core/java-src/reitit/Trie.java index b7af4c1f..ff5eb5f5 100644 --- a/modules/reitit-core/java-src/reitit/Trie.java +++ b/modules/reitit-core/java-src/reitit/Trie.java @@ -38,20 +38,35 @@ public class Trie { return decode(new String(chars, begin, end - begin), hasPercent, hasPlus); } - public static class Match { - public IPersistentMap params; + public static final class Match { + final private Object[] params; public final Object data; + private int i = 0; - public Match(IPersistentMap params, Object data) { - this.params = params; + public Match(Integer size, Object data) { + this.params = new Object[size]; this.data = data; } + public void assoc(Keyword key, Object value) { + params[i] = key; + params[i + 1] = value; + i += 2; + } + + public IPersistentMap params() { + return new PersistentArrayMap(params); + } + + Match copy() { + return new Match(params.length, data); + } + @Override public String toString() { Map m = new HashMap<>(); m.put(Keyword.intern("data"), data); - m.put(Keyword.intern("params"), params); + m.put(Keyword.intern("params"), params()); return m.toString(); } } @@ -116,13 +131,13 @@ public class Trie { private final Match match; DataMatcher(IPersistentMap params, Object data) { - this.match = new Match(params, data); + this.match = new Match(params.count() * 2, data); } @Override public Match match(int i, int max, char[] path) { if (i == max) { - return match; + return match.copy(); } return null; } @@ -175,7 +190,7 @@ public class Trie { } final Match m = child.match(stop, max, path); if (m != null) { - m.params = m.params.assoc(key, decode(new String(path, i, stop - i), hasPercent, hasPlus)); + m.assoc(key, decode(new String(path, i, stop - i), hasPercent, hasPlus)); } return m; } @@ -204,19 +219,18 @@ public class Trie { static final class CatchAllMatcher implements Matcher { private final Keyword parameter; - private final IPersistentMap params; - private final Object data; + private final Match match; CatchAllMatcher(Keyword parameter, IPersistentMap params, Object data) { + this.match = new Match(params.count() * 2, data); this.parameter = parameter; - this.params = params; - this.data = data; } @Override public Match match(int i, int max, char[] path) { if (i <= max) { - return new Match(params.assoc(parameter, decode(path, i, max)), data); + match.copy().assoc(parameter, decode(path, i, max)); + return match; } return null; } @@ -233,7 +247,7 @@ public class Trie { @Override public String toString() { - return "[" + parameter + " " + new DataMatcher(null, data) + "]"; + return "[" + parameter + " " + new DataMatcher(null, match.data) + "]"; } } diff --git a/perf-test/clj/reitit/go_perf_test.clj b/perf-test/clj/reitit/go_perf_test.clj index 4e432c2e..ba03b753 100644 --- a/perf-test/clj/reitit/go_perf_test.clj +++ b/perf-test/clj/reitit/go_perf_test.clj @@ -296,8 +296,7 @@ (def app (ring/ring-handler (ring/router - (reduce (partial add h) [] routes) - {::trie/parameters trie/record-parameters}) + (reduce (partial add h) [] routes)) (ring/create-default-handler) {:inject-match? false, :inject-router? false})) @@ -319,6 +318,7 @@ ;; 140µs (java-segment-router) ;; 60ns (java-segment-router, no injects) ;; 55ns (trie-router, no injects) + ;; 54µs (trie-router, quick-pam) ;; 54ns (trie-router, no injects, optimized) (let [req (map->Req {:request-method :get, :uri "/user/repos"})] (title "static") @@ -337,6 +337,7 @@ ;; 273ns (trie-router, no injects, direct-data) ;; 256ns (trie-router, pre-defined parameters) ;; 237ns (trie-router, single-sweep wild-params) + ;; 226µs (trie-router, quick-pam) ;; 191ns (trie-router, record parameters) (let [req (map->Req {:request-method :get, :uri "/repos/julienschmidt/httprouter/stargazers"})] (title "param") @@ -354,6 +355,7 @@ ;; 63µs (trie-router, no injects, switch-case) - 124µs (clojure) ;; 63µs (trie-router, no injects, direct-data) ;; 54µs (trie-router, non-transient params) + ;; 50µs (trie-router, quick-pam) ;; 49µs (trie-router, pre-defined parameters) (let [requests (mapv route->req routes)] (title "all") diff --git a/project.clj b/project.clj index 5db61e4e..8b76504a 100644 --- a/project.clj +++ b/project.clj @@ -70,7 +70,7 @@ :java-source-paths ["modules/reitit-core/java-src"] - :dependencies [[org.clojure/clojure "1.10.0"] + :dependencies [[org.clojure/clojure "1.10.1-beta2"] [org.clojure/clojurescript "1.10.520"] ;; modules dependencies