mirror of
https://github.com/metosin/reitit.git
synced 2025-12-17 16:31:11 +00:00
Trie -> SegmentTrie
This commit is contained in:
parent
54aded4442
commit
93bcc5dad8
6 changed files with 51 additions and 52 deletions
|
|
@ -6,7 +6,7 @@ import java.io.UnsupportedEncodingException;
|
|||
import java.net.URLEncoder;
|
||||
import java.util.*;
|
||||
|
||||
public class Trie {
|
||||
public class SegmentTrie {
|
||||
|
||||
public static ArrayList<String> split(final String path) {
|
||||
final ArrayList<String> segments = new ArrayList<>(4);
|
||||
|
|
@ -50,35 +50,35 @@ public class Trie {
|
|||
}
|
||||
}
|
||||
|
||||
private Map<String, Trie> childs = new HashMap<>();
|
||||
private Map<Keyword, Trie> wilds = new HashMap<>();
|
||||
private Map<Keyword, Trie> catchAll = new HashMap<>();
|
||||
private Map<String, SegmentTrie> childs = new HashMap<>();
|
||||
private Map<Keyword, SegmentTrie> wilds = new HashMap<>();
|
||||
private Map<Keyword, SegmentTrie> catchAll = new HashMap<>();
|
||||
private Object data;
|
||||
|
||||
public Trie add(String path, Object data) {
|
||||
public SegmentTrie add(String path, Object data) {
|
||||
List<String> paths = split(path);
|
||||
Trie pointer = this;
|
||||
SegmentTrie pointer = this;
|
||||
for (String p : paths) {
|
||||
if (p.startsWith(":")) {
|
||||
Keyword k = Keyword.intern(p.substring(1));
|
||||
Trie s = pointer.wilds.get(k);
|
||||
SegmentTrie s = pointer.wilds.get(k);
|
||||
if (s == null) {
|
||||
s = new Trie();
|
||||
s = new SegmentTrie();
|
||||
pointer.wilds.put(k, s);
|
||||
}
|
||||
pointer = s;
|
||||
} else if (p.startsWith("*")) {
|
||||
Keyword k = Keyword.intern(p.substring(1));
|
||||
Trie s = pointer.catchAll.get(k);
|
||||
SegmentTrie s = pointer.catchAll.get(k);
|
||||
if (s == null) {
|
||||
s = new Trie();
|
||||
s = new SegmentTrie();
|
||||
pointer.catchAll.put(k, s);
|
||||
}
|
||||
break;
|
||||
} else {
|
||||
Trie s = pointer.childs.get(p);
|
||||
SegmentTrie s = pointer.childs.get(p);
|
||||
if (s == null) {
|
||||
s = new Trie();
|
||||
s = new SegmentTrie();
|
||||
pointer.childs.put(p, s);
|
||||
}
|
||||
pointer = s;
|
||||
|
|
@ -93,7 +93,7 @@ public class Trie {
|
|||
return new StaticMatcher(childs.keySet().iterator().next(), childs.values().iterator().next().matcher());
|
||||
} else {
|
||||
Map<String, Matcher> m = new HashMap<>();
|
||||
for (Map.Entry<String, Trie> e : childs.entrySet()) {
|
||||
for (Map.Entry<String, SegmentTrie> e : childs.entrySet()) {
|
||||
m.put(e.getKey(), e.getValue().matcher());
|
||||
}
|
||||
return new StaticMapMatcher(m);
|
||||
|
|
@ -112,7 +112,7 @@ public class Trie {
|
|||
if (!childs.isEmpty()) {
|
||||
matchers.add(staticMatcher());
|
||||
}
|
||||
for (Map.Entry<Keyword, Trie> e : wilds.entrySet()) {
|
||||
for (Map.Entry<Keyword, SegmentTrie> e : wilds.entrySet()) {
|
||||
matchers.add(new WildMatcher(e.getKey(), e.getValue().matcher()));
|
||||
}
|
||||
m = new LinearMatcher(matchers);
|
||||
|
|
@ -301,7 +301,7 @@ public class Trie {
|
|||
|
||||
public static void main(String[] args) {
|
||||
|
||||
Trie trie = new Trie();
|
||||
SegmentTrie trie = new SegmentTrie();
|
||||
//trie.add("/kikka/:id/permissions", 1);
|
||||
trie.add("/kikka/:id", 2);
|
||||
trie.add("/kakka/ping", 3);
|
||||
|
|
@ -311,7 +311,7 @@ public class Trie {
|
|||
System.out.println(lookup(m, "/kikka/1"));
|
||||
|
||||
/*
|
||||
Trie trie = new Trie();
|
||||
SegmentTrie trie = new SegmentTrie();
|
||||
trie.add("/user/:id/profile/:type", 1);
|
||||
trie.add("/user/:id/permissions", 2);
|
||||
trie.add("/company/:cid/dept/:did", 3);
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@
|
|||
(:import (java.util.regex Pattern)
|
||||
(java.util HashMap Map)
|
||||
(java.net URLEncoder URLDecoder)
|
||||
(reitit Trie))))
|
||||
(reitit SegmentTrie))))
|
||||
|
||||
(defn maybe-map-values
|
||||
"Applies a function to every value of a map, updates the value if not nil.
|
||||
|
|
@ -21,7 +21,7 @@
|
|||
coll))
|
||||
|
||||
(defn segments [path]
|
||||
#?(:clj (Trie/split ^String path)
|
||||
#?(:clj (SegmentTrie/split ^String path)
|
||||
:cljs (.split path #"/" 666)))
|
||||
|
||||
;;
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
(:refer-clojure :exclude [-lookup compile])
|
||||
(:require [reitit.impl :as impl]
|
||||
[clojure.string :as str])
|
||||
#?(:clj (:import (reitit Trie Trie$Match))))
|
||||
#?(:clj (:import (reitit SegmentTrie Trie$Match))))
|
||||
|
||||
(defrecord Match [data path-params])
|
||||
|
||||
|
|
@ -50,13 +50,13 @@
|
|||
|
||||
(defn insert [root path data]
|
||||
#?(:cljs (-insert (or root (segment)) (impl/segments path) (map->Match {:data data}))
|
||||
:clj (.add (or ^Trie root ^Trie (Trie.)) ^String path data)))
|
||||
:clj (.add (or ^SegmentTrie root ^SegmentTrie (SegmentTrie.)) ^String path data)))
|
||||
|
||||
(defn compile [segment]
|
||||
#?(:cljs segment
|
||||
:clj (.matcher ^Trie segment)))
|
||||
:clj (.matcher ^SegmentTrie segment)))
|
||||
|
||||
(defn lookup [segment path]
|
||||
#?(:cljs (-lookup segment (impl/segments path) {})
|
||||
:clj (if-let [match ^Trie$Match (Trie/lookup segment path)]
|
||||
:clj (if-let [match ^Trie$Match (SegmentTrie/lookup segment path)]
|
||||
(->Match (.data match) (clojure.lang.PersistentHashMap/create (.params match))))))
|
||||
|
|
|
|||
|
|
@ -7,7 +7,8 @@
|
|||
[reitit.impl :as impl]
|
||||
[reitit.ring :as ring]
|
||||
[reitit.core :as r])
|
||||
(:import (reitit Trie Trie$Matcher)))
|
||||
(:import (reitit SegmentTrie Trie$Matcher)
|
||||
(calfpath Util)))
|
||||
|
||||
;;
|
||||
;; start repl with `lein perf repl`
|
||||
|
|
@ -109,20 +110,20 @@
|
|||
(impl/segments "/user/1234/profile/compact")))
|
||||
|
||||
(comment
|
||||
(Trie/split "/user/1234/profile/compact")
|
||||
(SegmentTrie/split "/user/1234/profile/compact")
|
||||
;; 91ns
|
||||
(cc/quick-bench
|
||||
(Trie/split "/user/1234/profile/compact")))
|
||||
(SegmentTrie/split "/user/1234/profile/compact")))
|
||||
|
||||
(comment
|
||||
(let [router (r/router ["/user/:id/profile/:type"])]
|
||||
(cc/quick-bench
|
||||
(r/match-by-path router "/user/1234/profile/compact"))))
|
||||
|
||||
(let [lookup ^Trie$Matcher (Trie/sample)]
|
||||
(Trie/lookup lookup "/user/1234/profile/compact")
|
||||
(let [lookup ^Trie$Matcher (SegmentTrie/sample)]
|
||||
(SegmentTrie/lookup lookup "/user/1234/profile/compact")
|
||||
#_(cc/quick-bench
|
||||
(Trie/lookup lookup "/user/1234/profile/compact")))
|
||||
(SegmentTrie/lookup lookup "/user/1234/profile/compact")))
|
||||
|
||||
(let [router (r/router [["/user/:id" ::1]
|
||||
["/user/:id/permissions" ::2]
|
||||
|
|
@ -144,50 +145,50 @@
|
|||
(read-string
|
||||
(str
|
||||
(.matcher
|
||||
(doto (Trie.)
|
||||
(doto (SegmentTrie.)
|
||||
(.add "/user" 1)
|
||||
#_(.add "/user/id/permissions" 2)
|
||||
(.add "/user/id/permissions2" 3)))))
|
||||
|
||||
(Trie/lookup
|
||||
(SegmentTrie/lookup
|
||||
(.matcher
|
||||
(doto (Trie.)
|
||||
(doto (SegmentTrie.)
|
||||
(.add "/user/1" 1)
|
||||
(.add "/user/1/permissions" 2)))
|
||||
"/user/1")
|
||||
|
||||
(.matcher
|
||||
(doto (Trie.)
|
||||
(doto (SegmentTrie.)
|
||||
(.add "/user/1" 1)
|
||||
(.add "/user/1/permissions" 2)))
|
||||
|
||||
;; 137ns
|
||||
(let [m (.matcher
|
||||
(doto (Trie.)
|
||||
(doto (SegmentTrie.)
|
||||
(.add "/user/:id/profile/:type" 1)))]
|
||||
#_(cc/quick-bench
|
||||
(Trie/lookup m "/user/1234/profile/compact"))
|
||||
(Trie/lookup m "/user/1234/profile/compact"))
|
||||
(SegmentTrie/lookup m "/user/1234/profile/compact"))
|
||||
(SegmentTrie/lookup m "/user/1234/profile/compact"))
|
||||
|
||||
(comment
|
||||
|
||||
(let [matcher ^Trie$Matcher (Trie/sample)]
|
||||
(Trie/lookup matcher "/user/1234/profile/compact")
|
||||
(let [matcher ^Trie$Matcher (SegmentTrie/sample)]
|
||||
(SegmentTrie/lookup matcher "/user/1234/profile/compact")
|
||||
(cc/quick-bench
|
||||
(Trie/lookup matcher "/user/1234/profile/compact")))
|
||||
(SegmentTrie/lookup matcher "/user/1234/profile/compact")))
|
||||
|
||||
;; 173ns
|
||||
(let [lookup ^Trie$Matcher (Trie/tree2)]
|
||||
(Trie/lookup lookup "/user/1234/profile/compact")
|
||||
(let [lookup ^Trie$Matcher (SegmentTrie/tree2)]
|
||||
(SegmentTrie/lookup lookup "/user/1234/profile/compact")
|
||||
(cc/quick-bench
|
||||
(Trie/lookup lookup "/user/1234/profile/compact")))
|
||||
(SegmentTrie/lookup lookup "/user/1234/profile/compact")))
|
||||
|
||||
|
||||
;; 140ns
|
||||
(let [lookup ^Trie$Matcher (Trie/tree1)]
|
||||
(Trie/lookup lookup "/user/1234/profile/compact")
|
||||
(let [lookup ^Trie$Matcher (SegmentTrie/tree1)]
|
||||
(SegmentTrie/lookup lookup "/user/1234/profile/compact")
|
||||
(cc/quick-bench
|
||||
(Trie/lookup lookup "/user/1234/profile/compact")))
|
||||
(SegmentTrie/lookup lookup "/user/1234/profile/compact")))
|
||||
|
||||
;; 849ns (clojure, original)
|
||||
;; 599ns (java, initial)
|
||||
|
|
@ -225,15 +226,13 @@
|
|||
(dotimes [_ 1000]
|
||||
(handler-reitit request)))))
|
||||
|
||||
(import '[reitit Util])
|
||||
|
||||
(comment
|
||||
(Util/matchURI "/user/1234/profile/compact/" ["/user/" :id "/profile/" :type "/"])
|
||||
(cc/quick-bench
|
||||
(Util/matchURI "/user/1234/profile/compact/" ["/user/" :id "/profile/" :type "/"]))
|
||||
|
||||
(cc/quick-bench
|
||||
(Trie/split "/user/1234/profile/compact/"))
|
||||
(SegmentTrie/split "/user/1234/profile/compact/"))
|
||||
|
||||
(cc/quick-bench
|
||||
(.split "/user/1234/profile/compact/" "/" 666)))
|
||||
|
|
@ -265,9 +264,9 @@
|
|||
(segment/lookup segment "/user/1/permissions/"))))
|
||||
|
||||
#_(cc/quick-bench
|
||||
(Trie/split "/user/1/profile/compat"))
|
||||
(SegmentTrie/split "/user/1/profile/compat"))
|
||||
|
||||
#_(Trie/split "/user/1/profile/compat")
|
||||
#_(SegmentTrie/split "/user/1/profile/compat")
|
||||
|
||||
#_(cc/quick-bench
|
||||
(Segment2/hashLookup h "abba"))
|
||||
|
|
|
|||
|
|
@ -190,7 +190,7 @@
|
|||
(suite "split")
|
||||
|
||||
;; 114ns (String/split)
|
||||
;; 82ns (Trie/split)
|
||||
;; 82ns (SegmentTrie/split)
|
||||
(test "Splitting a String")
|
||||
(test! impl/segments "/olipa/kerran/:avaruus"))
|
||||
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@
|
|||
[io.pedestal.http.route.prefix-tree :as p]
|
||||
[reitit.segment :as segment]
|
||||
[criterium.core :as cc])
|
||||
(:import (reitit Trie)))
|
||||
(:import (reitit SegmentTrie)))
|
||||
|
||||
;;
|
||||
;; testing
|
||||
|
|
@ -72,7 +72,7 @@
|
|||
|
||||
(def matcher
|
||||
(.matcher
|
||||
^Trie
|
||||
^SegmentTrie
|
||||
(reduce
|
||||
(fn [acc [p d]]
|
||||
(segment/insert acc p d))
|
||||
|
|
|
|||
Loading…
Reference in a new issue