Start working on cljs trie

This commit is contained in:
Tommi Reiman 2019-02-03 18:09:38 +02:00
parent fbf2786093
commit cecd6cf526
7 changed files with 63 additions and 51 deletions

View file

@ -258,10 +258,6 @@ public class Trie {
return matcher.match(0, path.length(), path.toCharArray(), new Match()); return matcher.match(0, path.length(), path.toCharArray(), new Match());
} }
public static Matcher scanner(List<Matcher> matchers) {
return new LinearMatcher(matchers);
}
public static void main(String[] args) { public static void main(String[] args) {
Matcher matcher = Matcher matcher =
linearMatcher( linearMatcher(

View file

@ -115,7 +115,7 @@
[[] {}] [[] {}]
compiled-routes) compiled-routes)
lookup (impl/fast-map nl) lookup (impl/fast-map nl)
scanner (trie/scanner pl) matcher (trie/linear-matcher pl)
routes (impl/uncompile-routes compiled-routes)] routes (impl/uncompile-routes compiled-routes)]
^{:type ::router} ^{:type ::router}
(reify (reify
@ -131,7 +131,7 @@
(route-names [_] (route-names [_]
names) names)
(match-by-path [_ path] (match-by-path [_ path]
(if-let [match (trie/lookup scanner path)] (if-let [match (trie/lookup matcher path)]
(-> (:data match) (-> (:data match)
(assoc :path-params (:path-params match)) (assoc :path-params (:path-params match))
(assoc :path path)))) (assoc :path path))))

View file

@ -9,13 +9,10 @@
(java.util HashMap Map) (java.util HashMap Map)
(java.net URLEncoder URLDecoder)))) (java.net URLEncoder URLDecoder))))
(defn normalize [s]
(-> s (trie/split-path) (trie/join-path)))
(defrecord Route [path path-parts path-params]) (defrecord Route [path path-parts path-params])
(defn parse [path] (defn parse [path]
(let [path #?(:clj (.intern ^String (normalize path)) :cljs (normalize path)) (let [path #?(:clj (.intern ^String (trie/normalize path)) :cljs (trie/normalize path))
path-parts (trie/split-path path) path-parts (trie/split-path path)
path-params (->> path-parts (remove string?) (map :value) set)] path-params (->> path-parts (remove string?) (map :value) set)]
(map->Route {:path-params path-params (map->Route {:path-params path-params

View file

@ -11,6 +11,9 @@
(defn wild? [x] (instance? Wild x)) (defn wild? [x] (instance? Wild x))
(defn catch-all? [x] (instance? CatchAll x)) (defn catch-all? [x] (instance? CatchAll x))
(defprotocol Matcher
(match [this i max path match]))
;; https://stackoverflow.com/questions/8033655/find-longest-common-prefix ;; https://stackoverflow.com/questions/8033655/find-longest-common-prefix
(defn common-prefix [s1 s2] (defn common-prefix [s1 s2]
(let [max (min (count s1) (count s2))] (let [max (min (count s1) (count s2))]
@ -58,6 +61,9 @@
(instance? CatchAll x) (str "{*" (-> x :value str (subs 1)) "}")))) (instance? CatchAll x) (str "{*" (-> x :value str (subs 1)) "}"))))
"" xs)) "" xs))
(defn normalize [s]
(-> s (split-path) (join-path)))
(defn- -node [m] (defn- -node [m]
(map->Node (merge {:children {}, :wilds {}, :catch-all {}} m))) (map->Node (merge {:children {}, :wilds {}, :catch-all {}} m)))
@ -103,6 +109,21 @@
(update :children dissoc "")) (update :children dissoc ""))
node'))) node')))
(defn data-matcher [data]
#?(:clj (Trie/dataMatcher data)))
(defn static-matcher [path matcher]
#?(:clj (Trie/staticMatcher path matcher)))
(defn wild-matcher [path matcher]
#?(:clj (Trie/wildMatcher path matcher)))
(defn catch-all-matcher [path data]
#?(:clj (Trie/catchAllMatcher path data)))
(defn linear-matcher [matchers]
#?(:clj (Trie/linearMatcher matchers)))
;; ;;
;; public api ;; public api
;; ;;
@ -118,14 +139,14 @@
([node path data] ([node path data]
(-insert (or node (-node {})) (split-path path) data))) (-insert (or node (-node {})) (split-path path) data)))
(defn ^Trie$Matcher compile [{:keys [data children wilds catch-all]}] (defn compile [{:keys [data children wilds catch-all]}]
(let [matchers (cond-> [] (let [matchers (cond-> []
data (conj (Trie/dataMatcher data)) data (conj (data-matcher data))
children (into (for [[p c] children] (Trie/staticMatcher p (compile c)))) children (into (for [[p c] children] (static-matcher p (compile c))))
wilds (into (for [[p c] wilds] (Trie/wildMatcher p (compile c)))) wilds (into (for [[p c] wilds] (wild-matcher p (compile c))))
catch-all (into (for [[p c] catch-all] (Trie/catchAllMatcher p (:data c)))))] catch-all (into (for [[p c] catch-all] (catch-all-matcher p (:data c)))))]
(if (rest matchers) (if (rest matchers)
(Trie/linearMatcher matchers) (linear-matcher matchers)
(first matchers)))) (first matchers))))
(defn pretty [matcher] (defn pretty [matcher]
@ -135,9 +156,6 @@
(if-let [match ^Trie$Match (Trie/lookup matcher ^String path)] (if-let [match ^Trie$Match (Trie/lookup matcher ^String path)]
(->Match (.data match) (.parameters match)))) (->Match (.data match) (.parameters match))))
(defn scanner [compiled-tries]
(Trie/scanner compiled-tries))
;; ;;
;; spike ;; spike
;; ;;

View file

@ -5,7 +5,8 @@
[clojure.spec.alpha :as s] [clojure.spec.alpha :as s]
[clojure.set :as set] [clojure.set :as set]
[clojure.string :as str] [clojure.string :as str]
[reitit.coercion :as coercion])) [reitit.coercion :as coercion]
[reitit.trie :as trie]))
(s/def ::id (s/or :keyword keyword? :set (s/coll-of keyword? :into #{}))) (s/def ::id (s/or :keyword keyword? :set (s/coll-of keyword? :into #{})))
(s/def ::no-doc boolean?) (s/def ::no-doc boolean?)
@ -65,7 +66,7 @@
:spec ::spec}) :spec ::spec})
(defn- swagger-path [path] (defn- swagger-path [path]
(-> path impl/normalize (str/replace #"\{\*" "{"))) (-> path trie/normalize (str/replace #"\{\*" "{")))
(defn create-swagger-handler [] (defn create-swagger-handler []
"Create a ring handler to emit swagger spec. Collects all routes from router which have "Create a ring handler to emit swagger spec. Collects all routes from router which have

View file

@ -2,17 +2,6 @@
(:require [clojure.test :refer [deftest testing is are]] (:require [clojure.test :refer [deftest testing is are]]
[reitit.impl :as impl])) [reitit.impl :as impl]))
(deftest normalize-test
(are [path expected]
(is (= expected (impl/normalize path)))
"/olipa/:kerran/avaruus", "/olipa/{kerran}/avaruus"
"/olipa/{kerran}/avaruus", "/olipa/{kerran}/avaruus"
"/olipa/{a.b/c}/avaruus", "/olipa/{a.b/c}/avaruus"
"/olipa/kerran/*avaruus", "/olipa/kerran/{*avaruus}"
"/olipa/kerran/{*avaruus}", "/olipa/kerran/{*avaruus}"
"/olipa/kerran/{*valvavan.suuri/avaruus}", "/olipa/kerran/{*valvavan.suuri/avaruus}"))
(deftest conflicting-route-test (deftest conflicting-route-test
(are [c? p1 p2] (are [c? p1 p2]
(is (= c? (impl/conflicting-routes? [p1] [p2]))) (is (= c? (impl/conflicting-routes? [p1] [p2])))

View file

@ -1,26 +1,37 @@
(ns reitit.trie-test (ns reitit.trie-test
(:require [clojure.test :refer [deftest testing is are]] (:require [clojure.test :refer [deftest testing is are]]
[reitit.trie :as rt])) [reitit.trie :as trie]))
(deftest normalize-test
(are [path expected]
(is (= expected (trie/normalize path)))
"/olipa/:kerran/avaruus", "/olipa/{kerran}/avaruus"
"/olipa/{kerran}/avaruus", "/olipa/{kerran}/avaruus"
"/olipa/{a.b/c}/avaruus", "/olipa/{a.b/c}/avaruus"
"/olipa/kerran/*avaruus", "/olipa/kerran/{*avaruus}"
"/olipa/kerran/{*avaruus}", "/olipa/kerran/{*avaruus}"
"/olipa/kerran/{*valvavan.suuri/avaruus}", "/olipa/kerran/{*valvavan.suuri/avaruus}"))
(deftest tests (deftest tests
(is (= (rt/->Match {:a 1} {}) (is (= (trie/->Match {:a 1} {})
(-> (rt/insert nil "/foo" {:a 1}) (-> (trie/insert nil "/foo" {:a 1})
(rt/compile) (trie/compile)
(rt/lookup "/foo")))) (trie/lookup "/foo"))))
(is (= (rt/->Match {:a 1} {}) (is (= (trie/->Match {:a 1} {})
(-> (rt/insert nil "/foo" {:a 1}) (-> (trie/insert nil "/foo" {:a 1})
(rt/insert "/foo/*bar" {:b 1}) (trie/insert "/foo/*bar" {:b 1})
(rt/compile) (trie/compile)
(rt/lookup "/foo")))) (trie/lookup "/foo"))))
(is (= (rt/->Match {:b 1} {:bar "bar"}) (is (= (trie/->Match {:b 1} {:bar "bar"})
(-> (rt/insert nil "/foo" {:a 1}) (-> (trie/insert nil "/foo" {:a 1})
(rt/insert "/foo/*bar" {:b 1}) (trie/insert "/foo/*bar" {:b 1})
(rt/compile) (trie/compile)
(rt/lookup "/foo/bar")))) (trie/lookup "/foo/bar"))))
(is (= (rt/->Match {:a 1} {}) (is (= (trie/->Match {:a 1} {})
(-> (rt/insert nil "" {:a 1}) (-> (trie/insert nil "" {:a 1})
(rt/compile) (trie/compile)
(rt/lookup ""))))) (trie/lookup "")))))