mirror of
https://github.com/metosin/reitit.git
synced 2025-12-18 08:51:12 +00:00
wip
This commit is contained in:
parent
25287e0df7
commit
f2d131a897
9 changed files with 469 additions and 20 deletions
|
|
@ -83,7 +83,8 @@
|
||||||
(ring/routes
|
(ring/routes
|
||||||
(swagger-ui/create-swagger-ui-handler
|
(swagger-ui/create-swagger-ui-handler
|
||||||
{:path "/"
|
{:path "/"
|
||||||
:config {:validatorUrl nil}})
|
:config {:validatorUrl nil
|
||||||
|
:operationsSorter "alpha"}})
|
||||||
(ring/create-default-handler))))
|
(ring/create-default-handler))))
|
||||||
|
|
||||||
(defn start []
|
(defn start []
|
||||||
|
|
|
||||||
216
modules/reitit-core/java-src/reitit/Trie.java
Normal file
216
modules/reitit-core/java-src/reitit/Trie.java
Normal file
|
|
@ -0,0 +1,216 @@
|
||||||
|
package reitit;
|
||||||
|
|
||||||
|
// https://www.codeproject.com/Tips/1190293/Iteration-Over-Java-Collections-with-High-Performa
|
||||||
|
|
||||||
|
import clojure.lang.Keyword;
|
||||||
|
|
||||||
|
import java.io.UnsupportedEncodingException;
|
||||||
|
import java.net.URLDecoder;
|
||||||
|
import java.util.*;
|
||||||
|
|
||||||
|
public class Trie {
|
||||||
|
|
||||||
|
private static String decode(char[] chars, int i, int j, boolean hasPercent, boolean hasPlus) {
|
||||||
|
final String s = new String(chars, i, j);
|
||||||
|
try {
|
||||||
|
if (hasPercent) {
|
||||||
|
return URLDecoder.decode(hasPlus ? s.replace("+", "%2B") : s, "UTF-8");
|
||||||
|
}
|
||||||
|
} catch (UnsupportedEncodingException ignored) {
|
||||||
|
}
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class Match {
|
||||||
|
public final List<Object> params = new ArrayList<>();
|
||||||
|
public Object data;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
Map<Object, Object> m = new HashMap<>();
|
||||||
|
m.put(Keyword.intern("data"), data);
|
||||||
|
m.put(Keyword.intern("params"), params);
|
||||||
|
return m.toString();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class Path {
|
||||||
|
final char[] value;
|
||||||
|
final int size;
|
||||||
|
|
||||||
|
Path(String value) {
|
||||||
|
this.value = value.toCharArray();
|
||||||
|
this.size = value.length();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public interface Matcher {
|
||||||
|
Match match(int i, Path path, Match match);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static StaticMatcher staticMatcher(String path, Matcher child) {
|
||||||
|
return new StaticMatcher(path, child);
|
||||||
|
}
|
||||||
|
|
||||||
|
static class StaticMatcher implements Matcher {
|
||||||
|
private final Matcher child;
|
||||||
|
private final char[] path;
|
||||||
|
private final int size;
|
||||||
|
|
||||||
|
StaticMatcher(String path, Matcher child) {
|
||||||
|
this.path = path.toCharArray();
|
||||||
|
this.size = path.length();
|
||||||
|
this.child = child;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Match match(int i, Path path, Match match) {
|
||||||
|
final char[] value = path.value;
|
||||||
|
if (path.size < i + size) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
for (int j = 0; j < size; j++) {
|
||||||
|
if (value[j + i] != this.path[j]) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return child.match(i + size, path, match);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return "[\"" + new String(path) + "\" " + child + "]";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static DataMatcher dataMatcher(Object data) {
|
||||||
|
return new DataMatcher(data);
|
||||||
|
}
|
||||||
|
|
||||||
|
static final class DataMatcher implements Matcher {
|
||||||
|
private final Object data;
|
||||||
|
|
||||||
|
DataMatcher(Object data) {
|
||||||
|
this.data = data;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Match match(int i, Path path, Match match) {
|
||||||
|
if (i == path.size) {
|
||||||
|
match.data = data;
|
||||||
|
return match;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return (data != null ? data.toString() : "nil");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static WildMatcher wildMatcher(Keyword parameter, Matcher child) {
|
||||||
|
return new WildMatcher(parameter, child);
|
||||||
|
}
|
||||||
|
|
||||||
|
static final class WildMatcher implements Matcher {
|
||||||
|
private final Keyword key;
|
||||||
|
private final Matcher child;
|
||||||
|
|
||||||
|
WildMatcher(Keyword key, Matcher child) {
|
||||||
|
this.key = key;
|
||||||
|
this.child = child;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Match match(int i, Path path, Match match) {
|
||||||
|
final char[] value = path.value;
|
||||||
|
if (i < path.size && value[i] != '/') {
|
||||||
|
boolean hasPercent = false;
|
||||||
|
boolean hasPlus = false;
|
||||||
|
for (int j = i; j < path.size; j++) {
|
||||||
|
if (value[j] == '/') {
|
||||||
|
final Match m = child.match(j, path, match);
|
||||||
|
if (m != null) {
|
||||||
|
m.params.add(key);
|
||||||
|
m.params.add(decode(value, i, j - i, hasPercent, hasPlus));
|
||||||
|
}
|
||||||
|
return m;
|
||||||
|
} else if (value[j] == '%') {
|
||||||
|
hasPercent = true;
|
||||||
|
} else if (value[j] == '+') {
|
||||||
|
hasPlus = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (child instanceof DataMatcher) {
|
||||||
|
final Match m = child.match(path.size, path, match);
|
||||||
|
m.params.add(key);
|
||||||
|
m.params.add(decode(value, i, path.size - i, hasPercent, hasPlus));
|
||||||
|
return m;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return "[" + key + " " + child + "]";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static LinearMatcher linearMatcher(List<Matcher> childs) {
|
||||||
|
return new LinearMatcher(childs);
|
||||||
|
}
|
||||||
|
|
||||||
|
static final class LinearMatcher implements Matcher {
|
||||||
|
|
||||||
|
private final Matcher[] childs;
|
||||||
|
private final int size;
|
||||||
|
|
||||||
|
LinearMatcher(List<Matcher> childs) {
|
||||||
|
this.childs = childs.toArray(new Matcher[0]);
|
||||||
|
this.size = childs.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Match match(int i, Path path, Match match) {
|
||||||
|
for (int j = 0; j < size; j++) {
|
||||||
|
final Match m = childs[j].match(i, path, match);
|
||||||
|
if (m != null) {
|
||||||
|
return m;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return Arrays.toString(childs);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Object lookup(Matcher matcher, String path) {
|
||||||
|
return matcher.match(0, new Path(path), new Match());
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void main(String[] args) {
|
||||||
|
|
||||||
|
//Matcher matcher = new StaticMatcher("/kikka", new StaticMatcher("/kukka", new DataMatcher(1)));
|
||||||
|
// Matcher matcher =
|
||||||
|
// staticMatcher("/kikka/",
|
||||||
|
// wildMatcher(Keyword.intern("kukka"),
|
||||||
|
// staticMatcher("/kikka",
|
||||||
|
// dataMatcher(1))));
|
||||||
|
Matcher matcher =
|
||||||
|
linearMatcher(
|
||||||
|
Arrays.asList(
|
||||||
|
staticMatcher("/auth/",
|
||||||
|
linearMatcher(
|
||||||
|
Arrays.asList(
|
||||||
|
staticMatcher("login", dataMatcher(1)),
|
||||||
|
staticMatcher("recovery", dataMatcher(2)))))));
|
||||||
|
System.err.println(matcher);
|
||||||
|
System.out.println(lookup(matcher, "/auth/login"));
|
||||||
|
System.out.println(lookup(matcher, "/auth/recovery"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -8,5 +8,5 @@
|
||||||
:plugins [[lein-parent "0.3.2"]]
|
:plugins [[lein-parent "0.3.2"]]
|
||||||
:parent-project {:path "../../project.clj"
|
:parent-project {:path "../../project.clj"
|
||||||
:inherit [:deploy-repositories :managed-dependencies]}
|
:inherit [:deploy-repositories :managed-dependencies]}
|
||||||
:java-source-paths ["java-src"]
|
;:java-source-paths ["java-src"]
|
||||||
:dependencies [[meta-merge]])
|
:dependencies [[meta-merge]])
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,7 @@
|
||||||
(:require [meta-merge.core :refer [meta-merge]]
|
(:require [meta-merge.core :refer [meta-merge]]
|
||||||
[clojure.string :as str]
|
[clojure.string :as str]
|
||||||
[reitit.segment :as segment]
|
[reitit.segment :as segment]
|
||||||
|
[reitit.segment :as trie]
|
||||||
[reitit.impl :as impl #?@(:cljs [:refer [Route]])])
|
[reitit.impl :as impl #?@(:cljs [:refer [Route]])])
|
||||||
#?(:clj
|
#?(:clj
|
||||||
(:import (reitit.impl Route))))
|
(:import (reitit.impl Route))))
|
||||||
|
|
@ -265,11 +266,11 @@
|
||||||
f #(if-let [path (impl/path-for route %)]
|
f #(if-let [path (impl/path-for route %)]
|
||||||
(->Match p data result (impl/url-decode-coll %) path)
|
(->Match p data result (impl/url-decode-coll %) path)
|
||||||
(->PartialMatch p data result % path-params))]
|
(->PartialMatch p data result % path-params))]
|
||||||
[(segment/insert pl p (->Match p data result nil nil))
|
[(trie/insert pl p (->Match p data result nil nil))
|
||||||
(if name (assoc nl name f) nl)]))
|
(if name (assoc nl name f) nl)]))
|
||||||
[nil {}]
|
[nil {}]
|
||||||
compiled-routes)
|
compiled-routes)
|
||||||
pl (segment/compile pl)
|
pl (trie/compile pl)
|
||||||
lookup (impl/fast-map nl)
|
lookup (impl/fast-map nl)
|
||||||
routes (uncompile-routes compiled-routes)]
|
routes (uncompile-routes compiled-routes)]
|
||||||
^{:type ::router}
|
^{:type ::router}
|
||||||
|
|
@ -286,7 +287,7 @@
|
||||||
(route-names [_]
|
(route-names [_]
|
||||||
names)
|
names)
|
||||||
(match-by-path [_ path]
|
(match-by-path [_ path]
|
||||||
(if-let [match (segment/lookup pl path)]
|
(if-let [match (trie/lookup pl path)]
|
||||||
(-> (:data match)
|
(-> (:data match)
|
||||||
(assoc :path-params (:path-params match))
|
(assoc :path-params (:path-params match))
|
||||||
(assoc :path path))))
|
(assoc :path path))))
|
||||||
|
|
|
||||||
146
modules/reitit-core/src/reitit/trie.cljc
Normal file
146
modules/reitit-core/src/reitit/trie.cljc
Normal file
|
|
@ -0,0 +1,146 @@
|
||||||
|
(ns reitit.trie
|
||||||
|
(:refer-clojure :exclude [compile])
|
||||||
|
(:require [clojure.string :as str])
|
||||||
|
(:import [reitit Trie Trie$Match Trie$Matcher]))
|
||||||
|
|
||||||
|
(defrecord Match [data path-params])
|
||||||
|
(defrecord Node [children wilds catch-all data])
|
||||||
|
|
||||||
|
;; https://stackoverflow.com/questions/8033655/find-longest-common-prefix
|
||||||
|
(defn- -common-prefix [s1 s2]
|
||||||
|
(let [max (min (count s1) (count s2))]
|
||||||
|
(loop [i 0]
|
||||||
|
(cond
|
||||||
|
;; full match
|
||||||
|
(> i max)
|
||||||
|
(subs s1 0 max)
|
||||||
|
;; partial match
|
||||||
|
(not= (get s1 i) (get s2 i))
|
||||||
|
(if-not (zero? i) (subs s1 0 i))
|
||||||
|
;; recur
|
||||||
|
:else
|
||||||
|
(recur (inc i))))))
|
||||||
|
|
||||||
|
(defn- -keyword [s]
|
||||||
|
(if-let [i (str/index-of s "/")]
|
||||||
|
(keyword (subs s 0 i) (subs s (inc i)))
|
||||||
|
(keyword s)))
|
||||||
|
|
||||||
|
(defn- -split [s]
|
||||||
|
(let [-static (fn [from to] (if-not (= from to) [(subs s from to)]))
|
||||||
|
-wild (fn [from to] [(-keyword (subs s (inc from) to))])
|
||||||
|
-catch-all (fn [from to] [#{(keyword (subs s (inc from) to))}])]
|
||||||
|
(loop [ss nil, from 0, to 0]
|
||||||
|
(if (= to (count s))
|
||||||
|
(concat ss (-static from to))
|
||||||
|
(condp = (get s to)
|
||||||
|
\{ (let [to' (or (str/index-of s "}" to) (throw (ex-info (str "Unbalanced brackets: " (pr-str s)) {})))]
|
||||||
|
(recur (concat ss (-static from to) (-wild to to')) (inc to') (inc to')))
|
||||||
|
\: (let [to' (or (str/index-of s "/" to) (count s))]
|
||||||
|
(recur (concat ss (-static from to) (-wild to to')) to' to'))
|
||||||
|
\* (let [to' (count s)]
|
||||||
|
(recur (concat ss (-static from to) (-catch-all to to')) to' to'))
|
||||||
|
(recur ss from (inc to)))))))
|
||||||
|
|
||||||
|
(defn- -node [m]
|
||||||
|
(map->Node (merge {:children {}, :wilds {}, :catch-all {}} m)))
|
||||||
|
|
||||||
|
(defn- -insert [node [path & ps] data]
|
||||||
|
(let [node' (cond
|
||||||
|
|
||||||
|
(nil? path)
|
||||||
|
(assoc node :data data)
|
||||||
|
|
||||||
|
(keyword? path)
|
||||||
|
(update-in node [:wilds path] (fn [n] (-insert (or n (-node {})) ps data)))
|
||||||
|
|
||||||
|
(set? path)
|
||||||
|
(assoc-in node [:catch-all path] (-node {:data data}))
|
||||||
|
|
||||||
|
(str/blank? path)
|
||||||
|
(-insert node ps data)
|
||||||
|
|
||||||
|
:else
|
||||||
|
(or
|
||||||
|
(reduce
|
||||||
|
(fn [_ [p n]]
|
||||||
|
(if-let [cp (-common-prefix p path)]
|
||||||
|
(if (= cp p)
|
||||||
|
;; insert into child node
|
||||||
|
(let [n' (-insert n (conj ps (subs path (count p))) data)]
|
||||||
|
(reduced (assoc-in node [:children p] n')))
|
||||||
|
;; split child node
|
||||||
|
(let [rp (subs p (count cp))
|
||||||
|
rp' (subs path (count cp))
|
||||||
|
n' (-insert (-node {}) ps data)
|
||||||
|
n'' (-insert (-node {:children {rp n, rp' n'}}) nil nil)]
|
||||||
|
(reduced (update node :children (fn [children]
|
||||||
|
(-> children
|
||||||
|
(dissoc p)
|
||||||
|
(assoc cp n'')))))))))
|
||||||
|
nil (:children node))
|
||||||
|
;; new child node
|
||||||
|
(assoc-in node [:children path] (-insert (-node {}) ps data))))]
|
||||||
|
(if-let [child (get-in node' [:children ""])]
|
||||||
|
;; optimize by removing empty paths
|
||||||
|
(-> (merge-with merge node' child)
|
||||||
|
(update :children dissoc ""))
|
||||||
|
node')))
|
||||||
|
|
||||||
|
(defn insert [node path data]
|
||||||
|
(-insert (or node (-node {})) (-split path) data))
|
||||||
|
|
||||||
|
(defn ^Trie$Matcher compile [{:keys [data children wilds catch-all]}]
|
||||||
|
(let [matchers (cond-> []
|
||||||
|
data (conj (Trie/dataMatcher data))
|
||||||
|
children (into (for [[p c] children] (Trie/staticMatcher p (compile c))))
|
||||||
|
wilds (into (for [[p c] wilds] (Trie/wildMatcher p (compile c)))))]
|
||||||
|
(if (rest matchers)
|
||||||
|
(Trie/linearMatcher matchers)
|
||||||
|
(first matchers))))
|
||||||
|
|
||||||
|
(defn pretty [{:keys [data children wilds catch-all]}]
|
||||||
|
(into
|
||||||
|
(if data [data] [])
|
||||||
|
(mapcat (fn [[p n]] [p (pretty n)]) (concat children wilds catch-all))))
|
||||||
|
|
||||||
|
(defn lookup [^Trie$Matcher matcher path]
|
||||||
|
(if-let [match ^Trie$Match (Trie/lookup matcher ^String path)]
|
||||||
|
(->Match (.data match) (clojure.lang.PersistentHashMap/create (.toArray (.params match))))))
|
||||||
|
|
||||||
|
;;
|
||||||
|
;; matcher
|
||||||
|
;;
|
||||||
|
|
||||||
|
;;
|
||||||
|
;; spike
|
||||||
|
;;
|
||||||
|
|
||||||
|
(-> nil
|
||||||
|
(insert "/:abba" 1)
|
||||||
|
(insert "/kikka" 2)
|
||||||
|
(insert "/kikka/kakka/kukka" 3)
|
||||||
|
(insert "/kikka/:kakka/kukka" 4)
|
||||||
|
(insert "/kikka/kuri/{user/doc}.html" 5)
|
||||||
|
(insert "/kikkare/*path" 6)
|
||||||
|
#_(pretty))
|
||||||
|
|
||||||
|
(-> nil
|
||||||
|
(insert "/kikka" 2)
|
||||||
|
(insert "/kikka/kakka/kukka" 3)
|
||||||
|
(insert "/kikka/:kakka/kurkku" 4)
|
||||||
|
(insert "/kikka/kuri/{user/doc}/html" 5)
|
||||||
|
(compile)
|
||||||
|
(lookup "/kikka/kakka/kurkku"))
|
||||||
|
|
||||||
|
;; =>
|
||||||
|
|
||||||
|
["/"
|
||||||
|
["kikka" [2
|
||||||
|
"/" ["k" ["akka/kukka" [3]
|
||||||
|
"uri/" [:user/doc [".html" [5]]]]
|
||||||
|
:kakka ["/kukka" [4]]]
|
||||||
|
"re/" [#{:path} [6]]]
|
||||||
|
:abba [1]]]
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -205,3 +205,69 @@
|
||||||
(routing-test1)
|
(routing-test1)
|
||||||
(routing-test2)
|
(routing-test2)
|
||||||
(reverse-routing-test))
|
(reverse-routing-test))
|
||||||
|
|
||||||
|
(import '[reitit Trie])
|
||||||
|
|
||||||
|
(set! *warn-on-reflection* true)
|
||||||
|
|
||||||
|
(comment
|
||||||
|
(let [trie ]
|
||||||
|
|
||||||
|
|
||||||
|
(println
|
||||||
|
(Trie/lookup trie "/auth/login"))
|
||||||
|
|
||||||
|
;; 27ns
|
||||||
|
(cc/quick-bench
|
||||||
|
(dotimes [_ 1000]
|
||||||
|
(Trie/lookup trie "/auth/login")))
|
||||||
|
|
||||||
|
(println
|
||||||
|
(Trie/lookup trie "/auth/recovery/token/123"))
|
||||||
|
|
||||||
|
;; 82ns
|
||||||
|
(cc/quick-bench
|
||||||
|
(dotimes [_ 1000]
|
||||||
|
(Trie/lookup trie "/auth/recovery/token/123")))
|
||||||
|
|
||||||
|
(println
|
||||||
|
(Trie/lookup trie "/workspace/1/1"))
|
||||||
|
|
||||||
|
;; 96ns
|
||||||
|
(cc/quick-bench
|
||||||
|
(dotimes [_ 1000]
|
||||||
|
(Trie/lookup trie "/workspace/1/1")))))
|
||||||
|
|
||||||
|
(comment
|
||||||
|
(let [trie (Trie/linearMatcher
|
||||||
|
[(Trie/staticMatcher
|
||||||
|
"/auth/" (Trie/linearMatcher
|
||||||
|
[(Trie/staticMatcher "login" (Trie/dataMatcher 1))
|
||||||
|
(Trie/staticMatcher "recovery/token/" (Trie/wildMatcher :token (Trie/dataMatcher 2)))]))
|
||||||
|
(Trie/staticMatcher
|
||||||
|
"/workspace/" (Trie/wildMatcher :project (Trie/staticMatcher "/" (Trie/wildMatcher :page (Trie/dataMatcher 3)))))])]
|
||||||
|
|
||||||
|
|
||||||
|
(println
|
||||||
|
(Trie/lookup trie "/auth/login"))
|
||||||
|
|
||||||
|
;; 27ns
|
||||||
|
(cc/quick-bench
|
||||||
|
(dotimes [_ 1000]
|
||||||
|
(Trie/lookup trie "/auth/login")))
|
||||||
|
|
||||||
|
(println
|
||||||
|
(Trie/lookup trie "/auth/recovery/token/123"))
|
||||||
|
|
||||||
|
;; 82ns
|
||||||
|
(cc/quick-bench
|
||||||
|
(dotimes [_ 1000]
|
||||||
|
(Trie/lookup trie "/auth/recovery/token/123")))
|
||||||
|
|
||||||
|
(println
|
||||||
|
(Trie/lookup trie "/workspace/1/1"))
|
||||||
|
|
||||||
|
;; 96ns
|
||||||
|
(cc/quick-bench
|
||||||
|
(dotimes [_ 1000]
|
||||||
|
(Trie/lookup trie "/workspace/1/1")))))
|
||||||
|
|
|
||||||
|
|
@ -578,35 +578,36 @@
|
||||||
;; 806ns (decode path-parameters)
|
;; 806ns (decode path-parameters)
|
||||||
;; 735ns (maybe-map-values)
|
;; 735ns (maybe-map-values)
|
||||||
;; 474ns (java-segment-router)
|
;; 474ns (java-segment-router)
|
||||||
(b! "reitit-ring" reitit-ring-f)
|
#_(b! "reitit-ring" reitit-ring-f)
|
||||||
|
|
||||||
;; 385ns (java-segment-router, no injects)
|
;; 385ns (java-segment-router, no injects)
|
||||||
(b! "reitit-ring-fast" reitit-ring-fast-f)
|
#_(b! "reitit-ring-fast" reitit-ring-fast-f)
|
||||||
|
|
||||||
;; 2553ns (linear-router)
|
;; 2553ns (linear-router)
|
||||||
;; 630ns (segment-router-backed)
|
;; 630ns (segment-router-backed)
|
||||||
(b! "reitit-ring-linear" reitit-ring-linear-f)
|
#_(b! "reitit-ring-linear" reitit-ring-linear-f)
|
||||||
|
|
||||||
;; 2137ns
|
;; 2137ns
|
||||||
(b! "calfpath-walker" calfpath-walker-f)
|
#_(b! "calfpath-walker" calfpath-walker-f)
|
||||||
|
|
||||||
;; 4774ns
|
;; 4774ns
|
||||||
(b! "calfpath-unroll" calfpath-unroll-f)
|
#_(b! "calfpath-unroll" calfpath-unroll-f)
|
||||||
|
|
||||||
;; 2821ns
|
;; 2821ns
|
||||||
(b! "pedestal" pedestal-f)
|
#_(b! "pedestal" pedestal-f)
|
||||||
|
|
||||||
;; 4803ns
|
;; 4803ns
|
||||||
(b! "calfpath-macros" calfpath-macros-f)
|
#_(b! "calfpath-macros" calfpath-macros-f)
|
||||||
|
|
||||||
;; 11615ns
|
;; 11615ns
|
||||||
(b! "compojure" compojure-f)
|
#_(b! "compojure" compojure-f)
|
||||||
|
|
||||||
;; 15034ns
|
;; 15034ns
|
||||||
(b! "bidi" bidi-f)
|
#_(b! "bidi" bidi-f)
|
||||||
|
|
||||||
;; 19688ns
|
;; 19688ns
|
||||||
(b! "ataraxy" ataraxy-f)))
|
#_(b! "ataraxy" ataraxy-f)))
|
||||||
|
|
||||||
(comment
|
(comment
|
||||||
(bench-rest!))
|
(bench-rest!))
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,7 @@
|
||||||
(:require [clojure.test :refer :all]
|
(:require [clojure.test :refer :all]
|
||||||
[io.pedestal.http.route.prefix-tree :as p]
|
[io.pedestal.http.route.prefix-tree :as p]
|
||||||
[reitit.segment :as segment]
|
[reitit.segment :as segment]
|
||||||
|
[reitit.trie :as trie]
|
||||||
[criterium.core :as cc])
|
[criterium.core :as cc])
|
||||||
(:import (reitit SegmentTrie)))
|
(:import (reitit SegmentTrie)))
|
||||||
|
|
||||||
|
|
@ -70,7 +71,7 @@
|
||||||
(p/insert acc p d))
|
(p/insert acc p d))
|
||||||
nil routes))
|
nil routes))
|
||||||
|
|
||||||
(def matcher
|
(def segment-matcher
|
||||||
(.matcher
|
(.matcher
|
||||||
^SegmentTrie
|
^SegmentTrie
|
||||||
(reduce
|
(reduce
|
||||||
|
|
@ -78,6 +79,13 @@
|
||||||
(segment/insert acc p d))
|
(segment/insert acc p d))
|
||||||
nil routes)))
|
nil routes)))
|
||||||
|
|
||||||
|
(def trie-matcher
|
||||||
|
(trie/compile
|
||||||
|
(reduce
|
||||||
|
(fn [acc [p d]]
|
||||||
|
(trie/insert acc p d))
|
||||||
|
nil routes)))
|
||||||
|
|
||||||
(defn bench! []
|
(defn bench! []
|
||||||
|
|
||||||
;; 2.3µs
|
;; 2.3µs
|
||||||
|
|
@ -110,12 +118,21 @@
|
||||||
;; 0.51µs (Cleanup)
|
;; 0.51µs (Cleanup)
|
||||||
;; 0.30µs (Java)
|
;; 0.30µs (Java)
|
||||||
(cc/quick-bench
|
(cc/quick-bench
|
||||||
(segment/lookup matcher "/v1/orgs/1/topics")))
|
(segment/lookup segment-matcher "/v1/orgs/1/topics"))
|
||||||
|
|
||||||
|
;; 0.32µs (initial)
|
||||||
|
;; 0.30µs (iterate arrays)
|
||||||
|
;; 0.28µs (list-params)
|
||||||
|
(cc/quick-bench
|
||||||
|
(trie/lookup trie-matcher "/v1/orgs/1/topics")))
|
||||||
|
|
||||||
(comment
|
(comment
|
||||||
(bench!))
|
(bench!))
|
||||||
|
|
||||||
|
(set! *warn-on-reflection* true)
|
||||||
|
|
||||||
(comment
|
(comment
|
||||||
(p/lookup pedestal-tree "/v1/orgs/1/topics")
|
(p/lookup pedestal-tree "/v1/orgs/1/topics")
|
||||||
#_(trie/lookup reitit-tree "/v1/orgs/1/topics" {})
|
(trie/lookup trie-matcher "/v1/orgs/1/topics")
|
||||||
(segment/lookup matcher "/v1/orgs/1/topics"))
|
(segment/lookup segment-matcher "/v1/orgs/1/topics"))
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -38,6 +38,7 @@
|
||||||
[io.pedestal/pedestal.service "0.5.5"]]
|
[io.pedestal/pedestal.service "0.5.5"]]
|
||||||
|
|
||||||
:plugins [[jonase/eastwood "0.3.4"]
|
:plugins [[jonase/eastwood "0.3.4"]
|
||||||
|
[lein-virgil "0.1.7"]
|
||||||
[lein-doo "0.1.11"]
|
[lein-doo "0.1.11"]
|
||||||
[lein-cljsbuild "1.1.7"]
|
[lein-cljsbuild "1.1.7"]
|
||||||
[lein-cloverage "1.0.13"]
|
[lein-cloverage "1.0.13"]
|
||||||
|
|
@ -61,7 +62,7 @@
|
||||||
"modules/reitit-sieppari/src"
|
"modules/reitit-sieppari/src"
|
||||||
"modules/reitit-pedestal/src"]
|
"modules/reitit-pedestal/src"]
|
||||||
|
|
||||||
:java-source-paths ["modules/reitit-core/java-src"]
|
;:java-source-paths ["modules/reitit-core/java-src"]
|
||||||
|
|
||||||
:dependencies [[org.clojure/clojure "1.10.0"]
|
:dependencies [[org.clojure/clojure "1.10.0"]
|
||||||
[org.clojure/clojurescript "1.10.439"]
|
[org.clojure/clojurescript "1.10.439"]
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue