Skip to content

Commit 062170f

Browse files
committed
code cleanup: remove zerocopystring from routing algorithm
1 parent 59979ee commit 062170f

File tree

3 files changed

+26
-206
lines changed

3 files changed

+26
-206
lines changed

jooby/src/main/java/io/jooby/internal/Chi.java

Lines changed: 24 additions & 135 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
* Commit: 17fb1065d2b256d20f68bed0b7bca6c2942aff49
2424
*/
2525
class Chi implements RouteTree {
26+
private static final String EMPTY_STRING = "";
2627
private static final byte ntStatic = 0;// /home
2728
private static final byte ntRegexp = 1; // /{id:[0-9]+}
2829
private static final byte ntParam = 2; // /{user}
@@ -51,130 +52,18 @@ public void put(String method, Route route) {
5152
}
5253
}
5354

54-
static class ZeroCopyString {
55-
public static final ZeroCopyString EMPTY = new ZeroCopyString(new char[0], 0, 0);
56-
57-
private final int offset;
58-
private final int length;
59-
private int hash = 0;
60-
private final char[] value;
61-
62-
public ZeroCopyString(String source) {
63-
this.offset = 0;
64-
this.length = source.length();
65-
this.value = source.toCharArray();
66-
}
67-
68-
@Override public boolean equals(Object anObject) {
69-
if (this == anObject) {
70-
return true;
71-
}
72-
if (anObject instanceof ZeroCopyString) {
73-
ZeroCopyString anotherString = (ZeroCopyString) anObject;
74-
int n = length;
75-
if (n == anotherString.length) {
76-
char v1[] = value;
77-
char v2[] = anotherString.value;
78-
int i = 0;
79-
while (n-- != 0) {
80-
if (v1[i + offset] != v2[i + anotherString.offset])
81-
return false;
82-
i++;
83-
}
84-
return true;
85-
}
86-
}
87-
return false;
88-
}
89-
90-
public int hashCode() {
91-
int h = hash;
92-
if (h == 0 && length > 0) {
93-
char val[] = value;
94-
int len = offset + length;
95-
for (int i = offset; i < len; i++) {
96-
h = 31 * h + val[i];
97-
}
98-
hash = h;
99-
}
100-
return h;
101-
}
102-
103-
protected ZeroCopyString(char[] source, int offset, int length) {
104-
this.offset = offset;
105-
this.length = length;
106-
this.value = source;
107-
}
108-
109-
public int length() {
110-
return length;
111-
}
112-
113-
public ZeroCopyString substring(int beginIndex) {
114-
return (beginIndex == 0)
115-
? this
116-
: new ZeroCopyString(value, offset + beginIndex, length - beginIndex);
117-
}
118-
119-
public ZeroCopyString substring(int beginIndex, int endIndex) {
120-
int len = endIndex - beginIndex;
121-
return (beginIndex == 0 && len == length)
122-
? this
123-
: new ZeroCopyString(value, offset + beginIndex, endIndex - beginIndex);
124-
}
125-
126-
public char charAt(int index) {
127-
return value[offset + index];
128-
}
129-
130-
public int indexOf(int ch) {
131-
int fromIndex = offset;
132-
final int max = Math.min(value.length, offset + length);
133-
134-
final char[] value = this.value;
135-
for (int i = fromIndex; i < max; i++) {
136-
if (value[i] == ch) {
137-
return i - offset;
138-
}
139-
}
140-
return -1;
141-
}
142-
143-
public boolean startsWith(ZeroCopyString prefix) {
144-
char ta[] = value;
145-
int to = offset;
146-
char pa[] = prefix.value;
147-
int po = prefix.offset;
148-
int pc = prefix.length;
149-
// Note: toffset might be near -1>>>1.
150-
if (pc > length) {
151-
return false;
152-
}
153-
while (--pc >= 0) {
154-
if (ta[to++] != pa[po++]) {
155-
return false;
156-
}
157-
}
158-
return true;
159-
}
160-
161-
@Override public String toString() {
162-
return new String(value, offset, length);
163-
}
164-
}
165-
16655
static class Segment {
16756
byte nodeType;
16857
// String key = "";
169-
ZeroCopyString rexPat = ZeroCopyString.EMPTY;
58+
String rexPat = EMPTY_STRING;
17059
char tail;
17160
int startIndex;
17261
int endIndex;
17362

17463
public Segment() {
17564
}
17665

177-
public Segment(byte nodeType, /*String key,*/ ZeroCopyString regex, char tail, int startIndex,
66+
public Segment(byte nodeType, /*String key,*/ String regex, char tail, int startIndex,
17867
int endIndex) {
17968
this.nodeType = nodeType;
18069
// this.key = key;
@@ -196,7 +85,7 @@ private static class Node implements Comparable<Node> {
19685
char tail;
19786

19887
// prefix is the common prefix we ignore
199-
ZeroCopyString prefix;
88+
String prefix;
20089

20190
// regexp matcher for regexp nodes
20291
Pattern rex;
@@ -230,7 +119,7 @@ public Node tail(char tail) {
230119
return this;
231120
}
232121

233-
public Node prefix(ZeroCopyString prefix) {
122+
public Node prefix(String prefix) {
234123
this.prefix = prefix;
235124
return this;
236125
}
@@ -264,10 +153,10 @@ public Node prefix(ZeroCopyString prefix) {
264153
return node.toString();
265154
}
266155

267-
Node insertRoute(String method, ZeroCopyString pattern, Route route) {
156+
Node insertRoute(String method, String pattern, Route route) {
268157
Node n = this;
269158
Node parent;
270-
ZeroCopyString search = pattern;
159+
String search = pattern;
271160

272161
while (true) {
273162
// Handle key exhaustion
@@ -291,11 +180,11 @@ Node insertRoute(String method, ZeroCopyString pattern, Route route) {
291180
seg = new Segment();
292181
}
293182

294-
ZeroCopyString prefix;
183+
String prefix;
295184
if (seg.nodeType == ntRegexp) {
296185
prefix = seg.rexPat;
297186
} else {
298-
prefix = ZeroCopyString.EMPTY;
187+
prefix = EMPTY_STRING;
299188
}
300189

301190
// Look for the edge to attach to
@@ -358,7 +247,7 @@ Node insertRoute(String method, ZeroCopyString pattern, Route route) {
358247
// For a URL router like chi's, we split the static, param, regexp and wildcard segments
359248
// into different nodes. In addition, addChild will recursively call itself until every
360249
// pattern segment is added to the url pattern tree as individual nodes, depending on type.
361-
Node addChild(Node child, ZeroCopyString search) {
250+
Node addChild(Node child, String search) {
362251
Node n = this;
363252
// String search = prefix.toString();
364253

@@ -449,7 +338,7 @@ void replaceChild(char label, char tail, Node child) {
449338
throw new IllegalArgumentException("chi: replacing missing child");
450339
}
451340

452-
Node getEdge(int ntyp, char label, char tail, ZeroCopyString prefix) {
341+
Node getEdge(int ntyp, char label, char tail, String prefix) {
453342
Node n = this;
454343
Node[] nds = n.children[ntyp];
455344
for (int i = 0; nds != null && i < nds.length; i++) {
@@ -495,13 +384,13 @@ void setEndpoint(String method, Route route) {
495384

496385
// Recursive edge traversal by checking all nodeTyp groups along the way.
497386
// It's like searching through a multi-dimensional radix trie.
498-
Route findRoute(RouterMatch rctx, String method, ZeroCopyString path) {
387+
Route findRoute(RouterMatch rctx, String method, String path) {
499388

500389
for (int ntyp = 0; ntyp < NODE_SIZE; ntyp++) {
501390
Node[] nds = this.children[ntyp];
502391
if (nds != null) {
503392
Node xn = null;
504-
ZeroCopyString xsearch = path;
393+
String xsearch = path;
505394

506395
char label = path.length() > 0 ? path.charAt(0) : ZERO_CHAR;
507396

@@ -558,7 +447,7 @@ Route findRoute(RouterMatch rctx, String method, ZeroCopyString path) {
558447
rctx.value(xsearch);
559448
}
560449
xn = nds[0];
561-
xsearch = ZeroCopyString.EMPTY;
450+
xsearch = EMPTY_STRING;
562451
}
563452

564453
if (xn == null) {
@@ -625,7 +514,7 @@ boolean isLeaf() {
625514
}
626515

627516
// longestPrefix finds the filesize of the shared prefix of two strings
628-
int longestPrefix(ZeroCopyString k1, ZeroCopyString k2) {
517+
int longestPrefix(String k1, String k2) {
629518
int len = Math.min(k1.length(), k2.length());
630519
for (int i = 0; i < len; i++) {
631520
if (k1.charAt(i) != k2.charAt(i)) {
@@ -661,12 +550,12 @@ private Node[] append(Node[] src, Node child) {
661550

662551
// patNextSegment returns the next segment details from a pattern:
663552
// node type, param key, regexp string, param tail byte, param starting index, param ending index
664-
Segment patNextSegment(ZeroCopyString pattern) {
553+
Segment patNextSegment(String pattern) {
665554
int ps = pattern.indexOf('{');
666555
int ws = pattern.indexOf('*');
667556

668557
if (ps < 0 && ws < 0) {
669-
return new Segment(ntStatic, ZeroCopyString.EMPTY, (char) 0, 0,
558+
return new Segment(ntStatic, EMPTY_STRING, (char) 0, 0,
670559
pattern.length()); // we return the entire thing
671560
}
672561

@@ -685,7 +574,7 @@ Segment patNextSegment(ZeroCopyString pattern) {
685574
// Read to closing } taking into account opens and closes in curl count (cc)
686575
int cc = 0;
687576
int pe = ps;
688-
ZeroCopyString range = pattern.substring(ps);
577+
String range = pattern.substring(ps);
689578
for (int i = 0; i < range.length(); i++) {
690579
char c = range.charAt(i);
691580
if (c == '{') {
@@ -703,7 +592,7 @@ Segment patNextSegment(ZeroCopyString pattern) {
703592
"Router: route param closing delimiter '}' is missing");
704593
}
705594

706-
ZeroCopyString key = pattern.substring(ps + 1, pe);
595+
String key = pattern.substring(ps + 1, pe);
707596
pe++; // set end to next position
708597

709598
if (pe < pattern.length()) {
@@ -727,14 +616,14 @@ Segment patNextSegment(ZeroCopyString pattern) {
727616
}
728617
}
729618

730-
return new Segment(nt, new ZeroCopyString(rexpat), tail, ps, pe);
619+
return new Segment(nt, rexpat, tail, ps, pe);
731620
}
732621

733622
// Wildcard pattern as finale
734623
// EDIT: should we panic if there is stuff after the * ???
735624
// We allow naming a wildcard: *path
736625
//String key = ws == pattern.length() - 1 ? "*" : pattern.substring(ws + 1).toString();
737-
return new Segment(ntCatchAll, ZeroCopyString.EMPTY, (char) 0, ws, pattern.length());
626+
return new Segment(ntCatchAll, EMPTY_STRING, (char) 0, ws, pattern.length());
738627
}
739628

740629
public void destroy() {
@@ -782,7 +671,7 @@ public void insert(String method, String pattern, Route route) {
782671
StaticRoute staticRoute = staticPaths.computeIfAbsent(pattern, k -> new StaticRoute());
783672
staticRoute.put(method, route);
784673
}
785-
root.insertRoute(method, new ZeroCopyString(pattern), route);
674+
root.insertRoute(method, pattern, route);
786675
}
787676

788677
private String baseCatchAll(String pattern) {
@@ -803,7 +692,7 @@ public void destroy() {
803692

804693
public boolean exists(String method, String path) {
805694
if (!staticPaths.getOrDefault(path, NO_MATCH).methods.containsKey(method)) {
806-
return root.findRoute(new RouterMatch(), method, new ZeroCopyString(path)) != null;
695+
return root.findRoute(new RouterMatch(), method, path) != null;
807696
}
808697
return true;
809698
}
@@ -813,7 +702,7 @@ public boolean exists(String method, String path) {
813702
if (match == null) {
814703
// use radix tree
815704
RouterMatch result = new RouterMatch();
816-
Route route = root.findRoute(result, method, new ZeroCopyString(path));
705+
Route route = root.findRoute(result, method, path);
817706
if (route == null) {
818707
return result.missing(method, path, encoder);
819708
}

jooby/src/main/java/io/jooby/internal/RouterMatch.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -36,11 +36,11 @@ public void key(List<String> keys) {
3636
}
3737
}
3838

39-
public void value(Chi.ZeroCopyString value) {
39+
public void value(String value) {
4040
if (vars == Collections.EMPTY_MAP) {
4141
vars = new LinkedHashMap();
4242
}
43-
vars.put(vars.size(), value.toString());
43+
vars.put(vars.size(), value);
4444
}
4545

4646
public void pop() {

jooby/src/test/java/io/jooby/internal/ZeroCopyStringTest.java

Lines changed: 0 additions & 69 deletions
This file was deleted.

0 commit comments

Comments
 (0)