Faster path conflict resolution, O(n2) -> O(n)

This commit is contained in:
Tommi Reiman 2020-04-27 08:38:27 +03:00
parent b128a0f3db
commit 1b0cc0a100
3 changed files with 22 additions and 18 deletions

View file

@ -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 {}

View file

@ -132,9 +132,7 @@
(concat [(subs x i)] xs)
xs)))
(defn conflicting-paths? [path1 path2 opts]
(loop [parts1 (split-path path1 opts)
parts2 (split-path path2 opts)]
(defn conflicting-parts? [parts1 parts2]
(let [[[s1 & ss1] [s2 & ss2]] (-slice-start parts1 parts2)]
(cond
(= s1 s2 nil) true
@ -142,7 +140,10 @@
(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)))))
:else (recur ss1 ss2))))
(defn conflicting-paths? [path1 path2 opts]
(conflicting-parts? (split-path path1 opts) (split-path path2 opts)))
;;
;; Creating Tries

View file

@ -40,6 +40,7 @@
(suite "non-conflicting")
;; 104ms
;; 11ms (reuse parts in conflict resolution)
(bench! "default" (r/router hundred-routes))
;; 7ms
@ -50,6 +51,7 @@
;; 205ms
;; 105ms (cache path-conflicts)
;; 13ms (reuse parts in conflict resolution)
(bench! "default" (r/router routes {:conflicts nil}))))
(comment