20% faster wildcard parameters with records

This commit is contained in:
Tommi Reiman 2019-03-07 08:20:41 +02:00
parent 55a5133e85
commit e41a50cb80
5 changed files with 33 additions and 6 deletions

View file

@ -80,6 +80,7 @@
| key | description |
| -----------------------------|-------------|
| `:reitit.trie/trie-compiler` | Optional trie-compiler.
| `:reitit.trie/parameters` | Optional function to transform path-parameters at creation time (default `identity`)."
([compiled-routes]
(linear-router compiled-routes {}))
([compiled-routes opts]
@ -91,7 +92,7 @@
f #(if-let [path (impl/path-for route %)]
(->Match p data result (impl/url-decode-coll %) path)
(->PartialMatch p data result (impl/url-decode-coll %) path-params))]
[(conj pl (-> (trie/insert nil p (->Match p data result nil nil)) (trie/compile)))
[(conj pl (-> (trie/insert nil p (->Match p data result nil nil) opts) (trie/compile)))
(if name (assoc nl name f) nl)]))
[[] {}]
compiled-routes)
@ -175,6 +176,7 @@
| key | description |
| -----------------------------|-------------|
| `:reitit.trie/trie-compiler` | Optional trie-compiler.
| `:reitit.trie/parameters` | Optional function to transform path-parameters at creation time (default `identity`)."
([compiled-routes]
(trie-router compiled-routes {}))
([compiled-routes opts]
@ -186,7 +188,7 @@
f #(if-let [path (impl/path-for route %)]
(->Match p data result (impl/url-decode-coll %) path)
(->PartialMatch p data result (impl/url-decode-coll %) path-params))]
[(trie/insert pl p (->Match p data result nil nil))
[(trie/insert pl p (->Match p data result nil nil) opts)
(if name (assoc nl name f) nl)]))
[nil {}]
compiled-routes)

View file

@ -288,6 +288,18 @@
;; Managing Tries
;;
#?(:clj
(def record-parameters
"Memoized function to transform parameters into runtime generated Record."
(memoize
(fn [params]
(let [fields (keys params)]
(if (some qualified-keyword? fields)
params
(let [name (gensym "PathParams")
ctor (symbol (str "map->" name))]
(eval `(do (defrecord ~name ~(mapv symbol fields)) (~ctor {}))))))))))
(defn insert
"Returns a trie with routes added to it."
([routes]
@ -298,8 +310,10 @@
(insert acc p d))
node routes))
([node path data]
(insert node path data nil))
([node path data {::keys [parameters] :or {parameters identity}}]
(let [parts (split-path path)
params (zipmap (->> parts (remove string?) (map :value)) (repeat nil))]
params (parameters (zipmap (->> parts (remove string?) (map :value)) (repeat nil)))]
(-insert (or node (-node {})) (split-path path) path params data))))
(defn compiler

View file

@ -2,6 +2,7 @@
(:require [criterium.core :as cc]
[reitit.perf-utils :refer :all]
[reitit.ring :as ring]
[reitit.trie :as trie]
[clojure.string :as str]))
;;
@ -295,7 +296,8 @@
(def app
(ring/ring-handler
(ring/router
(reduce (partial add h) [] routes))
(reduce (partial add h) [] routes)
{::trie/parameters trie/record-parameters})
(ring/create-default-handler)
{:inject-match? false, :inject-router? false}))
@ -335,6 +337,7 @@
;; 273ns (trie-router, no injects, direct-data)
;; 256ns (trie-router, pre-defined parameters)
;; 237ns (trie-router, single-sweep wild-params)
;; 191ns (trie-router, record parameters)
(let [req (map->Req {:request-method :get, :uri "/repos/julienschmidt/httprouter/stargazers"})]
(title "param")
(assert (= {:status 200, :body "/repos/:owner/:repo/stargazers"} (app req)))

View file

@ -74,7 +74,7 @@
(trie/compile
(reduce
(fn [acc [p d]]
(trie/insert acc p d))
(trie/insert acc p d {::trie/parameters trie/record-parameters}))
nil routes))))
(defn bench! []
@ -117,6 +117,7 @@
;; 0.300µs (iterate arrays)
;; 0.280µs (list-params)
;; 0.096µs (trie)
;; 0.083µs (trie, record-params, faster decode)
(cc/with-progress-reporting
(cc/bench
(trie-matcher "/v1/orgs/1/topics"))))

View file

@ -34,4 +34,11 @@
(is (= (trie/->Match {} {:a 1})
((-> (trie/insert nil "" {:a 1})
(trie/compile)
(trie/path-matcher)) ""))))
(trie/path-matcher)) "")))
#?(:clj
(let [match ((-> (trie/insert nil "/:a" {:a 1} {::trie/parameters trie/record-parameters})
(trie/compile)
(trie/path-matcher)) "/a")]
(is (record? (:params match)))
(is (= (trie/->Match {:a "a"} {:a 1}) (update match :params (partial into {})))))))