Skip to content

Commit

Permalink
Faster path conflict resolution, O(n2) -> O(n)
Browse files Browse the repository at this point in the history
  • Loading branch information
ikitommi committed Apr 27, 2020
1 parent b128a0f commit 1b0cc0a
Show file tree
Hide file tree
Showing 3 changed files with 22 additions and 18 deletions.
17 changes: 9 additions & 8 deletions modules/reitit-core/src/reitit/impl.cljc
Expand Up @@ -74,14 +74,15 @@
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 {}
Expand Down
21 changes: 11 additions & 10 deletions modules/reitit-core/src/reitit/trie.cljc
Expand Up @@ -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
Expand Down
2 changes: 2 additions & 0 deletions perf-test/clj/reitit/router_creation_perf_test.clj
Expand Up @@ -40,6 +40,7 @@
(suite "non-conflicting")

;; 104ms
;; 11ms (reuse parts in conflict resolution)
(bench! "default" (r/router hundred-routes))

;; 7ms
Expand All @@ -50,6 +51,7 @@

;; 205ms
;; 105ms (cache path-conflicts)
;; 13ms (reuse parts in conflict resolution)
(bench! "default" (r/router routes {:conflicts nil}))))

(comment
Expand Down

0 comments on commit 1b0cc0a

Please sign in to comment.