Implement catch-all from trie

This commit is contained in:
Tommi Reiman 2019-01-27 22:10:46 +02:00
parent fe0ea19e31
commit eaee4ca38d
4 changed files with 59 additions and 9 deletions

View file

@ -13,8 +13,8 @@ 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);
private static String decode(char[] chars, int offset, int count, boolean hasPercent, boolean hasPlus) {
final String s = new String(chars, offset, count);
try {
if (hasPercent) {
return URLDecoder.decode(hasPlus ? s.replace("+", "%2B") : s, "UTF-8");
@ -24,6 +24,20 @@ public class Trie {
return s;
}
private static String decode(char[] chars, int offset, int count) {
boolean hasPercent = false;
boolean hasPlus = false;
for (int j = offset; j < offset + count; j++) {
if (chars[j] == '%') {
hasPercent = true;
} else if (chars[j] == '+') {
hasPlus = true;
}
}
System.err.println();
return decode(chars, offset, count, hasPercent, hasPlus);
}
public static class Match {
final ITransientMap params = PersistentArrayMap.EMPTY.asTransient();
public Object data;
@ -36,7 +50,7 @@ public class Trie {
public String toString() {
Map<Object, Object> m = new HashMap<>();
m.put(Keyword.intern("data"), data);
m.put(Keyword.intern("params"), params.persistent());
m.put(Keyword.intern("params"), parameters());
return m.toString();
}
}
@ -163,6 +177,35 @@ public class Trie {
}
}
public static CatchAllMatcher catchAllMatcher(Keyword parameter, Object data) {
return new CatchAllMatcher(parameter, data);
}
static final class CatchAllMatcher implements Matcher {
private final Keyword parameter;
private final Object data;
CatchAllMatcher(Keyword parameter, Object data) {
this.parameter = parameter;
this.data = data;
}
@Override
public Match match(int i, Path path, Match match) {
if (i < path.value.length) {
match.params.assoc(parameter, decode(path.value, i, path.size - i));
match.data = data;
return match;
}
return null;
}
@Override
public String toString() {
return "[" + parameter + " " + new DataMatcher(data) + "]";
}
}
public static LinearMatcher linearMatcher(List<Matcher> childs) {
return new LinearMatcher(childs);
}
@ -198,6 +241,10 @@ public class Trie {
return matcher.match(0, new Path(path), new Match());
}
public static Matcher scanner(List<Matcher> matchers) {
return new LinearMatcher(matchers);
}
public static void main(String[] args) {
//Matcher matcher = new StaticMatcher("/kikka", new StaticMatcher("/kukka", new DataMatcher(1)));

View file

@ -1,7 +1,6 @@
(ns reitit.core
(:require [meta-merge.core :refer [meta-merge]]
[clojure.string :as str]
[reitit.segment :as segment]
[reitit.trie :as trie]
[reitit.impl :as impl #?@(:cljs [:refer [Route]])])
#?(:clj
@ -176,12 +175,12 @@
f #(if-let [path (impl/path-for route %)]
(->Match p data result (impl/url-decode-coll %) path)
(->PartialMatch p data result % path-params))]
[(conj pl (-> (segment/insert nil p (->Match p data result nil nil)) (segment/compile)))
[(conj pl (-> (trie/insert nil p (->Match p data result nil nil)) (trie/compile)))
(if name (assoc nl name f) nl)]))
[[] {}]
compiled-routes)
lookup (impl/fast-map nl)
scanner (segment/scanner pl)
scanner (trie/scanner pl)
routes (uncompile-routes compiled-routes)]
^{:type ::router}
(reify
@ -197,7 +196,7 @@
(route-names [_]
names)
(match-by-path [_ path]
(if-let [match (segment/lookup scanner path)]
(if-let [match (trie/lookup scanner path)]
(-> (:data match)
(assoc :path-params (:path-params match))
(assoc :path path))))

View file

@ -94,7 +94,8 @@
(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)))))]
wilds (into (for [[p c] wilds] (Trie/wildMatcher p (compile c))))
catch-all (into (for [[p c] catch-all] (Trie/catchAllMatcher (first p) (:data c)))))]
(if (rest matchers)
(Trie/linearMatcher matchers)
(first matchers))))
@ -108,6 +109,9 @@
(if-let [match ^Trie$Match (Trie/lookup matcher ^String path)]
(->Match (.data match) (.parameters match))))
(defn scanner [compiled-tries]
(Trie/scanner compiled-tries))
;;
;; matcher
;;

View file

@ -62,7 +62,7 @@
"modules/reitit-sieppari/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"]
[org.clojure/clojurescript "1.10.439"]