From bd66659ec11993feb44f6217eb7d1bf762fd4875 Mon Sep 17 00:00:00 2001 From: Tit Petric Date: Thu, 24 Aug 2023 14:53:00 +0200 Subject: [PATCH] Optimize allocations in newRouteRegexp --- regexp.go | 53 +++++++++++++++++++++++++++++++++++++---------------- 1 file changed, 37 insertions(+), 16 deletions(-) diff --git a/regexp.go b/regexp.go index 0baba6a4..4c916c8b 100644 --- a/regexp.go +++ b/regexp.go @@ -65,35 +65,48 @@ func newRouteRegexp(tpl string, typ regexpType, options routeRegexpOptions) (*ro } varsN := make([]string, len(idxs)/2) varsR := make([]*regexp.Regexp, len(idxs)/2) - pattern := bytes.NewBufferString("") + + var pattern, reverse strings.Builder pattern.WriteByte('^') - reverse := bytes.NewBufferString("") - var end int + + var end, colonIdx, groupIdx int var err error + var patt, param, name string for i := 0; i < len(idxs); i += 2 { // Set all values we are interested in. + groupIdx = i/2 + raw := tpl[end:idxs[i]] end = idxs[i+1] - parts := strings.SplitN(tpl[idxs[i]+1:end-1], ":", 2) - name := parts[0] - patt := defaultPattern - if len(parts) == 2 { - patt = parts[1] + + param = tpl[idxs[i]+1 : end-1] + colonIdx = strings.Index(param, ":") + if colonIdx == -1 { + name = param + patt = defaultPattern + } else { + name = param[0:colonIdx] + patt = param[colonIdx+1:] + } + if patt == "" { + patt = defaultPattern } + // Name or pattern can't be empty. if name == "" || patt == "" { - return nil, fmt.Errorf("mux: missing name or pattern in %q", - tpl[idxs[i]:end]) + return nil, fmt.Errorf("mux: missing name or pattern in %q", param) } // Build the regexp pattern. - fmt.Fprintf(pattern, "%s(?P<%s>%s)", regexp.QuoteMeta(raw), varGroupName(i/2), patt) + groupName := varGroupName(groupIdx) + + pattern.WriteString(regexp.QuoteMeta(raw)+"(?P<" + groupName + ">" + patt + ")") // Build the reverse template. - fmt.Fprintf(reverse, "%s%%s", raw) + reverse.WriteString(raw+"%s") // Append variable name and compiled pattern. - varsN[i/2] = name - varsR[i/2], err = RegexpCompileFunc(fmt.Sprintf("^%s$", patt)) + varsN[groupIdx] = name + varsR[groupIdx], err = RegexpCompileFunc("^" + patt + "$") if err != nil { return nil, err } @@ -101,31 +114,39 @@ func newRouteRegexp(tpl string, typ regexpType, options routeRegexpOptions) (*ro // Add the remaining. raw := tpl[end:] pattern.WriteString(regexp.QuoteMeta(raw)) + if options.strictSlash { pattern.WriteString("[/]?") } + if typ == regexpTypeQuery { // Add the default pattern if the query value is empty if queryVal := strings.SplitN(template, "=", 2)[1]; queryVal == "" { pattern.WriteString(defaultPattern) } } + if typ != regexpTypePrefix { pattern.WriteByte('$') } + patternStr := pattern.String() + var wildcardHostPort bool if typ == regexpTypeHost { - if !strings.Contains(pattern.String(), ":") { + if !strings.Contains(patternStr, ":") { wildcardHostPort = true } } + reverse.WriteString(raw) + if endSlash { reverse.WriteByte('/') } + // Compile full regexp. - reg, errCompile := RegexpCompileFunc(pattern.String()) + reg, errCompile := RegexpCompileFunc(patternStr) if errCompile != nil { return nil, errCompile }