|
20 | 20 | /** Sync: May 22, 2020 Commit: 5704d7ee98edd3fe55169b506531bdd061667c70 */ |
21 | 21 | class Chi implements RouteTree { |
22 | 22 | private static final String EMPTY_STRING = ""; |
| 23 | + private static final Slice EMPTY_SLICE = new Slice(EMPTY_STRING); |
23 | 24 | private static final byte ntStatic = 0; // /home |
24 | 25 | private static final byte ntRegexp = 1; // /{id:[0-9]+} |
25 | 26 | private static final byte ntParam = 2; // /{user} |
26 | 27 | private static final byte ntCatchAll = 3; // /api/v1/* |
27 | 28 |
|
28 | 29 | private static final int NODE_SIZE = ntCatchAll + 1; |
29 | 30 |
|
30 | | - static final char ZERO_CHAR = (char) 0; |
| 31 | + static final char ZERO_CHAR = Character.MIN_VALUE; |
31 | 32 | private MessageEncoder encoder; |
32 | 33 |
|
| 34 | + /** Avoid string allocation */ |
| 35 | + private static class Slice implements CharSequence { |
| 36 | + private final String base; |
| 37 | + private final int startIndex; |
| 38 | + |
| 39 | + private final int endIndex; |
| 40 | + |
| 41 | + public Slice(String base, int startIndex, int endIndex) { |
| 42 | + this.base = base; |
| 43 | + this.startIndex = startIndex; |
| 44 | + this.endIndex = endIndex; |
| 45 | + } |
| 46 | + |
| 47 | + public Slice(String base, int startIndex) { |
| 48 | + this(base, startIndex, base.length()); |
| 49 | + } |
| 50 | + |
| 51 | + public Slice(String base) { |
| 52 | + this(base, 0); |
| 53 | + } |
| 54 | + |
| 55 | + @Override |
| 56 | + public int length() { |
| 57 | + return endIndex - startIndex; |
| 58 | + } |
| 59 | + |
| 60 | + @Override |
| 61 | + public char charAt(int index) { |
| 62 | + return base.charAt(startIndex + index); |
| 63 | + } |
| 64 | + |
| 65 | + @Override |
| 66 | + public Slice subSequence(int start, int end) { |
| 67 | + return new Slice(base, startIndex + start, startIndex + end); |
| 68 | + } |
| 69 | + |
| 70 | + @Override |
| 71 | + public String toString() { |
| 72 | + return base.substring(startIndex, endIndex); |
| 73 | + } |
| 74 | + |
| 75 | + public Slice substring(int start) { |
| 76 | + return substring(start, length()); |
| 77 | + } |
| 78 | + |
| 79 | + public Slice substring(int start, int end) { |
| 80 | + return subSequence(start, end); |
| 81 | + } |
| 82 | + |
| 83 | + public int indexOf(int ch) { |
| 84 | + for (int i = startIndex; i < endIndex; i++) { |
| 85 | + if (base.charAt(i) == ch) { |
| 86 | + return i - startIndex; |
| 87 | + } |
| 88 | + } |
| 89 | + return -1; |
| 90 | + } |
| 91 | + |
| 92 | + public boolean startsWith(String prefix) { |
| 93 | + int len = prefix.length(); |
| 94 | + if (len <= length()) { |
| 95 | + for (int i = 0; i < len; i++) { |
| 96 | + if (base.charAt(i + startIndex) != prefix.charAt(i)) { |
| 97 | + return false; |
| 98 | + } |
| 99 | + } |
| 100 | + return true; |
| 101 | + } |
| 102 | + return false; |
| 103 | + } |
| 104 | + } |
| 105 | + |
33 | 106 | private interface MethodMatcher { |
34 | 107 | StaticRouterMatch get(String method); |
35 | 108 |
|
@@ -434,15 +507,15 @@ void setEndpoint(String method, Route route) { |
434 | 507 |
|
435 | 508 | // Recursive edge traversal by checking all nodeTyp groups along the way. |
436 | 509 | // It's like searching through a multi-dimensional radix trie. |
437 | | - Route findRoute(RouterMatch rctx, String method, String path) { |
| 510 | + Route findRoute(RouterMatch rctx, String method, Slice path) { |
438 | 511 |
|
439 | 512 | for (int ntyp = 0; ntyp < NODE_SIZE; ntyp++) { |
440 | 513 | Node[] nds = this.children[ntyp]; |
441 | 514 | if (nds != null) { |
442 | 515 | Node xn = null; |
443 | | - String xsearch = path; |
| 516 | + Slice xsearch = path; |
444 | 517 |
|
445 | | - char label = path.length() > 0 ? path.charAt(0) : ZERO_CHAR; |
| 518 | + char label = xsearch.isEmpty() ? ZERO_CHAR : xsearch.charAt(0); |
446 | 519 |
|
447 | 520 | switch (ntyp) { |
448 | 521 | case ntStatic: |
@@ -475,17 +548,18 @@ Route findRoute(RouterMatch rctx, String method, String path) { |
475 | 548 | } |
476 | 549 |
|
477 | 550 | if (ntyp == ntRegexp && xn.rex != null) { |
| 551 | + // 12, ar, page, arx |
478 | 552 | if (!xn.rex.matcher(xsearch.substring(0, p)).matches()) { |
479 | 553 | continue; |
480 | 554 | } |
481 | | - } else if (xsearch.substring(0, p).indexOf('/') != -1) { |
| 555 | + } else if (xsearch.substring(0, p).indexOf('/') > 0) { |
482 | 556 | // avoid a newRuntimeRoute across path segments |
483 | 557 | continue; |
484 | 558 | } |
485 | 559 |
|
486 | 560 | // rctx.routeParams.Values = append(rctx.routeParams.Values, xsearch[:p]) |
487 | 561 | int prevlen = rctx.vars.size(); |
488 | | - rctx.value(xsearch.substring(0, p)); |
| 562 | + rctx.value(xsearch.substring(0, p).toString()); |
489 | 563 | xsearch = xsearch.substring(p); |
490 | 564 |
|
491 | 565 | if (xsearch.length() == 0) { |
@@ -514,10 +588,10 @@ Route findRoute(RouterMatch rctx, String method, String path) { |
514 | 588 | // catch-all nodes |
515 | 589 | // rctx.routeParams.Values = append(rctx.routeParams.Values, search) |
516 | 590 | if (xsearch.length() > 0) { |
517 | | - rctx.value(xsearch); |
| 591 | + rctx.value(xsearch.toString()); |
518 | 592 | } |
519 | 593 | xn = nds[0]; |
520 | | - xsearch = EMPTY_STRING; |
| 594 | + xsearch = EMPTY_SLICE; |
521 | 595 | } |
522 | 596 |
|
523 | 597 | if (xn == null) { |
@@ -632,7 +706,7 @@ Segment patNextSegment(String pattern) { |
632 | 706 | } |
633 | 707 |
|
634 | 708 | // Sanity check |
635 | | - if (ps >= 0 && ws >= 0 && ws < ps) { |
| 709 | + if (ws >= 0 && ws < ps) { |
636 | 710 | throw new IllegalArgumentException( |
637 | 711 | "chi: wildcard '*' must be the last pattern in a route, otherwise use a '{param}'"); |
638 | 712 | } |
@@ -778,7 +852,7 @@ public Router.Match find(String method, String path) { |
778 | 852 | private Router.Match findInternal(String method, String path) { |
779 | 853 | // use radix tree |
780 | 854 | RouterMatch result = new RouterMatch(); |
781 | | - Route route = root.findRoute(result, method, path); |
| 855 | + Route route = root.findRoute(result, method, new Slice(path)); |
782 | 856 | if (route == null) { |
783 | 857 | return result.missing(method, path, encoder); |
784 | 858 | } |
|
0 commit comments