mirror of https://github.com/gofiber/fiber.git
♻️ Refactor: add findNextNonEscapedCharsetPosition to process a single-byte parameter
``` goos: linux goarch: amd64 pkg: github.com/gofiber/fiber/v3 cpu: AMD EPYC 9J14 96-Core Processor │ old.txt │ new.txt │ │ sec/op │ sec/op vs base │ _RoutePatternMatch//api/v1/const_|_match_|_/api/v1/const-16 160.4n ± 1% 159.0n ± 0% -0.84% (p=0.000 n=20) _RoutePatternMatch//api/v1/const_|_not_match_|_/api/v1-16 151.6n ± 0% 150.8n ± 0% -0.53% (p=0.005 n=20) _RoutePatternMatch//api/v1/const_|_not_match_|_/api/v1/-16 151.7n ± 0% 150.6n ± 0% -0.73% (p=0.000 n=20) _RoutePatternMatch//api/v1/const_|_not_match_|_/api/v1/something-16 162.3n ± 0% 160.8n ± 0% -0.96% (p=0.000 n=20) _RoutePatternMatch//api/:param/fixedEnd_|_match_|_/api/abc/fixedEnd-16 452.9n ± 1% 435.8n ± 0% -3.79% (p=0.000 n=20) _RoutePatternMatch//api/:param/fixedEnd_|_not_match_|_/api/abc/def/fixedEnd-16 455.6n ± 1% 435.7n ± 0% -4.38% (p=0.000 n=20) _RoutePatternMatch//api/v1/:param/*_|_match_|_/api/v1/entity-16 524.4n ± 1% 507.6n ± 1% -3.19% (p=0.000 n=20) _RoutePatternMatch//api/v1/:param/*_|_match_|_/api/v1/entity/-16 528.2n ± 0% 508.7n ± 0% -3.69% (p=0.000 n=20) _RoutePatternMatch//api/v1/:param/*_|_match_|_/api/v1/entity/1-16 528.1n ± 0% 510.6n ± 0% -3.31% (p=0.000 n=20) _RoutePatternMatch//api/v1/:param/*_|_not_match_|_/api/v-16 500.3n ± 0% 489.0n ± 0% -2.27% (p=0.000 n=20) _RoutePatternMatch//api/v1/:param/*_|_not_match_|_/api/v2-16 502.1n ± 0% 489.9n ± 0% -2.44% (p=0.000 n=20) _RoutePatternMatch//api/v1/:param/*_|_not_match_|_/api/v1/-16 515.5n ± 0% 498.8n ± 0% -3.24% (p=0.000 n=20) geomean 339.4n 331.1n -2.46% │ old.txt │ new.txt │ │ B/op │ B/op vs base │ _RoutePatternMatch//api/v1/const_|_match_|_/api/v1/const-16 144.0 ± 0% 144.0 ± 0% ~ (p=1.000 n=20) ¹ _RoutePatternMatch//api/v1/const_|_not_match_|_/api/v1-16 136.0 ± 0% 136.0 ± 0% ~ (p=1.000 n=20) ¹ _RoutePatternMatch//api/v1/const_|_not_match_|_/api/v1/-16 136.0 ± 0% 136.0 ± 0% ~ (p=1.000 n=20) ¹ _RoutePatternMatch//api/v1/const_|_not_match_|_/api/v1/something-16 152.0 ± 0% 152.0 ± 0% ~ (p=1.000 n=20) ¹ _RoutePatternMatch//api/:param/fixedEnd_|_match_|_/api/abc/fixedEnd-16 368.0 ± 0% 368.0 ± 0% ~ (p=1.000 n=20) ¹ _RoutePatternMatch//api/:param/fixedEnd_|_not_match_|_/api/abc/def/fixedEnd-16 368.0 ± 0% 368.0 ± 0% ~ (p=1.000 n=20) ¹ _RoutePatternMatch//api/v1/:param/*_|_match_|_/api/v1/entity-16 432.0 ± 0% 432.0 ± 0% ~ (p=1.000 n=20) ¹ _RoutePatternMatch//api/v1/:param/*_|_match_|_/api/v1/entity/-16 432.0 ± 0% 432.0 ± 0% ~ (p=1.000 n=20) ¹ _RoutePatternMatch//api/v1/:param/*_|_match_|_/api/v1/entity/1-16 432.0 ± 0% 432.0 ± 0% ~ (p=1.000 n=20) ¹ _RoutePatternMatch//api/v1/:param/*_|_not_match_|_/api/v-16 424.0 ± 0% 424.0 ± 0% ~ (p=1.000 n=20) ¹ _RoutePatternMatch//api/v1/:param/*_|_not_match_|_/api/v2-16 424.0 ± 0% 424.0 ± 0% ~ (p=1.000 n=20) ¹ _RoutePatternMatch//api/v1/:param/*_|_not_match_|_/api/v1/-16 424.0 ± 0% 424.0 ± 0% ~ (p=1.000 n=20) ¹ geomean 288.8 288.8 +0.00% ¹ all samples are equal │ old.txt │ new.txt │ │ allocs/op │ allocs/op vs base │ _RoutePatternMatch//api/v1/const_|_match_|_/api/v1/const-16 4.000 ± 0% 4.000 ± 0% ~ (p=1.000 n=20) ¹ _RoutePatternMatch//api/v1/const_|_not_match_|_/api/v1-16 4.000 ± 0% 4.000 ± 0% ~ (p=1.000 n=20) ¹ _RoutePatternMatch//api/v1/const_|_not_match_|_/api/v1/-16 4.000 ± 0% 4.000 ± 0% ~ (p=1.000 n=20) ¹ _RoutePatternMatch//api/v1/const_|_not_match_|_/api/v1/something-16 4.000 ± 0% 4.000 ± 0% ~ (p=1.000 n=20) ¹ _RoutePatternMatch//api/:param/fixedEnd_|_match_|_/api/abc/fixedEnd-16 9.000 ± 0% 9.000 ± 0% ~ (p=1.000 n=20) ¹ _RoutePatternMatch//api/:param/fixedEnd_|_not_match_|_/api/abc/def/fixedEnd-16 9.000 ± 0% 9.000 ± 0% ~ (p=1.000 n=20) ¹ _RoutePatternMatch//api/v1/:param/*_|_match_|_/api/v1/entity-16 9.000 ± 0% 9.000 ± 0% ~ (p=1.000 n=20) ¹ _RoutePatternMatch//api/v1/:param/*_|_match_|_/api/v1/entity/-16 9.000 ± 0% 9.000 ± 0% ~ (p=1.000 n=20) ¹ _RoutePatternMatch//api/v1/:param/*_|_match_|_/api/v1/entity/1-16 9.000 ± 0% 9.000 ± 0% ~ (p=1.000 n=20) ¹ _RoutePatternMatch//api/v1/:param/*_|_not_match_|_/api/v-16 9.000 ± 0% 9.000 ± 0% ~ (p=1.000 n=20) ¹ _RoutePatternMatch//api/v1/:param/*_|_not_match_|_/api/v2-16 9.000 ± 0% 9.000 ± 0% ~ (p=1.000 n=20) ¹ _RoutePatternMatch//api/v1/:param/*_|_not_match_|_/api/v1/-16 9.000 ± 0% 9.000 ± 0% ~ (p=1.000 n=20) ¹ geomean 6.868 6.868 +0.00% ¹ all samples are equal ```pull/3378/head
parent
e90fe8afbc
commit
53f0e42116
46
path.go
46
path.go
|
@ -123,16 +123,6 @@ var (
|
|||
parameterDelimiterChars = append([]byte{paramStarterChar, escapeChar}, routeDelimiter...)
|
||||
// list of chars to find the end of a parameter
|
||||
parameterEndChars = append([]byte{optionalParam}, parameterDelimiterChars...)
|
||||
// list of parameter constraint start
|
||||
parameterConstraintStartChars = []byte{paramConstraintStart}
|
||||
// list of parameter constraint end
|
||||
parameterConstraintEndChars = []byte{paramConstraintEnd}
|
||||
// list of parameter separator
|
||||
parameterConstraintSeparatorChars = []byte{paramConstraintSeparator}
|
||||
// list of parameter constraint data start
|
||||
parameterConstraintDataStartChars = []byte{paramConstraintDataStart}
|
||||
// list of parameter constraint data separator
|
||||
parameterConstraintDataSeparatorChars = []byte{paramConstraintDataSeparator}
|
||||
)
|
||||
|
||||
// RoutePatternMatch checks if a given path matches a Fiber route pattern.
|
||||
|
@ -337,8 +327,8 @@ func (parser *routeParser) analyseParameterPart(pattern string, customConstraint
|
|||
|
||||
// find constraint part if exists in the parameter part and remove it
|
||||
if parameterEndPosition > 0 {
|
||||
parameterConstraintStart = findNextNonEscapedCharsetPosition(pattern[0:parameterEndPosition], parameterConstraintStartChars)
|
||||
parameterConstraintEnd = strings.LastIndexByte(pattern[0:parameterEndPosition+1], paramConstraintEnd)
|
||||
parameterConstraintStart = findNextNonEscapedCharPosition(pattern[:parameterEndPosition], paramConstraintStart)
|
||||
parameterConstraintEnd = strings.LastIndexByte(pattern[:parameterEndPosition+1], paramConstraintEnd)
|
||||
}
|
||||
|
||||
// cut params part
|
||||
|
@ -351,11 +341,11 @@ func (parser *routeParser) analyseParameterPart(pattern string, customConstraint
|
|||
|
||||
if hasConstraint := parameterConstraintStart != -1 && parameterConstraintEnd != -1; hasConstraint {
|
||||
constraintString := pattern[parameterConstraintStart+1 : parameterConstraintEnd]
|
||||
userConstraints := splitNonEscaped(constraintString, string(parameterConstraintSeparatorChars))
|
||||
userConstraints := splitNonEscaped(constraintString, paramConstraintSeparator)
|
||||
constraints = make([]*Constraint, 0, len(userConstraints))
|
||||
|
||||
for _, c := range userConstraints {
|
||||
start := findNextNonEscapedCharsetPosition(c, parameterConstraintDataStartChars)
|
||||
start := findNextNonEscapedCharPosition(c, paramConstraintDataStart)
|
||||
end := strings.LastIndexByte(c, paramConstraintDataEnd)
|
||||
|
||||
// Assign constraint
|
||||
|
@ -368,7 +358,7 @@ func (parser *routeParser) analyseParameterPart(pattern string, customConstraint
|
|||
|
||||
// remove escapes from data
|
||||
if constraint.ID != regexConstraint {
|
||||
constraint.Data = splitNonEscaped(c[start+1:end], string(parameterConstraintDataSeparatorChars))
|
||||
constraint.Data = splitNonEscaped(c[start+1:end], paramConstraintDataSeparator)
|
||||
if len(constraint.Data) == 1 {
|
||||
constraint.Data[0] = RemoveEscapeChar(constraint.Data[0])
|
||||
} else if len(constraint.Data) == 2 { // This is fine, we simply expect two parts
|
||||
|
@ -432,11 +422,11 @@ func findNextCharsetPosition(search string, charset []byte) int {
|
|||
return nextPosition
|
||||
}
|
||||
|
||||
// findNextCharsetPositionConstraint search the next char position from the charset
|
||||
// findNextCharsetPositionConstraint searches the next char position from the charset
|
||||
// unlike findNextCharsetPosition, it takes care of constraint start-end chars to parse route pattern
|
||||
func findNextCharsetPositionConstraint(search string, charset []byte) int {
|
||||
constraintStart := findNextNonEscapedCharsetPosition(search, parameterConstraintStartChars)
|
||||
constraintEnd := findNextNonEscapedCharsetPosition(search, parameterConstraintEndChars)
|
||||
constraintStart := findNextNonEscapedCharPosition(search, paramConstraintStart)
|
||||
constraintEnd := findNextNonEscapedCharPosition(search, paramConstraintEnd)
|
||||
nextPosition := -1
|
||||
|
||||
for _, char := range charset {
|
||||
|
@ -452,7 +442,7 @@ func findNextCharsetPositionConstraint(search string, charset []byte) int {
|
|||
return nextPosition
|
||||
}
|
||||
|
||||
// findNextNonEscapedCharsetPosition search the next char position from the charset and skip the escaped characters
|
||||
// findNextNonEscapedCharsetPosition searches the next char position from the charset and skips the escaped characters
|
||||
func findNextNonEscapedCharsetPosition(search string, charset []byte) int {
|
||||
pos := findNextCharsetPosition(search, charset)
|
||||
for pos > 0 && search[pos-1] == escapeChar {
|
||||
|
@ -471,16 +461,26 @@ func findNextNonEscapedCharsetPosition(search string, charset []byte) int {
|
|||
return pos
|
||||
}
|
||||
|
||||
// findNextNonEscapedCharPosition searches the next char position and skips the escaped characters
|
||||
func findNextNonEscapedCharPosition(search string, char byte) int {
|
||||
for i := 0; i < len(search); i++ {
|
||||
if search[i] == char && (i == 0 || search[i-1] != escapeChar) {
|
||||
return i
|
||||
}
|
||||
}
|
||||
return -1
|
||||
}
|
||||
|
||||
// splitNonEscaped slices s into all substrings separated by sep and returns a slice of the substrings between those separators
|
||||
// This function also takes a care of escape char when splitting.
|
||||
func splitNonEscaped(s, sep string) []string {
|
||||
func splitNonEscaped(s string, sep byte) []string {
|
||||
var result []string
|
||||
i := findNextNonEscapedCharsetPosition(s, []byte(sep))
|
||||
i := findNextNonEscapedCharPosition(s, sep)
|
||||
|
||||
for i > -1 {
|
||||
result = append(result, s[:i])
|
||||
s = s[i+len(sep):]
|
||||
i = findNextNonEscapedCharsetPosition(s, []byte(sep))
|
||||
s = s[i+1:]
|
||||
i = findNextNonEscapedCharPosition(s, sep)
|
||||
}
|
||||
|
||||
return append(result, s)
|
||||
|
|
Loading…
Reference in New Issue