Segment-router to rule 'em all

This commit is contained in:
Tommi Reiman 2017-11-20 08:11:18 +02:00
parent 607e34c671
commit 8019cebdc7
2 changed files with 70 additions and 1 deletions

View file

@ -0,0 +1,50 @@
(ns reitit.segment
(:require [reitit.impl :as impl]))
(defrecord Match [data params])
(defprotocol Segment
(-insert [this ps data])
(-lookup [this ps params]))
(extend-protocol Segment
nil
(-insert [this ps data])
(-lookup [this ps params]))
(defn- segments [^String path]
(mapv
(fn [^String p]
(if (impl/wild-param? p) (-> p (subs 1) keyword) p))
(.split path "/")))
;; TODO: catch-all
(defn- segment
([]
(segment {} #{} nil))
([children wilds data]
(let [children' (impl/fast-map children)]
(reify
Segment
(-insert [_ [p & ps] data]
(if-not p
(segment children wilds data)
(let [wilds (if (keyword? p) (conj wilds p) wilds)
children (update children p #(-insert (or % (segment)) ps data))]
(segment children wilds data))))
(-lookup [_ [p & ps] params]
(if (nil? p)
(assoc data :params params)
(or (-lookup (impl/fast-get children' p) ps params)
(some #(-lookup (impl/fast-get children' %) ps (assoc params % p)) wilds))))))))
(defn create [paths]
(reduce
(fn [segment [p data]]
(let [ps (segments p)]
(-insert segment ps (map->Match {:data data}))))
(segment) paths))
(defn lookup [segment ^String path]
(let [ps (.split path "/")]
(-lookup segment ps {})))

View file

@ -2,6 +2,7 @@
(:require [clojure.test :refer :all]
[io.pedestal.http.route.prefix-tree :as p]
[reitit.trie :as trie]
[reitit.segment :as segment]
[criterium.core :as cc]))
;;
@ -75,6 +76,9 @@
(trie/insert acc p d))
nil routes))
(def reitit-segment
(segment/create routes))
(defn bench! []
;; 2.3ms
@ -99,7 +103,22 @@
;; 0.8ms (fix payloads)
(cc/quick-bench
(dotimes [_ 1000]
(trie/lookup reitit-tree "/v1/orgs/1/topics" {}))))
(trie/lookup reitit-tree "/v1/orgs/1/topics" {})))
;; 0.9ms (initial)
;; 0.5ms (protocols)
;; 1.0ms (with path params)
;; 1.0ms (Match records)
;; 0.63ms (Single sweep path params)
;; 0.51ms (Cleanup)
(cc/quick-bench
(dotimes [_ 1000]
(segment/lookup reitit-segment "/v1/orgs/1/topics"))))
(comment
(bench!))
(comment
(p/lookup pedestal-tree "/v1/orgs/1/topics")
(trie/lookup reitit-tree "/v1/orgs/1/topics" {})
(segment/lookup reitit-segment "/v1/orgs/1/topics"))