Faster params in Trie

This commit is contained in:
Tommi Reiman 2019-04-23 07:50:16 -04:00
parent 68d68402d9
commit 1326d76936
3 changed files with 33 additions and 17 deletions

View file

@ -38,20 +38,35 @@ public class Trie {
return decode(new String(chars, begin, end - begin), hasPercent, hasPlus); return decode(new String(chars, begin, end - begin), hasPercent, hasPlus);
} }
public static class Match { public static final class Match {
public IPersistentMap params; final private Object[] params;
public final Object data; public final Object data;
private int i = 0;
public Match(IPersistentMap params, Object data) { public Match(Integer size, Object data) {
this.params = params; this.params = new Object[size];
this.data = data; 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 @Override
public String toString() { public String toString() {
Map<Object, Object> m = new HashMap<>(); Map<Object, Object> m = new HashMap<>();
m.put(Keyword.intern("data"), data); m.put(Keyword.intern("data"), data);
m.put(Keyword.intern("params"), params); m.put(Keyword.intern("params"), params());
return m.toString(); return m.toString();
} }
} }
@ -116,13 +131,13 @@ public class Trie {
private final Match match; private final Match match;
DataMatcher(IPersistentMap params, Object data) { DataMatcher(IPersistentMap params, Object data) {
this.match = new Match(params, data); this.match = new Match(params.count() * 2, data);
} }
@Override @Override
public Match match(int i, int max, char[] path) { public Match match(int i, int max, char[] path) {
if (i == max) { if (i == max) {
return match; return match.copy();
} }
return null; return null;
} }
@ -175,7 +190,7 @@ public class Trie {
} }
final Match m = child.match(stop, max, path); final Match m = child.match(stop, max, path);
if (m != null) { 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; return m;
} }
@ -204,19 +219,18 @@ public class Trie {
static final class CatchAllMatcher implements Matcher { static final class CatchAllMatcher implements Matcher {
private final Keyword parameter; private final Keyword parameter;
private final IPersistentMap params; private final Match match;
private final Object data;
CatchAllMatcher(Keyword parameter, IPersistentMap params, Object data) { CatchAllMatcher(Keyword parameter, IPersistentMap params, Object data) {
this.match = new Match(params.count() * 2, data);
this.parameter = parameter; this.parameter = parameter;
this.params = params;
this.data = data;
} }
@Override @Override
public Match match(int i, int max, char[] path) { public Match match(int i, int max, char[] path) {
if (i <= max) { 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; return null;
} }
@ -233,7 +247,7 @@ public class Trie {
@Override @Override
public String toString() { public String toString() {
return "[" + parameter + " " + new DataMatcher(null, data) + "]"; return "[" + parameter + " " + new DataMatcher(null, match.data) + "]";
} }
} }

View file

@ -296,8 +296,7 @@
(def app (def app
(ring/ring-handler (ring/ring-handler
(ring/router (ring/router
(reduce (partial add h) [] routes) (reduce (partial add h) [] routes))
{::trie/parameters trie/record-parameters})
(ring/create-default-handler) (ring/create-default-handler)
{:inject-match? false, :inject-router? false})) {:inject-match? false, :inject-router? false}))
@ -319,6 +318,7 @@
;; 140µs (java-segment-router) ;; 140µs (java-segment-router)
;; 60ns (java-segment-router, no injects) ;; 60ns (java-segment-router, no injects)
;; 55ns (trie-router, no injects) ;; 55ns (trie-router, no injects)
;; 54µs (trie-router, quick-pam)
;; 54ns (trie-router, no injects, optimized) ;; 54ns (trie-router, no injects, optimized)
(let [req (map->Req {:request-method :get, :uri "/user/repos"})] (let [req (map->Req {:request-method :get, :uri "/user/repos"})]
(title "static") (title "static")
@ -337,6 +337,7 @@
;; 273ns (trie-router, no injects, direct-data) ;; 273ns (trie-router, no injects, direct-data)
;; 256ns (trie-router, pre-defined parameters) ;; 256ns (trie-router, pre-defined parameters)
;; 237ns (trie-router, single-sweep wild-params) ;; 237ns (trie-router, single-sweep wild-params)
;; 226µs (trie-router, quick-pam)
;; 191ns (trie-router, record parameters) ;; 191ns (trie-router, record parameters)
(let [req (map->Req {:request-method :get, :uri "/repos/julienschmidt/httprouter/stargazers"})] (let [req (map->Req {:request-method :get, :uri "/repos/julienschmidt/httprouter/stargazers"})]
(title "param") (title "param")
@ -354,6 +355,7 @@
;; 63µs (trie-router, no injects, switch-case) - 124µs (clojure) ;; 63µs (trie-router, no injects, switch-case) - 124µs (clojure)
;; 63µs (trie-router, no injects, direct-data) ;; 63µs (trie-router, no injects, direct-data)
;; 54µs (trie-router, non-transient params) ;; 54µs (trie-router, non-transient params)
;; 50µs (trie-router, quick-pam)
;; 49µs (trie-router, pre-defined parameters) ;; 49µs (trie-router, pre-defined parameters)
(let [requests (mapv route->req routes)] (let [requests (mapv route->req routes)]
(title "all") (title "all")

View file

@ -70,7 +70,7 @@
:java-source-paths ["modules/reitit-core/java-src"] :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"] [org.clojure/clojurescript "1.10.520"]
;; modules dependencies ;; modules dependencies