mirror of
https://github.com/metosin/reitit.git
synced 2025-12-30 21:28:25 +00:00
Merge pull request #389 from metosin/QuickRouterCreation
Quick router creation
This commit is contained in:
commit
e5c4ae533f
4 changed files with 86 additions and 28 deletions
|
|
@ -301,7 +301,7 @@
|
|||
([compiled-routes]
|
||||
(quarantine-router compiled-routes {}))
|
||||
([compiled-routes opts]
|
||||
(let [conflicting-paths (-> compiled-routes (impl/path-conflicting-routes opts) impl/conflicting-paths)
|
||||
(let [conflicting-paths (impl/conflicting-paths (or (::path-conflicting opts) (impl/path-conflicting-routes compiled-routes opts)))
|
||||
conflicting? #(contains? conflicting-paths (first %))
|
||||
{conflicting true, non-conflicting false} (group-by conflicting? compiled-routes)
|
||||
linear-router (linear-router conflicting opts)
|
||||
|
|
@ -364,10 +364,10 @@
|
|||
([raw-routes]
|
||||
(router raw-routes {}))
|
||||
([raw-routes opts]
|
||||
(let [{:keys [router] :as opts} (merge (default-router-options) opts)]
|
||||
(let [{:keys [router conflicts] :as opts} (merge (default-router-options) opts)]
|
||||
(try
|
||||
(let [routes (impl/resolve-routes raw-routes opts)
|
||||
path-conflicting (impl/path-conflicting-routes routes opts)
|
||||
path-conflicting (if-not (and router (not conflicts)) (impl/path-conflicting-routes routes opts))
|
||||
name-conflicting (impl/name-conflicting-routes routes)
|
||||
compiled-routes (impl/compile-routes routes opts)
|
||||
wilds? (boolean (some (impl/->wild-route? opts) compiled-routes))
|
||||
|
|
@ -380,10 +380,8 @@
|
|||
all-wilds? trie-router
|
||||
:else mixed-router)]
|
||||
|
||||
(when-let [conflicts (:conflicts opts)]
|
||||
(when-let [conflict-report (impl/unresolved-conflicts
|
||||
path-conflicting)]
|
||||
(conflicts conflict-report)))
|
||||
(when-let [conflict-report (and conflicts (impl/unresolved-conflicts path-conflicting))]
|
||||
(conflicts conflict-report))
|
||||
|
||||
(when name-conflicting
|
||||
(exception/fail! :name-conflicts name-conflicting))
|
||||
|
|
@ -391,7 +389,7 @@
|
|||
(when-let [validate (:validate opts)]
|
||||
(validate compiled-routes opts))
|
||||
|
||||
(router compiled-routes opts))
|
||||
(router compiled-routes (assoc opts ::path-conflicting path-conflicting)))
|
||||
|
||||
(catch #?(:clj Exception, :cljs js/Error) e
|
||||
(throw ((get opts :exception identity) e)))))))
|
||||
|
|
|
|||
|
|
@ -71,17 +71,18 @@
|
|||
|
||||
(defn resolve-routes [raw-routes {:keys [coerce] :as opts}]
|
||||
(cond->> (->> (walk raw-routes opts) (map-data merge-data))
|
||||
coerce (into [] (keep #(coerce % opts)))))
|
||||
coerce (into [] (keep #(coerce % opts)))))
|
||||
|
||||
(defn path-conflicting-routes [routes opts]
|
||||
(-> (into {}
|
||||
(comp (map-indexed (fn [index route]
|
||||
[route (into #{}
|
||||
(filter #(trie/conflicting-paths? (first route) (first %) opts))
|
||||
(subvec routes (inc index)))]))
|
||||
(filter (comp seq second)))
|
||||
routes)
|
||||
(not-empty)))
|
||||
(let [parts-and-routes (mapv (fn [[s :as r]] [(trie/split-path s opts) r]) routes)]
|
||||
(-> (into {} (comp (map-indexed (fn [index [p r]]
|
||||
[r (reduce
|
||||
(fn [acc [p' r']]
|
||||
(if (trie/conflicting-parts? p p')
|
||||
(conj acc r') acc))
|
||||
#{} (subvec parts-and-routes (inc index)))]))
|
||||
(filter (comp seq second))) parts-and-routes)
|
||||
(not-empty))))
|
||||
|
||||
(defn unresolved-conflicts [path-conflicting]
|
||||
(-> (into {}
|
||||
|
|
@ -179,7 +180,7 @@
|
|||
(URLDecoder/decode
|
||||
(if (.contains ^String s "+")
|
||||
(.replace ^String s "+" "%2B")
|
||||
s)
|
||||
^String s)
|
||||
"UTF-8"))
|
||||
:cljs (js/decodeURIComponent s))))
|
||||
|
||||
|
|
|
|||
|
|
@ -132,17 +132,18 @@
|
|||
(concat [(subs x i)] xs)
|
||||
xs)))
|
||||
|
||||
(defn conflicting-parts? [parts1 parts2]
|
||||
(let [[[s1 & ss1] [s2 & ss2]] (-slice-start parts1 parts2)]
|
||||
(cond
|
||||
(= s1 s2 nil) true
|
||||
(or (nil? s1) (nil? s2)) false
|
||||
(or (catch-all? s1) (catch-all? s2)) true
|
||||
(or (wild? s1) (wild? s2)) (recur (-slice-end s1 ss1) (-slice-end s2 ss2))
|
||||
(not= s1 s2) false
|
||||
:else (recur ss1 ss2))))
|
||||
|
||||
(defn conflicting-paths? [path1 path2 opts]
|
||||
(loop [parts1 (split-path path1 opts)
|
||||
parts2 (split-path path2 opts)]
|
||||
(let [[[s1 & ss1] [s2 & ss2]] (-slice-start parts1 parts2)]
|
||||
(cond
|
||||
(= s1 s2 nil) true
|
||||
(or (nil? s1) (nil? s2)) false
|
||||
(or (catch-all? s1) (catch-all? s2)) true
|
||||
(or (wild? s1) (wild? s2)) (recur (-slice-end s1 ss1) (-slice-end s2 ss2))
|
||||
(not= s1 s2) false
|
||||
:else (recur ss1 ss2)))))
|
||||
(conflicting-parts? (split-path path1 opts) (split-path path2 opts)))
|
||||
|
||||
;;
|
||||
;; Creating Tries
|
||||
|
|
|
|||
58
perf-test/clj/reitit/router_creation_perf_test.clj
Normal file
58
perf-test/clj/reitit/router_creation_perf_test.clj
Normal file
|
|
@ -0,0 +1,58 @@
|
|||
(ns reitit.router-creation-perf-test
|
||||
(:require [reitit.perf-utils :refer [bench! suite]]
|
||||
[reitit.core :as r]
|
||||
[clojure.string :as str])
|
||||
(:import (java.util Random)))
|
||||
|
||||
;;
|
||||
;; start repl with `lein perf repl`
|
||||
;; perf measured with the following setup:
|
||||
;;
|
||||
;; Model Name: MacBook Pro
|
||||
;; Model Identifier: MacBookPro113
|
||||
;; Processor Name: Intel Core i7
|
||||
;; Processor Speed: 2,5 GHz
|
||||
;; Number of Processors: 1
|
||||
;; Total Number of Cores: 4
|
||||
;; L2 Cache (per Core): 256 KB
|
||||
;; L3 Cache: 6 MB
|
||||
;; Memory: 16 GB
|
||||
;;
|
||||
|
||||
(defn random [^long seed]
|
||||
(Random. seed))
|
||||
|
||||
(defn rand-str [^Random rnd len]
|
||||
(apply str (take len (repeatedly #(char (+ (.nextInt rnd 26) 97))))))
|
||||
|
||||
(defn route [rnd]
|
||||
(str/join "/" (repeatedly (+ 2 (.nextInt rnd 8)) (fn [] (rand-str rnd (.nextInt rnd 10))))))
|
||||
|
||||
(def hundred-routes
|
||||
(let [rnd (random 1)]
|
||||
(mapv (fn [n] [(route rnd) (keyword (str "route" n))]) (range 100))))
|
||||
|
||||
(conj hundred-routes (last hundred-routes))
|
||||
|
||||
|
||||
(defn bench-routers []
|
||||
|
||||
(suite "non-conflicting")
|
||||
|
||||
;; 104ms
|
||||
;; 11ms (reuse parts in conflict resolution)
|
||||
(bench! "default" (r/router hundred-routes))
|
||||
|
||||
;; 7ms
|
||||
(bench! "linear" (r/router hundred-routes {:router r/linear-router, :conflicts nil}))
|
||||
|
||||
(suite "conflicting")
|
||||
(let [routes (conj hundred-routes [(first (last hundred-routes)) ::route])]
|
||||
|
||||
;; 205ms
|
||||
;; 105ms (cache path-conflicts)
|
||||
;; 13ms (reuse parts in conflict resolution)
|
||||
(bench! "default" (r/router routes {:conflicts nil}))))
|
||||
|
||||
(comment
|
||||
(bench-routers))
|
||||
Loading…
Reference in a new issue