Repository navigation
Expand file tree
/
Copy pathpath_parser.go
More file actions
103 lines (91 loc) · 2.23 KB
/
Copy pathpath_parser.go
File metadata and controls
103 lines (91 loc) · 2.23 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
package nanite
// PathPart represents a single path segment with start/end indices
type PathPart struct {
Start int
End int
}
// PathParser provides zero-allocation path parsing
type PathParser struct {
path string
parts [12]PathPart // Fixed-size array for common case (most URLs have < 12 segments)
partsUsed byte
}
// NewPathParser creates a new parser for the given path
func NewPathParser(path string) PathParser {
parser := PathParser{
path: path,
partsUsed: 0,
}
parser.parse()
return parser
}
// parse splits the path into parts without allocations
func (p *PathParser) parse() {
if p.path == "" || p.path == "/" {
return
}
start := 0
if p.path[0] == '/' {
start = 1
}
for i := start; i < len(p.path); i++ {
if p.path[i] == '/' {
if i > start {
if p.partsUsed < 12 {
p.parts[p.partsUsed] = PathPart{Start: start, End: i}
p.partsUsed++
}
}
start = i + 1
}
}
// Add final part if exists
if start < len(p.path) {
if p.partsUsed < 12 {
p.parts[p.partsUsed] = PathPart{Start: start, End: len(p.path)}
p.partsUsed++
}
}
}
// Count returns the number of path parts
func (p *PathParser) Count() int {
return int(p.partsUsed)
}
// Part returns the path segment at the given index
//
//go:inline
func (p *PathParser) Part(index int) string {
if index < 0 || index >= int(p.partsUsed) {
return ""
}
part := p.parts[index]
return p.path[part.Start:part.End]
}
// IsParam returns true if the path segment at the given index is a parameter
//
//go:inline
func (p *PathParser) IsParam(index int) bool {
if index < 0 || index >= int(p.partsUsed) {
return false
}
part := p.parts[index]
return part.End > part.Start && p.path[part.Start] == ':'
}
// IsWildcard returns true if the path segment at the given index is a wildcard
//
//go:inline
func (p *PathParser) IsWildcard(index int) bool {
if index < 0 || index >= int(p.partsUsed) {
return false
}
part := p.parts[index]
return part.End > part.Start && p.path[part.Start] == '*'
}
// ParamName returns the parameter name at the given index
func (p *PathParser) ParamName(index int) string {
if !p.IsParam(index) && !p.IsWildcard(index) {
return ""
}
part := p.parts[index]
return p.path[part.Start+1 : part.End]
}